def get_connection_to_forward(self, metadata): """ Override ProxyConnection.get_connection_to_forward() """ if metadata.cluster_peer_id == 0: # RPC from master return None shard = self.shards.get(metadata.branch, None) if not shard: self.close_with_error("incorrect forwarding branch") return peer_shard_conn = shard.peers.get(metadata.cluster_peer_id, None) if peer_shard_conn is None: # Master can close the peer connection at any time # TODO: any way to avoid this race? Logger.warning_every_sec( "cannot find peer shard conn for cluster id {}".format( metadata.cluster_peer_id ), 1, ) return NULL_CONNECTION return peer_shard_conn.get_forwarding_connection()
def get_connection_to_forward(self, metadata): """ Override ProxyConnection.get_connection_to_forward() """ if metadata.cluster_peer_id == 0: # RPC from master return None if (metadata.branch.get_full_shard_id() not in self.env.quark_chain_config.get_full_shard_ids()): self.close_with_error("incorrect forwarding branch {}".format( metadata.branch.to_str())) shard = self.shards.get(metadata.branch, None) if not shard: # shard has not been created yet return NULL_CONNECTION peer_shard_conn = shard.peers.get(metadata.cluster_peer_id, None) if peer_shard_conn is None: # Master can close the peer connection at any time # TODO: any way to avoid this race? Logger.warning_every_sec( "cannot find peer shard conn for cluster id {}".format( metadata.cluster_peer_id), 1, ) return NULL_CONNECTION return peer_shard_conn.get_forwarding_connection()
async def add_block(self, block): """ Returns true if block is successfully added. False on any error. called by 1. local miner (will not run if syncing) 2. SyncTask """ old_tip = self.state.header_tip try: xshard_list = self.state.add_block(block) except Exception as e: Logger.error_exception() return False # only remove from pool if the block successfully added to state, # this may cache failed blocks but prevents them being broadcasted more than needed # TODO add ttl to blocks in new_block_pool self.state.new_block_pool.pop(block.header.get_hash(), None) # block has been added to local state, broadcast tip so that peers can sync if needed try: if old_tip != self.state.header_tip: self.broadcast_new_tip() except Exception: Logger.warning_every_sec("broadcast tip failure", 1) # block already existed in local shard state # but might not have been propagated to other shards and master # let's make sure all the shards and master got it before return if xshard_list is None: future = self.add_block_futures.get(block.header.get_hash(), None) if future: Logger.info( "[{}] {} is being added ... waiting for it to finish". format(block.header.branch.get_shard_id(), block.header.height)) await future return True self.add_block_futures[ block.header.get_hash()] = self.loop.create_future() # Start mining new one before propagating inside cluster # The propagation should be done by the time the new block is mined self.miner.mine_new_block_async() prev_root_height = self.state.db.get_root_block_by_hash( block.header.hash_prev_root_block).header.height await self.slave.broadcast_xshard_tx_list(block, xshard_list, prev_root_height) await self.slave.send_minor_block_header_to_master( block.header, len(block.tx_list), len(xshard_list), self.state.get_shard_stats(), ) self.add_block_futures[block.header.get_hash()].set_result(None) del self.add_block_futures[block.header.get_hash()] return True
async def add_block(self, block): """ Returns true if block is successfully added. False on any error. called by 1. local miner (will not run if syncing) 2. SyncTask """ block_hash = block.header.get_hash() commit_status, future = self.__get_block_commit_status_by_hash( block_hash) if commit_status == BLOCK_COMMITTED: return True elif commit_status == BLOCK_COMMITTING: Logger.info( "[{}] {} is being added ... waiting for it to finish".format( block.header.branch.to_str(), block.header.height)) await future return True check(commit_status == BLOCK_UNCOMMITTED) # Validate and add the block old_tip = self.state.header_tip try: xshard_list, coinbase_amount_map = self.state.add_block(block, force=True) except Exception as e: Logger.error_exception() return False # only remove from pool if the block successfully added to state, # this may cache failed blocks but prevents them being broadcasted more than needed # TODO add ttl to blocks in new_block_header_pool self.state.new_block_header_pool.pop(block_hash, None) # block has been added to local state, broadcast tip so that peers can sync if needed try: if old_tip != self.state.header_tip: self.broadcast_new_tip() except Exception: Logger.warning_every_sec("broadcast tip failure", 1) # Add the block in future and wait self.add_block_futures[block_hash] = self.loop.create_future() prev_root_height = self.state.db.get_root_block_header_by_hash( block.header.hash_prev_root_block).height await self.slave.broadcast_xshard_tx_list(block, xshard_list, prev_root_height) await self.slave.send_minor_block_header_to_master( block.header, len(block.tx_list), len(xshard_list), coinbase_amount_map, self.state.get_shard_stats(), ) # Commit the block self.state.commit_by_hash(block_hash) Logger.debug("committed mblock {}".format(block_hash.hex())) # Notify the rest self.add_block_futures[block_hash].set_result(None) del self.add_block_futures[block_hash] return True