def place_hold(self, block_hash, connection) -> None: """ Places hold on block hash and propagates message. :param block_hash: ObjectHash :param connection: """ block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HOLD_REQUESTED, network_num=connection.network_num, peers=[connection], ) if block_hash in self._node.blocks_seen.contents: return if block_hash not in self._holds.contents: self._holds.add(block_hash, BlockHold(time.time(), connection)) conns = self._node.broadcast( BlockHoldingMessage(block_hash, self._node.network_num), broadcasting_conn=connection, connection_types=(ConnectionType.RELAY_BLOCK, ConnectionType.GATEWAY)) if len(conns) > 0: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HOLD_SENT_BY_GATEWAY_TO_PEERS, network_num=self._node.network_num, peers=conns, )
def advance_bytes_written_to_socket(self, bytes_sent): if self.message_tracker and self.message_tracker.is_sending_block_message(): assert self.node.opts.track_detailed_sent_messages entry = self.message_tracker.messages[0] super(AbstractGatewayBlockchainConnection, self).advance_bytes_written_to_socket(bytes_sent) if not self.message_tracker.is_sending_block_message(): block_message = typing.cast(AbstractBlockMessage, entry.message) block_message_queue_time = entry.queued_time block_message_length = entry.length block_hash = block_message.block_hash() handling_time, relay_desc = self.node.track_block_from_bdn_handling_ended(block_hash) block_stats.add_block_event_by_block_hash(block_hash, BlockStatEventType.BLOCK_SENT_TO_BLOCKCHAIN_NODE, network_num=self.network_num, more_info="{} in {}; Handled in {}; R - {}; {}".format( stats_format.byte_count( block_message_length ), stats_format.timespan( block_message_queue_time, time.time() ), stats_format.duration(handling_time), relay_desc, block_message.extra_stats_data() )) else: super(AbstractGatewayBlockchainConnection, self).advance_bytes_written_to_socket(bytes_sent)
def _holding_timeout(self, block_hash, hold): block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HOLD_TIMED_OUT, network_num=hold.connection.network_num, peers=[hold.connection]) self._process_and_broadcast_block(hold.block_message, hold.connection)
def _process_ready_new_blocks(self): while self._ready_new_blocks: ready_block_hash = self._ready_new_blocks.pop() pending_new_block = self.pending_new_block_parts.contents[ ready_block_hash] last_known_total_difficulty = self.node.try_calculate_total_difficulty( ready_block_hash, pending_new_block) new_block_msg = InternalEthBlockInfo.from_new_block_parts( pending_new_block, last_known_total_difficulty) self.pending_new_block_parts.remove_item(ready_block_hash) if self.is_valid_block_timestamp(new_block_msg): block_stats.add_block_event_by_block_hash( ready_block_hash, BlockStatEventType.BLOCK_RECEIVED_FROM_BLOCKCHAIN_NODE, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}. {}".format( self.node.opts.blockchain_protocol, self.node.opts.blockchain_network, new_block_msg.extra_stats_data()), block_height=new_block_msg.block_number(), ) self.node.block_queuing_service.mark_block_seen_by_blockchain_node( ready_block_hash, new_block_msg) self.node.block_processing_service.queue_block_for_processing( new_block_msg, self.connection)
def send_block_to_node(self, block_hash: Sha256Hash, block_msg: Optional[TBlockMessage] = None) -> None: if not self.node.should_process_block_hash(block_hash): return if block_msg is None: block_msg = self._blocks[block_hash] logger.info("Forwarding block {} to blockchain node.", block_hash) assert block_msg is not None self.node.send_msg_to_node(block_msg) ( handling_time, relay_desc, ) = self.node.track_block_from_bdn_handling_ended(block_hash) # if tracking detailed send info, log this event only after all # bytes written to sockets if not self.node.opts.track_detailed_sent_messages: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_SENT_TO_BLOCKCHAIN_NODE, network_num=self.node.network_num, more_info="{} bytes; Handled in {}; R - {}; {}".format( len(block_msg.rawbytes()), stats_format.duration(handling_time), relay_desc, block_msg.extra_stats_data(), ), )
def record_block_receipt(self, cipher_hash, connection): """ Records a receipt of a block hash. Releases key if threshold reached. :param cipher_hash encrypted block ObjectHash :param connection posting block received receipt """ if cipher_hash in self._receipt_tracker: self._receipt_tracker[cipher_hash] += 1 block_stats.add_block_event_by_block_hash( cipher_hash, BlockStatEventType.ENC_BLOCK_RECEIVED_BLOCK_RECEIPT, network_num=self._node.network_num, peers=[connection], more_info="{}, {} receipts".format( stats_format.connection(connection), self._receipt_tracker[cipher_hash])) if self._are_enough_receipts_received(cipher_hash): logger.debug( "Received enough block receipt messages. Releasing key for block with hash: {}", convert.bytes_to_hex(cipher_hash.binary)) self._send_key(cipher_hash) self._node.alarm_queue.unregister_alarm( self._alarms[cipher_hash]) del self._receipt_tracker[cipher_hash] del self._alarms[cipher_hash]
def _propagate_block_to_gateway_peers(self, cipher_hash, bx_block): """ Propagates unencrypted bx_block to all gateway peers for encryption and sending to bloXroute. Also sends keys to bloXroute in case this was user error (e.g. no gateway peers). Called after a timeout. This invalidates all future bx_block receipts. """ bx_block_hash = crypto.double_sha256(bx_block) hex_bx_block_hash = convert.bytes_to_hex(bx_block_hash) logger.debug("Did not receive enough receipts for: {}. Propagating compressed block to other gateways: {}", cipher_hash, hex_bx_block_hash) self._send_key(cipher_hash) request = BlockPropagationRequestMessage(bx_block) conns = self._node.broadcast(request, None, connection_types=(ConnectionType.GATEWAY,)) block_stats.add_block_event_by_block_hash(cipher_hash, BlockStatEventType.ENC_BLOCK_PROPAGATION_NEEDED, network_num=self._node.network_num, compressed_block_hash=hex_bx_block_hash, peers=conns, more_info="Peers: {}, {} receipts".format( stats_format.connections(conns), self._receipt_tracker[cipher_hash])) del self._receipt_tracker[cipher_hash] del self._alarms[cipher_hash] return constants.CANCEL_ALARMS
def _propagate_unencrypted_block_to_network(self, bx_block, connection, block_info): if block_info is None: raise ValueError( "Block info is required to propagate unencrypted block") broadcast_message = BroadcastMessage(block_info.block_hash, self._node.network_num, is_encrypted=False, blob=bx_block) conns = self._node.broadcast( broadcast_message, connection, connection_types=[ConnectionType.RELAY_BLOCK]) handling_duration = self._node.track_block_from_node_handling_ended( block_info.block_hash) block_stats.add_block_event_by_block_hash( block_info.block_hash, BlockStatEventType.ENC_BLOCK_SENT_FROM_GATEWAY_TO_NETWORK, network_num=self._node.network_num, requested_by_peer=False, peers=conns, more_info="Peers: {}; Unencrypted; {}; Handled in {}".format( stats_format.connections(conns), self._format_block_info_stats(block_info), stats_format.duration(handling_duration))) logger.info("Propagating block {} to the BDN.", block_info.block_hash) return broadcast_message
def send_block_to_node(self, block_hash: Sha256Hash, block_msg: Optional[TBlockMessage] = None) -> None: if not self.node.should_process_block_hash(block_hash): return if block_msg is None: block_msg = self.node.block_storage[block_hash] self.connection.log_info("Forwarding block {} to node", block_hash) assert block_msg is not None self.connection.enqueue_msg(block_msg) # TODO: revisit this metric for multi-node gateway (handling_time, relay_desc ) = self.node.track_block_from_bdn_handling_ended(block_hash) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_SENT_TO_BLOCKCHAIN_NODE, network_num=self.node.network_num, more_info="{} bytes; Handled in {}; R - {}; {}".format( len(block_msg.rawbytes()), stats_format.duration(handling_time), relay_desc, block_msg.extra_stats_data(), ), )
def _propagate_encrypted_block_to_network(self, bx_block, connection, block_info): if block_info is None or block_info.block_hash is None: block_hash = b"Unknown" requested_by_peer = True else: block_hash = block_info.block_hash requested_by_peer = False encrypt_start_datetime = datetime.datetime.utcnow() encrypt_start_timestamp = time.time() encrypted_block, raw_cipher_hash = self._node.in_progress_blocks.encrypt_and_add_payload( bx_block) compressed_size = len(bx_block) encrypted_size = len(encrypted_block) encryption_details = "Encryption: {}; Size change: {}->{}bytes, {}".format( stats_format.timespan(encrypt_start_timestamp, time.time()), compressed_size, encrypted_size, stats_format.ratio(encrypted_size, compressed_size)) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_ENCRYPTED, start_date_time=encrypt_start_datetime, end_date_time=datetime.datetime.utcnow(), network_num=self._node.network_num, matching_block_hash=convert.bytes_to_hex(raw_cipher_hash), matching_block_type=StatBlockType.ENCRYPTED.value, more_info=encryption_details) cipher_hash = Sha256Hash(raw_cipher_hash) broadcast_message = BroadcastMessage(cipher_hash, self._node.network_num, is_encrypted=True, blob=encrypted_block) conns = self._node.broadcast( broadcast_message, connection, connection_types=[ConnectionType.RELAY_BLOCK]) handling_duration = self._node.track_block_from_node_handling_ended( block_hash) block_stats.add_block_event_by_block_hash( cipher_hash, BlockStatEventType.ENC_BLOCK_SENT_FROM_GATEWAY_TO_NETWORK, network_num=self._node.network_num, requested_by_peer=requested_by_peer, peers=conns, more_info="Peers: {}; {}; {}; Requested by peer: {}; Handled in {}" .format(stats_format.connections(conns), encryption_details, self._format_block_info_stats(block_info), requested_by_peer, stats_format.duration(handling_duration))) self.register_for_block_receipts(cipher_hash, bx_block) return broadcast_message
def can_add_block_to_queuing_service(self, block_hash: Sha256Hash) -> bool: if block_hash in self._blocks_seen_by_blockchain_node: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_IGNORE_SEEN_BY_BLOCKCHAIN_NODE, self.node.network_num, ) return False return True
def msg_new_block_hashes(self, msg: NewBlockHashesEthProtocolMessage): if not self.node.should_process_block_hash(msg.block_hash()): return block_hash_number_pairs = [] for block_hash, block_number in msg.get_block_hash_number_pairs(): block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_ANNOUNCED_BY_BLOCKCHAIN_NODE, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}. {}".format( self.node.opts.blockchain_protocol, self.node.opts.blockchain_network, msg.extra_stats_data()), block_height=block_number, ) gateway_bdn_performance_stats_service.log_block_message_from_blockchain_node( False) if block_hash in self.node.blocks_seen.contents: self.node.on_block_seen_by_blockchain_node( block_hash, block_number=block_number) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType. BLOCK_RECEIVED_FROM_BLOCKCHAIN_NODE_IGNORE_SEEN, network_num=self.connection.network_num, block_height=block_number, ) self.connection.log_info( "Ignoring duplicate block {} from local blockchain node.", block_hash) continue recovery_cancelled = self.node.on_block_seen_by_blockchain_node( block_hash, block_number=block_number) if recovery_cancelled: continue self.node.track_block_from_node_handling_started(block_hash) block_hash_number_pairs.append((block_hash, block_number)) self.connection.log_info( "Fetching block {} from local Ethereum node.", block_hash) if not block_hash_number_pairs: return for block_hash, block_number in block_hash_number_pairs: # pyre-fixme[6]: Expected `memoryview` for 1st param but got `None`. self.pending_new_block_parts.add( block_hash, NewBlockParts(None, None, block_number)) self.connection.enqueue_msg( GetBlockHeadersEthProtocolMessage(None, block_hash.binary, 1, 0, False)) self.request_block_body( [block_hash for block_hash, _ in block_hash_number_pairs])
def msg_block(self, msg: BlockOntMessage) -> None: block_stats.add_block_event_by_block_hash( msg.block_hash(), BlockStatEventType.REMOTE_BLOCK_RECEIVED_BY_GATEWAY, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}".format( self.connection.node.opts.blockchain_protocol, self.connection.node.opts.blockchain_network)) return self.msg_proxy_response(msg)
def msg_get_data(self, msg: GetDataOntMessage) -> None: inventory_type, item_hash = msg.inv_type() if inventory_type == InventoryOntType.MSG_BLOCK.value: block_stats.add_block_event_by_block_hash( item_hash, BlockStatEventType.REMOTE_BLOCK_REQUESTED_BY_GATEWAY, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}".format( self.node.opts.blockchain_protocol, self.node.opts.blockchain_network)) self.node.block_queuing_service.send_block_to_nodes(item_hash)
def process_msg_block(self, msg: AbstractBlockMessage, block_number: Optional[int] = None) -> None: block_hash = msg.block_hash() # if gateway is still syncing, skip this process if not self.node.should_process_block_hash(block_hash): return self.node.block_cleanup_service.on_new_block_received( block_hash, msg.prev_block_hash()) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_RECEIVED_FROM_BLOCKCHAIN_NODE, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}".format( self.node.opts.blockchain_protocol, self.node.opts.blockchain_network, msg.extra_stats_data())) gateway_bdn_performance_stats_service.log_block_message_from_blockchain_node( self.connection.endpoint, True) if block_hash in self.node.blocks_seen.contents: self.node.on_block_seen_by_blockchain_node( block_hash, self.connection, msg, block_number=block_number) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType. BLOCK_RECEIVED_FROM_BLOCKCHAIN_NODE_IGNORE_SEEN, network_num=self.connection.network_num) self.connection.log_info( "Discarding duplicate block {} from local blockchain node.", block_hash) self.node.log_blocks_network_content(self.node.network_num, msg) return if not self.is_valid_block_timestamp(msg): return gateway_bdn_performance_stats_service.log_block_from_blockchain_node( self.connection.endpoint) canceled_recovery = self.node.on_block_seen_by_blockchain_node( block_hash, self.connection, msg) if canceled_recovery: return self.node.track_block_from_node_handling_started(block_hash) self.node.on_block_seen_by_blockchain_node(block_hash, self.connection, msg, block_number=block_number) self.node.block_processing_service.queue_block_for_processing( msg, self.connection) self.node.block_queuing_service_manager.push( block_hash, msg, node_received_from=self.connection) return
def msg_block_propagation_request(self, msg): bx_block = msg.blob() bx_block_hash = crypto.double_sha256(bx_block) block_stats.add_block_event_by_block_hash( bx_block_hash, BlockStatEventType.BX_BLOCK_PROPAGATION_REQUESTED_BY_PEER, network_num=self.network_num, peers=[self], ) self.node.neutrality_service.propagate_block_to_network(bx_block, self, from_peer=True)
def try_send_header_to_node(self, block_hash: Sha256Hash) -> bool: if not self.node.block_queuing_service_manager.is_in_common_block_storage(block_hash): return False block_message = cast(TBlockMessage, self.node.block_storage[block_hash]) header_msg = self.build_block_header_message(block_hash, block_message) self.connection.enqueue_msg(header_msg) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HEADER_SENT_TO_BLOCKCHAIN_NODE, network_num=self.node.network_num, ) return True
def log_requested_remote_blocks(self, block_hashes: List[Sha256Hash]) -> None: if self._skip_remote_block_requests_stats_count > 0: self._skip_remote_block_requests_stats_count -= 1 else: for block_hash in block_hashes: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.REMOTE_BLOCK_REQUESTED_BY_GATEWAY, network_num=self.network_num, more_info=f"Protocol: {self.opts.blockchain_protocol}, " f"Network: {self.opts.blockchain_network}") self._requested_remote_blocks_queue.append(block_hashes)
def msg_compressed_block_txs(self, msg: CompressedBlockTxsMessage): start_time = time.time() self.msg_txs(msg.to_txs_message(), RecoveredTxsSource.COMPRESSED_BLOCK_TXS_RECEIVED) block_stats.add_block_event_by_block_hash( msg.block_hash(), BlockStatEventType.ENC_BLOCK_COMPRESSED_TXS_RECEIVED_BY_GATEWAY, network_num=msg.network_num(), peers=[self], more_info="{}. processing time: {}".format( stats_format.connection(self), stats_format.timespan(start_time, time.time())))
def _send_key(self, cipher_hash): key = self._node.in_progress_blocks.get_encryption_key(bytes(cipher_hash.binary)) key_message = KeyMessage(cipher_hash, self._node.network_num, key=key) conns = self._node.broadcast( key_message, None, connection_types=(ConnectionType.RELAY_BLOCK, ConnectionType.GATEWAY) ) block_stats.add_block_event_by_block_hash( cipher_hash, BlockStatEventType.ENC_BLOCK_KEY_SENT_FROM_GATEWAY_TO_NETWORK, network_num=self._node.network_num, peers=conns, )
def _process_ready_new_blocks(self): while self._ready_new_blocks: ready_block_hash = self._ready_new_blocks.pop() pending_new_block = self.pending_new_block_parts.contents[ ready_block_hash] self.pending_new_block_parts.remove_item(ready_block_hash) if ready_block_hash in self.node.blocks_seen.contents: self.node.on_block_seen_by_blockchain_node( ready_block_hash, self.connection, block_number=pending_new_block.block_number) self.connection.log_info( "Discarding already seen block {} received in block bodies msg from local blockchain node.", ready_block_hash) return last_known_total_difficulty = self.node.try_calculate_total_difficulty( ready_block_hash, pending_new_block) new_block_msg = InternalEthBlockInfo.from_new_block_parts( pending_new_block, last_known_total_difficulty) if self.is_valid_block_timestamp(new_block_msg): block_stats.add_block_event_by_block_hash( ready_block_hash, BlockStatEventType.BLOCK_RECEIVED_FROM_BLOCKCHAIN_NODE, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}. {}".format( self.node.opts.blockchain_protocol, self.node.opts.blockchain_network, new_block_msg.extra_stats_data()), block_height=new_block_msg.block_number(), ) gateway_bdn_performance_stats_service.log_block_from_blockchain_node( self.connection.endpoint) canceled_recovery = self.node.on_block_seen_by_blockchain_node( ready_block_hash, self.connection, new_block_msg, pending_new_block.block_number) if canceled_recovery: return self.node.block_queuing_service_manager.push( ready_block_hash, new_block_msg, node_received_from=self.connection) self.node.block_processing_service.queue_block_for_processing( new_block_msg, self.connection)
def try_send_header_to_node(self, block_hash: Sha256Hash) -> bool: if block_hash not in self._blocks: return False block_message = self._blocks[block_hash] if block_message is None: return False header_msg = self.build_block_header_message(block_hash, block_message) self.node.send_msg_to_node(header_msg) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HEADER_SENT_TO_BLOCKCHAIN_NODE, network_num=self.node.network_num, ) return True
def cancel_hold_timeout(self, block_hash, connection): """ Lifts hold on block hash and cancels timeout. :param block_hash: ObjectHash :param connection: connection cancelling hold """ if block_hash in self._holds.contents: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HOLD_LIFTED, network_num=connection.network_num, more_info=stats_format.connection(connection)) hold = self._holds.contents[block_hash] if hold.alarm is not None: self._node.alarm_queue.unregister_alarm(hold.alarm) del self._holds.contents[block_hash]
def _check_for_sent_or_queued_forked_block(self, block_hash: Sha256Hash, block_number: int) -> bool: """ Returns True if a block has already been queued or sent at the same height. """ is_duplicate = False more_info = "" for queued_block_hash, timestamp in self._block_queue: if (not self._blocks_waiting_for_recovery[queued_block_hash] and queued_block_hash in self._height_by_block_hash): if block_number == self._height_by_block_hash[ queued_block_hash]: self.connection.log_info( "In queuing service, fork detected at height {}. Setting aside block {} in favor of {}.", block_number, block_hash, queued_block_hash) is_duplicate = True more_info = "already queued" if block_number in self.sent_block_at_height: self.connection.log_info( "In queuing service, fork detected at height {}. " "Setting aside block {} in favor of already sent {}.", block_number, block_hash, self.sent_block_at_height[block_number]) is_duplicate = True more_info = "already sent" if block_number in self.accepted_block_hash_at_height: self.connection.log_info( "In queuing service, fork detected at height {}. " "Setting aside block {} in favor of already accepted {}.", block_number, block_hash, self.accepted_block_hash_at_height[block_number]) is_duplicate = True more_info = "already accepted" if is_duplicate: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_IGNORE_DUPLICATE_HEIGHT, self.node.network_num, more_info=more_info) return is_duplicate
def queue_block_for_processing(self, block_message, connection): """ Queues up block for processing on timeout if hold message received. If no hold exists, compress and broadcast block immediately. :param block_message: block message to process :param connection: receiving connection (AbstractBlockchainConnection) """ block_hash = block_message.block_hash() connection.log_info("Processing block {} from local blockchain node.", block_hash) if block_hash in self._holds.contents: hold: BlockHold = self._holds.contents[block_hash] block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HOLD_HELD_BLOCK, network_num=connection.network_num, more_info=stats_format.connection(hold.holding_connection)) if hold.alarm is None: hold.alarm = self._node.alarm_queue.register_alarm( self._node.opts.blockchain_block_hold_timeout_s, self._holding_timeout, block_hash, hold) hold.block_message = block_message hold.connection = connection else: # Broadcast BlockHoldingMessage through relays and gateways conns = self._node.broadcast(BlockHoldingMessage( block_hash, self._node.network_num), broadcasting_conn=connection, prepend_to_queue=True, connection_types=[ ConnectionType.RELAY_BLOCK, ConnectionType.GATEWAY ]) if len(conns) > 0: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_HOLD_SENT_BY_GATEWAY_TO_PEERS, network_num=self._node.network_num, more_info=stats_format.connections(conns)) self._process_and_broadcast_block(block_message, connection)
def msg_get_data(self, msg: GetDataBtcMessage) -> None: """ Handle GETDATA message from Bitcoin node. :param msg: GETDATA message """ for inv_type, object_hash in msg: if InventoryType.is_block(inv_type): block_stats.add_block_event_by_block_hash( object_hash, BlockStatEventType.REMOTE_BLOCK_REQUESTED_BY_GATEWAY, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}".format( self.node.opts.blockchain_protocol, self.node.opts.blockchain_network)) inv_msg = InvBtcMessage(magic=self.magic, inv_vects=[(InventoryType.MSG_BLOCK, object_hash)]) self.node.send_msg_to_node(inv_msg) return self.msg_proxy_request(msg)
def log_received_remote_blocks(self, blocks_count: int) -> None: if len(self._requested_remote_blocks_queue) > 0: expected_blocks = self._requested_remote_blocks_queue.pop() if len(expected_blocks) != blocks_count: logger.warning(log_messages.BLOCK_COUNT_MISMATCH, blocks_count, len(expected_blocks)) self._skip_remote_block_requests_stats_count = len(self._requested_remote_blocks_queue) * 2 self._requested_remote_blocks_queue.clear() return for block_hash in expected_blocks: block_stats.add_block_event_by_block_hash(block_hash, BlockStatEventType.REMOTE_BLOCK_RECEIVED_BY_GATEWAY, network_num=self.network_num, more_info="Protocol: {}, Network: {}".format( self.opts.blockchain_protocol, self.opts.blockchain_network)) else: logger.warning(log_messages.UNEXPECTED_BLOCKS)
def start_transaction_recovery( self, unknown_sids: Iterable[int], unknown_hashes: Iterable[Sha256Hash], block_hash: Sha256Hash, connection: Optional[AbstractRelayConnection] = None): all_unknown_sids = [] all_unknown_sids.extend(unknown_sids) tx_service = self._node.get_tx_service() # retrieving sids of txs with unknown contents for tx_hash in unknown_hashes: tx_sid = tx_service.get_short_id(tx_hash) all_unknown_sids.append(tx_sid) get_txs_message = GetTxsMessage(short_ids=all_unknown_sids) self._node.broadcast( get_txs_message, connection_types=[ConnectionType.RELAY_TRANSACTION]) if connection is not None: tx_stats.add_txs_by_short_ids_event( all_unknown_sids, TransactionStatEventType. TX_UNKNOWN_SHORT_IDS_REQUESTED_BY_GATEWAY_FROM_RELAY, network_num=self._node.network_num, peer=connection.peer_desc, block_hash=convert.bytes_to_hex(block_hash.binary)) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_RECOVERY_STARTED, network_num=connection.network_num, request_hash=convert.bytes_to_hex( crypto.double_sha256(get_txs_message.rawbytes()))) else: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_RECOVERY_REPEATED, network_num=self._node.network_num, request_hash=convert.bytes_to_hex( crypto.double_sha256(get_txs_message.rawbytes())))
def msg_block(self, msg: AbstractBlockMessage): """ Handle a block message. Sends to node for encryption, then broadcasts. """ block_hash = msg.block_hash() node = self.connection.node # if gateway is still syncing, skip this process if not node.should_process_block_hash(block_hash): return node.block_cleanup_service.on_new_block_received(block_hash, msg.prev_block_hash()) block_stats.add_block_event_by_block_hash(block_hash, BlockStatEventType.BLOCK_RECEIVED_FROM_BLOCKCHAIN_NODE, network_num=self.connection.network_num, more_info="Protocol: {}, Network: {}".format( node.opts.blockchain_protocol, node.opts.blockchain_network, msg.extra_stats_data() ) ) if block_hash in self.connection.node.blocks_seen.contents: node.on_block_seen_by_blockchain_node(block_hash) block_stats.add_block_event_by_block_hash(block_hash, BlockStatEventType.BLOCK_RECEIVED_FROM_BLOCKCHAIN_NODE_IGNORE_SEEN, network_num=self.connection.network_num) self.connection.log_info( "Discarding duplicate block {} from local blockchain node.", block_hash ) return if not self.is_valid_block_timestamp(msg): return node.track_block_from_node_handling_started(block_hash) node.on_block_seen_by_blockchain_node(block_hash, msg) node.block_processing_service.queue_block_for_processing(msg, self.connection) gateway_bdn_performance_stats_service.log_block_from_blockchain_node() node.block_queuing_service.store_block_data(block_hash, msg) return
def start_transaction_recovery( self, unknown_sids: Iterable[int], unknown_hashes: Iterable[Sha256Hash], block_hash: Sha256Hash, connection: Optional[AbstractRelayConnection] = None) -> None: all_unknown_sids = [] all_unknown_sids.extend(unknown_sids) tx_service = self._node.get_tx_service() # retrieving sids of txs with unknown contents for tx_hash in unknown_hashes: transaction_key = tx_service.get_transaction_key(tx_hash) tx_sid = tx_service.get_short_id_by_key(transaction_key) all_unknown_sids.append(tx_sid) if not self._node.opts.request_recovery: if connection is not None: network_num = connection.network_num else: network_num = self._node.network_num # log recovery started to match with recovery completing block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_RECOVERY_STARTED, network_num=network_num, txs_count=len(all_unknown_sids), more_info="recovery from relay is disabled", ) return get_txs_message = GetTxsMessage(short_ids=all_unknown_sids) self._node.broadcast( get_txs_message, connection_types=(ConnectionType.RELAY_TRANSACTION, )) if connection is not None: tx_stats.add_txs_by_short_ids_event( all_unknown_sids, TransactionStatEventType. TX_UNKNOWN_SHORT_IDS_REQUESTED_BY_GATEWAY_FROM_RELAY, network_num=self._node.network_num, peers=[connection], block_hash=convert.bytes_to_hex(block_hash.binary)) block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_RECOVERY_STARTED, network_num=connection.network_num, txs_count=len(all_unknown_sids), request_hash=convert.bytes_to_hex( crypto.double_sha256(get_txs_message.rawbytes()))) else: block_stats.add_block_event_by_block_hash( block_hash, BlockStatEventType.BLOCK_RECOVERY_REPEATED, network_num=self._node.network_num, txs_count=len(all_unknown_sids), request_hash=convert.bytes_to_hex( crypto.double_sha256(get_txs_message.rawbytes())))