diff --git a/beem/blockchain.py b/beem/blockchain.py index ebb9ff95237c8d577509f900f3c6222b80a5674f..5d086a1200da0266a3e1efb9f471af3eaf753617 100644 --- a/beem/blockchain.py +++ b/beem/blockchain.py @@ -174,9 +174,9 @@ class Blockchain(object): """ # Let's find out how often blocks are generated! self.block_interval = self.steem.get_block_interval() - + current_block_num = self.get_current_block_num() if not start: - start = self.get_current_block_num() + start = current_block_num # We are going to loop indefinitely while True: @@ -185,7 +185,8 @@ class Blockchain(object): if stop: head_block = stop else: - head_block = self.get_current_block_num() + current_block_num = self.get_current_block_num() + head_block = current_block_num if threading and FUTURES_MODULE: pool = ThreadPoolExecutor(max_workers=thread_num + 1) latest_block = 0 @@ -242,7 +243,7 @@ class Blockchain(object): # Blocks from start until head block for blocknum in range(start, head_block + 1): # Get full block - block = self.wait_for_and_get_block(blocknum) + block = self.wait_for_and_get_block(blocknum, last_fetched_block_num=current_block_num) yield block # Set new start start = head_block + 1 @@ -254,23 +255,24 @@ class Blockchain(object): # Sleep for one block time.sleep(self.block_interval) - def wait_for_and_get_block(self, block_number, blocks_waiting_for=None): + def wait_for_and_get_block(self, block_number, blocks_waiting_for=None, last_fetched_block_num=None): """ Get the desired block from the chain, if the current head block is smaller (for both head and irreversible) then we wait, but a maxmimum of blocks_waiting_for * max_block_wait_repetition time before failure. :param int block_number: desired block number :param int blocks_waiting_for: (default) difference between block_number and current head how many blocks we are willing to wait, positive int """ - if not blocks_waiting_for: - blocks_waiting_for = max(1, block_number - self.get_current_block_num()) - - repetition = 0 - # can't return the block before the chain has reached it (support future block_num) - while self.get_current_block_num() < block_number: - repetition += 1 - time.sleep(self.block_interval) - if repetition > blocks_waiting_for * self.max_block_wait_repetition: - raise Exception("Wait time for new block exceeded, aborting") + if last_fetched_block_num is None or (last_fetched_block_num is not None and block_number > last_fetched_block_num): + if not blocks_waiting_for: + blocks_waiting_for = max(1, block_number - self.get_current_block_num()) + + repetition = 0 + # can't return the block before the chain has reached it (support future block_num) + while self.get_current_block_num() < block_number: + repetition += 1 + time.sleep(self.block_interval) + if repetition > blocks_waiting_for * self.max_block_wait_repetition: + raise Exception("Wait time for new block exceeded, aborting") # block has to be returned properly block = Block(block_number, steem_instance=self.steem) repetition = 0 diff --git a/beem/storage.py b/beem/storage.py index 75778507b0a9af05e814c46aab51b22d2c866e42..061a2355a2d9d28b2dc565e2c1bcc41f981fe8d1 100644 --- a/beem/storage.py +++ b/beem/storage.py @@ -233,7 +233,10 @@ class Configuration(DataDir): #: Default configuration nodes = ["wss://steemd.pevo.science", "wss://gtg.steem.house:8090", "wss://rpc.steemliberator.com", "wss://rpc.buildteam.io", "wss://rpc.steemviz.com", "wss://seed.bitcoiner.me", "wss://steemd.steemgigs.org", - "wss://steemd.minnowsupportproject.org"] + "wss://steemd.minnowsupportproject.org", "https://api.steemit.com", "https://rpc.buildteam.io", + "https://steemd.minnowsupportproject.org", "https://steemd.pevo.science", "https://rpc.steemviz.com", "https://seed.bitcoiner.me", + "https://rpc.steemliberator.com", "https://steemd.privex.io", "https://gtg.steem.house:8090", "https://api.steem.house", + "https://rpc.curiesteem.com"] config_defaults = { "node": nodes, "rpcpassword": "", diff --git a/beemapi/steemnoderpc.py b/beemapi/steemnoderpc.py index b1bb1a83fd564a1ac141183a708a5a02fc7de391..a48f1f718d890b18273711adacb12bc50d1d0311 100644 --- a/beemapi/steemnoderpc.py +++ b/beemapi/steemnoderpc.py @@ -41,10 +41,10 @@ class SteemNodeRPC(GrapheneRPC): doRetryCount = 0 doRetry = True while doRetry and doRetryCount < 5: + doRetry = False + doRetryCount += 1 try: # Forward call to GrapheneWebsocketRPC and catch+evaluate errors - doRetry = False - doRetryCount += 1 return super(SteemNodeRPC, self).rpcexec(payload) except exceptions.RPCError as e: msg = exceptions.decodeRPCErrorMsg(e).strip() @@ -64,6 +64,12 @@ class SteemNodeRPC(GrapheneRPC): elif re.search("Internal Error", msg): sleep_and_check_retries(5, doRetryCount, self.url, str(msg)) doRetry = True + elif re.search("Service Temporarily Unavailable", msg): + sleep_and_check_retries(5, doRetryCount, self.url, str(msg)) + doRetry = True + elif re.search("Bad Gateway", msg): + sleep_and_check_retries(5, doRetryCount, self.url, str(msg)) + doRetry = True elif msg: raise exceptions.UnhandledRPCError(msg) else: diff --git a/beemgrapheneapi/graphenerpc.py b/beemgrapheneapi/graphenerpc.py index c3f441217223dd591affc5255582e9439c0fa620..2c08400a3dd12bc957e309609103f6a19052601c 100644 --- a/beemgrapheneapi/graphenerpc.py +++ b/beemgrapheneapi/graphenerpc.py @@ -231,11 +231,16 @@ class GrapheneRPC(object): try: ret = json.loads(reply, strict=False) except ValueError: - raise ValueError("Client returned invalid format. Expected JSON!") + if re.search("Service Temporarily Unavailable", reply): + raise RPCError("Service Temporarily Unavailable") + elif re.search("Bad Gateway", reply): + raise RPCError("Bad Gateway") + else: + raise ValueError("Client returned invalid format. Expected JSON!") log.debug(json.dumps(reply)) - if 'error' in ret: + if isinstance(ret, dict) and 'error' in ret: if 'detail' in ret['error']: raise RPCError(ret['error']['detail']) else: @@ -252,8 +257,10 @@ class GrapheneRPC(object): else: ret_list.append(r["result"]) return ret_list - elif "result" in ret: + elif isinstance(ret, dict) and "result" in ret: return ret["result"] + elif isinstance(ret, int): + raise ValueError("Client returned invalid format. Expected JSON!") else: return ret diff --git a/examples/benchmark_nodes.py b/examples/benchmark_nodes.py index 32f2df8a123cd555bd1a17c9edb42fd89c5d6011..833b8d2605e482561a2eeb3382b5d5ddb23cded0 100644 --- a/examples/benchmark_nodes.py +++ b/examples/benchmark_nodes.py @@ -22,7 +22,7 @@ nodes = ["wss://steemd.pevo.science", "wss://gtg.steem.house:8090", "wss://rpc.s "wss://steemd.minnowsupportproject.org", "https://api.steemit.com", "https://rpc.buildteam.io", "https://steemd.minnowsupportproject.org", "https://steemd.pevo.science", "https://rpc.steemviz.com", "https://seed.bitcoiner.me", "https://rpc.steemliberator.com", "https://steemd.privex.io", "https://gtg.steem.house:8090", "https://api.steem.house", - "https://rpc.curiesteem.com", "https://seed.bitcoiner.me"] + "https://rpc.curiesteem.com"] if __name__ == "__main__": how_many_minutes = 10 diff --git a/tests/beem/test_utils.py b/tests/beem/test_utils.py index 90185e6a4a5f9b45ef57ad6126cd532188414d0e..5f8b301597e01d26cfb6cfb918681b25c559f889 100644 --- a/tests/beem/test_utils.py +++ b/tests/beem/test_utils.py @@ -64,7 +64,7 @@ class Testcases(unittest.TestCase): def test_formatTimedelta(self): now = datetime.now() - self.assertEqual(formatTimedelta(now - now), '0:00.00') + self.assertEqual(formatTimedelta(now - now), '0:00:00') def test_remove_from_dict(self): a = {'a': 1, 'b': 2}