diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ffaf6399..0430298a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,9 @@ Changelog ========= +0.24.19 +------- +* Fix history item with index 0 for https://api.hive.blog + 0.24.18 ------- * Adapt account history on api changes and fixes issue #267 diff --git a/beem/account.py b/beem/account.py index 3e76ab87..49e9876b 100644 --- a/beem/account.py +++ b/beem/account.py @@ -1835,6 +1835,8 @@ def virtual_op_count(self, until=None): if op_count is None or len(op_count) == 0: op_count = self._get_account_history(start=-1, limit=1) if isinstance(op_count, list) and len(op_count) > 0 and len(op_count[0]) > 0: + if self.blockchain.rpc.url == "https://api.hive.blog": + return op_count[-1][0] + 1 return op_count[-1][0] else: return 0 @@ -1847,6 +1849,8 @@ def _get_account_history(self, account=None, start=-1, limit=1, operation_filter account = extract_account_name(account) if limit < 1: limit = 1 + elif limit > 1000: + limit = 1000 if not self.blockchain.is_connected(): raise OfflineHasNoRPCException("No RPC available in offline mode!") self.blockchain.rpc.set_next_node_on_empty_reply(False) @@ -1879,7 +1883,24 @@ def _get_account_history(self, account=None, start=-1, limit=1, operation_filter api="database") return ret - def estimate_virtual_op_num(self, blocktime, stop_diff=0, max_count=100): + def _get_blocknum_from_hist(self, index, min_index=1): + if index >= 0 and index < min_index: + index = min_index + op = self._get_account_history(start=(index)) + if len(op) == 0: + return None + return op[0][1]['block'] + + def _get_first_blocknum(self): + min_index = 0 + try: + created = self._get_blocknum_from_hist(0, min_index=min_index) + except: + min_index = 1 + created = self._get_blocknum_from_hist(0, min_index=min_index) + return created, min_index + + def estimate_virtual_op_num(self, blocktime, stop_diff=0, max_count=100, min_index=None): """ Returns an estimation of an virtual operation index for a given time or blockindex :param blocktime: start time or start block index from which account @@ -1921,20 +1942,15 @@ def estimate_virtual_op_num(self, blocktime, stop_diff=0, max_count=100): print(block_est - block_num) """ - def get_blocknum(index): - if index == 0: - index = 1 - op = self._get_account_history(start=(index)) - if len(op) == 0: - return None - return op[0][1]['block'] - max_index = self.virtual_op_count() if max_index < stop_diff: return 0 # calculate everything with block numbers - created = get_blocknum(1) + if min_index is None: + created, min_index = self._get_first_blocknum() + else: + created = self._get_blocknum_from_hist(0, min_index=min_index) # convert blocktime to block number if given as a datetime/date/time if isinstance(blocktime, (datetime, date, time)): @@ -1948,7 +1964,7 @@ def get_blocknum(index): return 0 # get the block number from the account's latest operation - latest_blocknum = get_blocknum(-1) + latest_blocknum = self._get_blocknum_from_hist(-1, min_index=min_index) # requested blocknum/timestamp is after the latest account operation if target_blocknum >= latest_blocknum: @@ -1985,10 +2001,10 @@ def get_blocknum(index): # get block number for current op number estimation if op_num != last_op_num: - block_num = get_blocknum(op_num) + block_num = self._get_blocknum_from_hist(op_num, min_index=min_index) while block_num is None and op_num < max_index: op_num += 1 - block_num = get_blocknum(op_num) + block_num = self._get_blocknum_from_hist(op_num, min_index=min_index) last_op_num = op_num # check if the required accuracy was reached @@ -2267,9 +2283,10 @@ def history( if start is not None and not use_block_num and not isinstance(start, (datetime, date, time)): start_index = start elif start is not None and max_index > batch_size: - op_est = self.estimate_virtual_op_num(start, stop_diff=1) - if op_est == 0: - op_est = 1 + created, min_index = self._get_first_blocknum() + op_est = self.estimate_virtual_op_num(start, stop_diff=1, min_index=min_index) + if op_est < min_index: + op_est = min_index est_diff = 0 if isinstance(start, (datetime, date, time)): for h in self.get_account_history(op_est, 0): @@ -2301,7 +2318,9 @@ def history( if first > max_index: _limit = max_index - start_index first = start_index + _limit - 1 - elif first < _limit: + elif first < _limit and self.blockchain.rpc.url == "https://api.hive.blog": + first = _limit - 1 + elif first < _limit and self.blockchain.rpc.url != "https://api.hive.blog": first = _limit last_round = False @@ -2316,7 +2335,9 @@ def history( while True: # RPC call - if first < _limit: + if first < _limit - 1 and self.blockchain.rpc.url == "https://api.hive.blog": + first = _limit - 1 + elif first < _limit and self.blockchain.rpc.url != "https://api.hive.blog": first = _limit batch_count = 0 for item in self.get_account_history(first, _limit, start=None, stop=None, order=1, only_ops=only_ops, exclude_ops=exclude_ops, raw_output=raw_output): @@ -2462,10 +2483,11 @@ def history_reverse( elif start is not None and isinstance(start, int) and not use_block_num: first = start elif start is not None and first > batch_size: - op_est = self.estimate_virtual_op_num(start, stop_diff=1) + created, min_index = self._get_first_blocknum() + op_est = self.estimate_virtual_op_num(start, stop_diff=1, min_index=min_index) est_diff = 0 - if op_est == 0: - op_est = 1 + if op_est < min_index: + op_est = min_index if isinstance(start, (datetime, date, time)): for h in self.get_account_history(op_est, 0): block_date = formatTimeString(h["timestamp"]) @@ -2496,7 +2518,9 @@ def history_reverse( last_item_index = first + 1 while True: # RPC call - if first - _limit < 0: + if first - _limit < 0 and self.blockchain.rpc.url == 'https://api.hive.blog': + _limit = first + 1 + elif first - _limit < 0 and self.blockchain.rpc.url != 'https://api.hive.blog': _limit = first batch_count = 0 for item in self.get_account_history(first, _limit, start=None, stop=None, order=-1, only_ops=only_ops, exclude_ops=exclude_ops, raw_output=raw_output): diff --git a/beem/version.py b/beem/version.py index 5dfb386f..a8090c25 100644 --- a/beem/version.py +++ b/beem/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.17' +version = '0.24.19' diff --git a/beemapi/version.py b/beemapi/version.py index 5dfb386f..a8090c25 100644 --- a/beemapi/version.py +++ b/beemapi/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.17' +version = '0.24.19' diff --git a/beembase/version.py b/beembase/version.py index 5dfb386f..a8090c25 100644 --- a/beembase/version.py +++ b/beembase/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.17' +version = '0.24.19' diff --git a/beemgraphenebase/version.py b/beemgraphenebase/version.py index 5dfb386f..a8090c25 100644 --- a/beemgraphenebase/version.py +++ b/beemgraphenebase/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.17' +version = '0.24.19' diff --git a/setup.py b/setup.py index 156e6461..db4de146 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ ascii = codecs.lookup('ascii') codecs.register(lambda name, enc=ascii: {True: enc}.get(name == 'mbcs')) -VERSION = '0.24.18' +VERSION = '0.24.19' tests_require = ['mock >= 2.0.0', 'pytest', 'pytest-mock', 'parameterized'] diff --git a/tests/beem/test_account.py b/tests/beem/test_account.py index aa24a87e..6b774b61 100644 --- a/tests/beem/test_account.py +++ b/tests/beem/test_account.py @@ -493,12 +493,14 @@ def test_estimate_virtual_op_num(self): self.assertTrue(abs(op_num1 - op_num3) < 200) block_diff1 = 0 block_diff2 = 0 - for h in account.get_account_history(op_num4 - 1, 0): + for h in account.get_account_history(op_num4 - 1, 1): block_diff1 = (block_num - h["block"]) - for h in account.get_account_history(op_num4 + 1, 0): + for h in account.get_account_history(op_num4 + 1, 1): block_diff2 = (block_num - h["block"]) self.assertTrue(block_diff1 > 0) + self.assertTrue(block_diff1 < 1000) self.assertTrue(block_diff2 <= 0) + self.assertTrue(block_diff2 > -1000) def test_estimate_virtual_op_num2(self): account = self.account @@ -542,6 +544,47 @@ def test_history_votes(self): self.assertEqual(votes_list[0]["voter"], votes_list2[-1]["voter"]) self.assertEqual(votes_list[-1]["voter"], votes_list2[0]["voter"]) + def test_history_op_filter(self): + stm = Hive("https://api.hive.blog") + account = Account("beembot", blockchain_instance=stm) + votes_list = list(account.history(only_ops=["vote"])) + other_list = list(account.history(exclude_ops=["vote"])) + all_list = list(account.history()) + self.assertEqual(len(all_list), len(votes_list) + len(other_list)) + index = 0 + for h in sorted((votes_list + other_list), key=lambda h: h["index"]): + self.assertEqual(index, h["index"]) + index += 1 + votes_list = list(account.history_reverse(only_ops=["vote"])) + other_list = list(account.history_reverse(exclude_ops=["vote"])) + all_list = list(account.history_reverse()) + self.assertEqual(len(all_list), len(votes_list) + len(other_list)) + index = 0 + for h in sorted((votes_list + other_list), key=lambda h: h["index"]): + self.assertEqual(index, h["index"]) + index += 1 + + def test_history_op_filter2(self): + stm = Hive("https://api.hive.blog") + batch_size = 100 + account = Account("beembot", blockchain_instance=stm) + votes_list = list(account.history(only_ops=["vote"], batch_size=batch_size)) + other_list = list(account.history(exclude_ops=["vote"], batch_size=batch_size)) + all_list = list(account.history(batch_size=batch_size)) + self.assertEqual(len(all_list), len(votes_list) + len(other_list)) + index = 0 + for h in sorted((votes_list + other_list), key=lambda h: h["index"]): + self.assertEqual(index, h["index"]) + index += 1 + votes_list = list(account.history_reverse(only_ops=["vote"], batch_size=batch_size)) + other_list = list(account.history_reverse(exclude_ops=["vote"], batch_size=batch_size)) + all_list = list(account.history_reverse(batch_size=batch_size)) + self.assertEqual(len(all_list), len(votes_list) + len(other_list)) + index = 0 + for h in sorted((votes_list + other_list), key=lambda h: h["index"]): + self.assertEqual(index, h["index"]) + index += 1 + def test_comment_history(self): account = self.account comments = [] @@ -601,3 +644,19 @@ def test_extract_account_name(self): self.assertEqual(extract_account_name("holger80"), "holger80") self.assertEqual(extract_account_name({"name": "holger80"}), "holger80") self.assertEqual(extract_account_name(""), "") + + def test_get_blocknum_from_hist(self): + stm = Hive("https://api.hive.blog") + account = Account("beembot", blockchain_instance=stm) + created, min_index = account._get_first_blocknum() + if min_index == 0: + self.assertEqual(created, 23687631) + block = account._get_blocknum_from_hist(0, min_index=min_index) + self.assertEqual(block, 23687631) + hist_num = account.estimate_virtual_op_num(block, min_index=min_index) + self.assertEqual(hist_num, 0) + else: + self.assertEqual(created, 23721519) + min_index = 1 + block = account._get_blocknum_from_hist(0, min_index=min_index) + self.assertEqual(block, 23721519)