def msg_inv(self, msg: InvBtcMessage) -> None: """ Handle an inventory message. Requests all transactions and blocks that haven't been previously seen. :param msg: INV message """ contains_block = False inventory_requests = [] block_hashes = [] for inventory_type, item_hash in msg: if InventoryType.is_block(inventory_type): if not self.node.should_process_block_hash(item_hash): continue block_hashes.append(item_hash) if item_hash not in self.node.blocks_seen.contents: contains_block = True inventory_requests.append((inventory_type, item_hash)) else: inventory_requests.append((inventory_type, item_hash)) self.node.block_cleanup_service.mark_blocks_and_request_cleanup( block_hashes) if inventory_requests: get_data = GetDataBtcMessage( magic=msg.magic(), inv_vects=inventory_requests, request_witness_data=self.request_witness_data) self.connection.enqueue_msg(get_data, prepend=contains_block) self.node.block_queuing_service.mark_blocks_seen_by_blockchain_node( block_hashes)
def test_parse_message_success_all_types(self): # TODO: pull these numbers into constants, along with all the BTC messages self.create_message_successfully(self.VERSION_BTC_MESSAGE, VersionBtcMessage) self.create_message_successfully(VerAckBtcMessage(self.MAGIC), VerAckBtcMessage) self.create_message_successfully(PingBtcMessage(self.MAGIC), PingBtcMessage) self.create_message_successfully(PongBtcMessage(self.MAGIC, 123), PongBtcMessage) self.create_message_successfully(GetAddrBtcMessage(self.MAGIC), GetAddrBtcMessage) self.create_message_successfully( AddrBtcMessage(self.MAGIC, [(int(time.time()), "127.0.0.1", 8000)]), AddrBtcMessage) inv_vector = [(1, self.HASH), (2, self.HASH)] self.create_message_successfully(InvBtcMessage(self.MAGIC, inv_vector), InvBtcMessage) self.create_message_successfully( GetDataBtcMessage(self.MAGIC, inv_vector), GetDataBtcMessage) self.create_message_successfully( NotFoundBtcMessage(self.MAGIC, inv_vector), NotFoundBtcMessage) hashes = [self.HASH, self.HASH] self.create_message_successfully( GetHeadersBtcMessage(self.MAGIC, self.VERSION, hashes, self.HASH), GetHeadersBtcMessage) self.create_message_successfully( GetBlocksBtcMessage(self.MAGIC, self.VERSION, hashes, self.HASH), GetBlocksBtcMessage) self.create_message_successfully( TxBtcMessage(self.MAGIC, self.VERSION, [], [], 0), TxBtcMessage) txs = [TxIn(buf=bytearray(10), length=10, off=0).rawbytes()] * 5 self.create_message_successfully( BlockBtcMessage(self.MAGIC, self.VERSION, self.HASH, self.HASH, 0, 0, 0, txs), BlockBtcMessage) self.create_message_successfully( HeadersBtcMessage(self.MAGIC, [helpers.generate_bytearray(81)] * 2), HeadersBtcMessage) self.create_message_successfully( RejectBtcMessage(self.MAGIC, b"a message", RejectBtcMessage.REJECT_MALFORMED, b"test break", helpers.generate_bytearray(10)), RejectBtcMessage) self.create_message_successfully(SendHeadersBtcMessage(self.MAGIC), SendHeadersBtcMessage) self.create_message_successfully( FeeFilterBtcMessage(self.MAGIC, fee_rate=100), FeeFilterBtcMessage) self.create_message_successfully( BtcMessage(self.MAGIC, b'xversion', 0, bytearray(30)), XversionBtcMessage)
def on_block_sent(self, block_hash: Sha256Hash, block_message: BlockBtcMessage): # After sending block message to Bitcoin node sending INV message for the same block to the node # This is needed to update Synced Headers value of the gateway peer on the Bitcoin node # If Synced Headers is not up-to-date than Bitcoin node does not push compact blocks to the gateway inv_msg = InvBtcMessage( magic=block_message.magic(), inv_vects=[(InventoryType.MSG_BLOCK, block_hash)], ) self.node.send_msg_to_node(inv_msg)
def msg_reject(self, msg): """ Handle REJECT message from Bitcoin node :param msg: REJECT message """ # Send inv message to the send in case of rejected block # remaining sync communication will proxy to remote blockchain node if msg.message() == BtcMessageType.BLOCK: inv_msg = InvBtcMessage(magic=self.magic, inv_vects=[(InventoryType.MSG_BLOCK, msg.obj_hash())]) self.node.send_msg_to_node(inv_msg)
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 msg_block(self, msg) -> None: """ Handle block message """ block_hash = msg.block_hash() if not self.node.should_process_block_hash(block_hash): return if self.node.block_cleanup_service.is_marked_for_cleanup(block_hash): self.connection.log_trace("Marked block for cleanup: {}", block_hash) self.node.block_cleanup_service.clean_block_transactions( transaction_service=self.node.get_tx_service(), block_msg=msg) else: self.process_msg_block(msg) # After receiving block message sending INV message for the same block to Bitcoin node # This is needed to update Synced Headers value of the gateway peer on the Bitcoin node # If Synced Headers is not up-to-date than Bitcoin node does not push compact blocks to the gateway inv_msg = InvBtcMessage(magic=self.node.opts.blockchain_net_magic, inv_vects=[(InventoryType.MSG_BLOCK, msg.block_hash())]) self.connection.enqueue_msg(inv_msg)
def test_get_data_only_new_data(self): seen_block_hash = BtcObjectHash( buf=helpers.generate_bytearray(BTC_SHA_HASH_LEN), length=BTC_SHA_HASH_LEN) not_seen_block_hash = BtcObjectHash( buf=helpers.generate_bytearray(BTC_SHA_HASH_LEN), length=BTC_SHA_HASH_LEN) self.node.blocks_seen.add(seen_block_hash) inv_message = InvBtcMessage( magic=123, inv_vects=[(InventoryType.MSG_TX, seen_block_hash), (InventoryType.MSG_BLOCK, not_seen_block_hash), (InventoryType.MSG_BLOCK, seen_block_hash)]) self.sut.msg_inv(inv_message) get_data_msg_bytes = self.sut.connection.get_bytes_to_send() get_data_msg = GetDataBtcMessage(buf=get_data_msg_bytes) self.assertEqual(2, get_data_msg.count()) self.assertIn((InventoryType.MSG_TX, seen_block_hash), get_data_msg) self.assertIn((InventoryType.MSG_BLOCK, not_seen_block_hash), get_data_msg)
def _create_inv_msg(self): return InvBtcMessage(magic=123, inv_vects=[(InventoryType.MSG_TX, self.tx_hash), (InventoryType.MSG_BLOCK, self.block_hash)])
def build_block_header_message( self, block_hash: Sha256Hash, block_message: BlockBtcMessage) -> InvBtcMessage: return InvBtcMessage(block_message.magic(), [(InventoryType.MSG_BLOCK, block_hash)])