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 test_complete_header_body_recovery(self): self.node.block_processing_service.queue_block_for_processing = MagicMock() self.node.block_queuing_service_manager.push = MagicMock() self.node.on_block_seen_by_blockchain_node = MagicMock(return_value=False) self.sut.is_valid_block_timestamp = MagicMock(return_value=True) header = mock_eth_messages.get_dummy_block_header(1) block = mock_eth_messages.get_dummy_block(1, header) block_hash = header.hash_object() new_block_hashes_message = NewBlockHashesEthProtocolMessage.from_block_hash_number_pair( block_hash, 1 ) header_message = BlockHeadersEthProtocolMessage(None, [header]) bodies_message = BlockBodiesEthProtocolMessage(None, [TransientBlockBody(block.transactions, block.uncles)]) self.sut.msg_new_block_hashes(new_block_hashes_message) self.node.on_block_seen_by_blockchain_node.assert_called_once() self.assertEqual(1, len(self.sut.pending_new_block_parts.contents)) self.assertEqual(2, len(self.enqueued_messages)) self.node.on_block_seen_by_blockchain_node.reset_mock() self.node.on_block_seen_by_blockchain_node = MagicMock(return_value=True) self.sut.msg_block_headers(header_message) self.sut.msg_block_bodies(bodies_message) self.assertEqual(1, len(gateway_bdn_performance_stats_service.interval_data.blockchain_node_to_bdn_stats)) for stats in gateway_bdn_performance_stats_service.interval_data.blockchain_node_to_bdn_stats.values(): self.assertEqual(1, stats.new_blocks_received_from_blockchain_node) self.assertEqual(0, stats.new_blocks_received_from_bdn) self.node.on_block_seen_by_blockchain_node.assert_called_once() self.node.block_queuing_service_manager.push.assert_not_called() self.node.block_processing_service.queue_block_for_processing.assert_not_called()
def send_block_to_node( self, block_hash: Sha256Hash, block_msg: Optional[InternalEthBlockInfo] = None, ) -> None: assert block_msg is not None # block must always be greater than previous best block_number = block_msg.block_number() best_height, _best_hash, _ = self.best_sent_block assert block_number > best_height new_block_parts = self.node.block_parts_storage[block_hash] if block_msg.has_total_difficulty(): new_block_msg = block_msg.to_new_block_msg() super(EthBlockQueuingService, self).send_block_to_node(block_hash, new_block_msg) self.node.set_known_total_difficulty( new_block_msg.block_hash(), new_block_msg.get_chain_difficulty()) else: calculated_total_difficulty = self.node.try_calculate_total_difficulty( block_hash, new_block_parts) if calculated_total_difficulty is None: # Total difficulty may be unknown after a long fork or # if gateways just started. Announcing new block hashes to # ETH node in that case. It # will request header and body separately. new_block_headers_msg = NewBlockHashesEthProtocolMessage.from_block_hash_number_pair( block_hash, new_block_parts.block_number) super(EthBlockQueuingService, self).send_block_to_node(block_hash, new_block_headers_msg) else: new_block_msg = NewBlockEthProtocolMessage.from_new_block_parts( new_block_parts, calculated_total_difficulty) super(EthBlockQueuingService, self).send_block_to_node(block_hash, new_block_msg) self.node.log_blocks_network_content(self.node.network_num, block_msg) self.sent_block_at_height[block_number] = block_hash self.best_sent_block = SentEthBlockInfo(block_number, block_hash, time.time()) self._schedule_confirmation_check(block_hash) if self.node.opts.filter_txs_factor > 0: self.node.on_transactions_in_block( block_msg.to_new_block_msg().txns())
def test_new_block_hashes_msg_from_block_hash(self): block_hash_bytes = helpers.generate_bytes( eth_common_constants.BLOCK_HASH_LEN) block_hash = Sha256Hash(block_hash_bytes) block_number = 1000 new_block_hashes_msg_from_hash = NewBlockHashesEthProtocolMessage.from_block_hash_number_pair( block_hash, block_number) new_block_hashes_msg_from_hash.deserialize() self.assertEqual( 1, len(new_block_hashes_msg_from_hash.get_block_hash_number_pairs())) deserialized_hash, deserialized_block_number = new_block_hashes_msg_from_hash.get_block_hash_number_pairs( )[0] self.assertEqual(deserialized_hash, block_hash) self.assertEqual(block_number, block_number)
def test_complete_header_body_fetch(self): self.node.block_processing_service.queue_block_for_processing = MagicMock() self.sut.is_valid_block_timestamp = MagicMock(return_value=True) header = mock_eth_messages.get_dummy_block_header(1) block = mock_eth_messages.get_dummy_block(1, header) block_hash = header.hash_object() new_block_hashes_message = NewBlockHashesEthProtocolMessage.from_block_hash_number_pair( block_hash, 1 ) header_message = BlockHeadersEthProtocolMessage(None, [header]) bodies_message = BlockBodiesEthProtocolMessage(None, [TransientBlockBody(block.transactions, block.uncles)]) self.sut.msg_new_block_hashes(new_block_hashes_message) self.assertEqual(1, len(self.sut.pending_new_block_parts.contents)) self.assertEqual(2, len(self.enqueued_messages)) self.sut.msg_block_headers(header_message) self.sut.msg_block_bodies(bodies_message) self.node.block_processing_service.queue_block_for_processing.assert_called_once()