def setUp(self): self.node = MockGatewayNode(gateway_helpers.get_gateway_opts( 8000, include_default_btc_args=True, compact_block_min_tx_count=5 )) self.node.block_processing_service = MagicMock() self.connection = BtcNodeConnection( MockSocketConnection(node=self.node, ip_address=LOCALHOST, port=123), self.node ) self.connection.node = self.node self.connection.peer_ip = LOCALHOST self.connection.peer_port = 8001 self.connection.network_num = 2 self.sut = BtcNodeConnectionProtocol(self.connection) full_block_msg = BlockBtcMessage( buf=bytearray(convert.hex_to_bytes(self.FULL_BLOCK_BYTES_HEX)) ) if self.node.opts.use_extensions: transaction_service = ExtensionTransactionService(self.node, 0) else: transaction_service = TransactionService(self.node, 0) short_id = 1 for tx in full_block_msg.txns(): tx_hash = btc_common_utils.get_txid(tx) transaction_service.set_transaction_contents(tx_hash, tx) transaction_service.assign_short_id(tx_hash, short_id) short_id += 1 self.sut.connection.node._tx_service = transaction_service
def test_get_txs_block_recovery_encrypted(self): block: BlockOntMessage = self.ont_block() transactions: List[TxOntMessage] = self.ont_transactions(block) # assign short ids that the local connection won't know about until it gets the txs message remote_transaction_service = ExtensionTransactionService( MockNode(gateway_helpers.get_gateway_opts(8999)), 0) short_id_mapping = {} for i, transaction in enumerate(transactions): tx_hash = transaction.tx_hash() remote_transaction_service.assign_short_id(tx_hash, i + 1) remote_transaction_service.set_transaction_contents( tx_hash, transaction.rawbytes()) short_id_mapping[tx_hash] = TransactionInfo( tx_hash, transaction.rawbytes(), i + 1) bx_block = bytes( self.gateway_node.message_converter.block_to_bx_block( block, remote_transaction_service)[0]) self.gateway_node.block_recovery_service.add_block = \ MagicMock(wraps=self.gateway_node.block_recovery_service.add_block) self.gateway_node.send_msg_to_node = MagicMock() self.gateway_node.broadcast = MagicMock() key, ciphertext = symmetric_encrypt(bx_block) block_hash = crypto.double_sha256(ciphertext) key_message = KeyMessage(Sha256Hash(block_hash), DEFAULT_NETWORK_NUM, "", key) broadcast_message = BroadcastMessage(Sha256Hash(block_hash), DEFAULT_NETWORK_NUM, "", BroadcastMessageType.BLOCK, True, ciphertext) self.sut.msg_broadcast(broadcast_message) self.gateway_node.broadcast.reset_mock() self.sut.msg_key(key_message) self.gateway_node.block_recovery_service.add_block.assert_called_once() self.assertEqual(2, self.gateway_node.broadcast.call_count) recovery_broadcast = self.gateway_node.broadcast.call_args_list[0] ((gettxs_message, ), recovery_kwargs) = recovery_broadcast self.assertIsInstance(gettxs_message, GetTxsMessage) self.assertIn(ConnectionType.RELAY_TRANSACTION, recovery_kwargs["connection_types"]) key_broadcast = self.gateway_node.broadcast.call_args_list[1] ((key_message, _conn), recovery_kwargs) = key_broadcast self.assertIsInstance(key_message, KeyMessage) self.assertIn(ConnectionType.GATEWAY, recovery_kwargs["connection_types"]) txs = [tx for tx in short_id_mapping.values()] txs_message = TxsMessage(txs=txs) self.sut.msg_txs(txs_message) self._assert_block_sent(block)
def test_msg_broadcast_duplicate_block_with_different_short_id(self): # test scenario when first received block is compressed with unknown short ids, # but second received block is compressed with known short ids ont_block = self.ont_block() block_hash = ont_block.block_hash() transactions = self.bx_transactions() unknown_sid_transaction_service = ExtensionTransactionService(MockNode( gateway_helpers.get_gateway_opts(8999)), 0) for i, transaction in enumerate(transactions): unknown_sid_transaction_service.assign_short_id(transaction.tx_hash(), i) unknown_sid_transaction_service.set_transaction_contents(transaction.tx_hash(), transaction.tx_val()) unknown_short_id_block = bytes( self.gateway_node.message_converter.block_to_bx_block( ont_block, unknown_sid_transaction_service, True, self.gateway_node.network.min_tx_age_seconds )[0] ) unknown_key, unknown_cipher = symmetric_encrypt(unknown_short_id_block) unknown_block_hash = crypto.double_sha256(unknown_cipher) unknown_message = BroadcastMessage(Sha256Hash(unknown_block_hash), self.TEST_NETWORK_NUM, "", BroadcastMessageType.BLOCK, False, bytearray(unknown_short_id_block)) unknown_key_message = KeyMessage(Sha256Hash(unknown_block_hash), self.TEST_NETWORK_NUM, "", unknown_key) local_transaction_service = self.gateway_node.get_tx_service() for i, transaction in enumerate(transactions): local_transaction_service.assign_short_id(transaction.tx_hash(), i + 20) local_transaction_service.set_transaction_contents(transaction.tx_hash(), transaction.tx_val()) known_short_id_block = bytes( self.gateway_node.message_converter.block_to_bx_block( ont_block, local_transaction_service, True, self.gateway_node.network.min_tx_age_seconds )[0] ) known_key, known_cipher = symmetric_encrypt(known_short_id_block) known_block_hash = crypto.double_sha256(known_cipher) known_message = BroadcastMessage(Sha256Hash(known_block_hash), self.TEST_NETWORK_NUM, "", BroadcastMessageType.BLOCK, False, bytearray(known_short_id_block)) known_key_message = KeyMessage(Sha256Hash(known_block_hash), self.TEST_NETWORK_NUM, "", known_key) self.sut.msg_broadcast(unknown_message) self.sut.msg_key(unknown_key_message) self.assertEqual(1, len(self.gateway_node.block_queuing_service)) self.assertEqual(True, self.gateway_node.block_queuing_service._blocks_waiting_for_recovery[block_hash]) self.assertEqual(1, len(self.gateway_node.block_recovery_service._block_hash_to_bx_block_hashes)) self.assertNotIn(block_hash, self.gateway_node.blocks_seen.contents) self.sut.msg_broadcast(known_message) self.sut.msg_key(known_key_message) self.gateway_node_sut.msg_get_data(GetDataOntMessage(self.magic, InventoryOntType.MSG_BLOCK.value, block_hash)) self.gateway_node.broadcast.assert_called() self.assertEqual(0, len(self.gateway_node.block_queuing_service)) self.assertEqual(0, len(self.gateway_node.block_recovery_service._block_hash_to_bx_block_hashes)) self.assertIn(block_hash, self.gateway_node.blocks_seen.contents)
def test_get_txs_multiple_sid_assignments(self): block = self.ont_block() transactions = self.ont_transactions(block) # assign short ids that the local connection won't know about until it gets the txs message remote_transaction_service1 = ExtensionTransactionService( MockNode(gateway_helpers.get_gateway_opts(8999)), 0) short_id_mapping1 = {} for i, transaction in enumerate(transactions): remote_transaction_service1.assign_short_id( transaction.tx_hash(), i + 1) remote_transaction_service1.set_transaction_contents( transaction.tx_hash(), transaction.tx()) short_id_mapping1[transaction.tx_hash()] = TransactionInfo( transaction.tx_hash(), transaction.tx(), i + 1) txs_message_1 = TxsMessage([tx for tx in short_id_mapping1.values()]) self.sut.msg_txs(txs_message_1) for transaction_hash, tx_info in short_id_mapping1.items(): transaction_key = self.gateway_node.get_tx_service( ).get_transaction_key(transaction_hash) self.assertEqual( tx_info.short_id, self.gateway_node.get_tx_service().get_short_id_by_key( transaction_key)) stored_hash, stored_content, _ = self.gateway_node.get_tx_service( ).get_transaction(tx_info.short_id) self.assertEqual(transaction_hash, stored_hash) self.assertEqual(tx_info.contents, stored_content) remote_transaction_service2 = ExtensionTransactionService( MockNode(gateway_helpers.get_gateway_opts(8999)), 0) short_id_mapping2 = {} for i, transaction in enumerate(transactions): remote_transaction_service2.assign_short_id( transaction.tx_hash(), i + 101) remote_transaction_service2.set_transaction_contents( transaction.tx_hash(), transaction.tx()) short_id_mapping2[transaction.tx_hash()] = TransactionInfo( transaction.tx_hash(), transaction.tx(), i + 101) txs_message_2 = TxsMessage([tx for tx in short_id_mapping2.values()]) self.sut.msg_txs(txs_message_2) for transaction_hash, tx_info in short_id_mapping2.items(): stored_hash, stored_content, _ = self.gateway_node.get_tx_service( ).get_transaction(tx_info.short_id) self.assertEqual(transaction_hash, stored_hash) self.assertEqual(tx_info.contents, stored_content)
def test_get_txs_block_recovery(self): block: BlockOntMessage = self.ont_block() transactions: List[TxOntMessage] = self.ont_transactions(block) # assign short ids that the local connection won't know about until it gets the txs message remote_transaction_service = ExtensionTransactionService( MockNode(gateway_helpers.get_gateway_opts(8999)), 0) short_id_mapping = {} for i, transaction in enumerate(transactions): tx_hash = transaction.tx_hash() remote_transaction_service.assign_short_id(tx_hash, i + 1) remote_transaction_service.set_transaction_contents( tx_hash, transaction.rawbytes()) short_id_mapping[tx_hash] = TransactionInfo( tx_hash, transaction.rawbytes(), i + 1) bx_block = bytes( self.gateway_node.message_converter.block_to_bx_block( block, remote_transaction_service, True, self.gateway_node.network.min_tx_age_seconds)[0]) self.gateway_node.block_recovery_service.add_block = \ MagicMock(wraps=self.gateway_node.block_recovery_service.add_block) self.gateway_node.broadcast = MagicMock() broadcast_message = BroadcastMessage(block.block_hash(), DEFAULT_NETWORK_NUM, "", BroadcastMessageType.BLOCK, False, bytearray(bx_block)) self.sut.msg_broadcast(broadcast_message) self.gateway_node.block_recovery_service.add_block.assert_called_once() self.assertEqual(1, self.gateway_node.broadcast.call_count) recovery_broadcast = self.gateway_node.broadcast.call_args_list[0] ((gettxs_message, ), recovery_kwargs) = recovery_broadcast self.assertIsInstance(gettxs_message, GetTxsMessage) self.assertIn(ConnectionType.RELAY_TRANSACTION, recovery_kwargs["connection_types"]) txs = [tx for tx in short_id_mapping.values()] txs_message = TxsMessage(txs=txs) self.sut.msg_txs(txs_message) self._assert_block_sent(block)
def init(self, use_extensions: bool): opts = Namespace() opts.use_extensions = use_extensions opts.import_extensions = use_extensions opts.tx_mem_pool_bucket_size = DEFAULT_TX_MEM_POOL_BUCKET_SIZE btc_message_converter = converter_factory.create_btc_message_converter(self.MAGIC, opts=opts) if use_extensions: helpers.set_extensions_parallelism() tx_service = ExtensionTransactionService(MockNode( gateway_helpers.get_gateway_opts(8999)), 0) else: tx_service = TransactionService(MockNode( gateway_helpers.get_gateway_opts(8999)), 0) if self.txns: for idx, txn in enumerate(self.txns): sha = btc_common_utils.get_txid(txn) if idx % 2 == 0: tx_service.assign_short_id(sha, self.short_ids[int(idx/2)]) tx_service.set_transaction_contents(sha, txn) return tx_service, btc_message_converter
class EthMessageConverterTests(AbstractTestCase): MAGIC = 123 def setUp(self): self.eth_message_converter: EthAbstractMessageConverter = converter_factory.create_eth_message_converter( gateway_helpers.get_gateway_opts(8000) ) self.tx_service = ExtensionTransactionService(MockNode(gateway_helpers.get_gateway_opts(8000)), 0) self.test_network_num = 12345 def test_tx_to_bx_tx__success(self): txs = [ mock_eth_messages.get_dummy_transaction(1), mock_eth_messages.get_dummy_transaction(2), mock_eth_messages.get_dummy_transaction(3), ] tx_msg = TransactionsEthProtocolMessage(None, txs) self.assertTrue(tx_msg.rawbytes()) self.validate_tx_to_bx_txs_conversion(tx_msg, txs) def test_tx_to_bx_tx__from_bytes_success(self): txs = [ mock_eth_messages.get_dummy_transaction(1), mock_eth_messages.get_dummy_transaction(2), mock_eth_messages.get_dummy_transaction(3), ] tx_msg = TransactionsEthProtocolMessage(None, txs) tx_msg_bytes = tx_msg.rawbytes() self.assertTrue(tx_msg_bytes) tx_msg_from_bytes = TransactionsEthProtocolMessage(tx_msg_bytes) self.validate_tx_to_bx_txs_conversion(tx_msg_from_bytes, txs) def test_tx_to_bx_tx__filter_low_fee(self): txs = [ mock_eth_messages.get_dummy_transaction(1, 20), mock_eth_messages.get_dummy_transaction(2, 25), mock_eth_messages.get_dummy_transaction(3, 10), ] tx_msg = TransactionsEthProtocolMessage(None, txs) results = self.eth_message_converter.tx_to_bx_txs( tx_msg, self.test_network_num, min_tx_network_fee=15 ) self.assertEqual(2, len(results)) for i, result in enumerate(results): bx_tx_message, tx_hash, tx_contents = result self.assertEqual(txs[i].hash(), tx_hash) def test_tx_to_bx_tx__from_bytes_single_tx_success(self): txs = [ mock_eth_messages.get_dummy_transaction(1), ] tx_msg = TransactionsEthProtocolMessage(None, txs) tx_msg_bytes = tx_msg.rawbytes() self.assertTrue(tx_msg_bytes) tx_msg_from_bytes = TransactionsEthProtocolMessage(tx_msg_bytes) self.validate_tx_to_bx_txs_conversion(tx_msg_from_bytes, txs) def validate_tx_to_bx_txs_conversion(self, tx_msg, txs): bx_tx_msgs = self.eth_message_converter.tx_to_bx_txs(tx_msg, self.test_network_num) self.assertTrue(bx_tx_msgs) self.assertEqual(len(txs), len(bx_tx_msgs)) for tx, (bx_tx_msg, tx_hash, tx_bytes) in zip(txs, bx_tx_msgs): self.assertIsInstance(bx_tx_msg, TxMessage) tx_obj = rlp.decode(bx_tx_msg.tx_val().tobytes(), Transaction) self.assertEqual(tx, tx_obj) def test_bx_tx_to_tx__success(self): tx = mock_eth_messages.get_dummy_transaction(1) tx_bytes = rlp.encode(tx, Transaction) tx_hash_bytes = hashlib.sha256(tx_bytes).digest() tx_hash = Sha256Hash(tx_hash_bytes) bx_tx_message = TxMessage(message_hash=tx_hash, network_num=self.test_network_num, tx_val=tx_bytes) tx_message = self.eth_message_converter.bx_tx_to_tx(bx_tx_message) self.assertIsNotNone(tx_message) self.assertIsInstance(tx_message, TransactionsEthProtocolMessage) self.assertTrue(tx_message.get_transactions()) self.assertEqual(1, len(tx_message.get_transactions())) tx_obj = tx_message.get_transactions()[0] self.assertEqual(tx, tx_obj) @multi_setup() def test_block_to_bx_block__success(self): txs = [] txs_bytes = [] txs_hashes = [] short_ids = [] used_short_ids = [] tx_count = 150 for i in range(1, tx_count): tx = mock_eth_messages.get_dummy_transaction(1) txs.append(tx) tx_bytes = rlp.encode(tx, Transaction) txs_bytes.append(tx_bytes) tx_hash = tx.hash() txs_hashes.append(tx_hash) if i % 2 == 0: self.tx_service.assign_short_id(tx_hash, i) short_ids.append(i) used_short_ids.append(i) else: short_ids.append(0) block = Block( mock_eth_messages.get_dummy_block_header(1), txs, [ mock_eth_messages.get_dummy_block_header(2), mock_eth_messages.get_dummy_block_header(3), ] ) dummy_chain_difficulty = 10 block_msg = NewBlockEthProtocolMessage(None, block, dummy_chain_difficulty) self.assertTrue(block_msg.rawbytes()) internal_new_block_msg = InternalEthBlockInfo.from_new_block_msg(block_msg) bx_block_msg, block_info = self.eth_message_converter.block_to_bx_block( internal_new_block_msg, self.tx_service, True, 0 ) self.assertEqual(len(txs), block_info.txn_count) self.assertEqual(convert.bytes_to_hex(block.header.prev_hash), block_info.prev_block_hash) self.assertEqual(used_short_ids, list(block_info.short_ids)) self.assertTrue(bx_block_msg) self.assertIsInstance(bx_block_msg, memoryview) block_offsets = compact_block_short_ids_serializer.get_bx_block_offsets(bx_block_msg) parsed_short_ids, short_ids_len = compact_block_short_ids_serializer.deserialize_short_ids_from_buffer( bx_block_msg, block_offsets.short_id_offset ) compact_block = rlp.decode( bx_block_msg[block_offsets.block_begin_offset: block_offsets.short_id_offset].tobytes(), CompactBlock ) self.assertTrue(compact_block) self.assertIsInstance(compact_block, CompactBlock) self._assert_values_equal(compact_block.header, block.header) self._assert_values_equal(compact_block.uncles, block.uncles) self.assertEqual(len(compact_block.transactions), len(block.transactions)) short_tx_index = 0 for tx, short_tx, i in zip(block.transactions, compact_block.transactions, range(1, tx_count)): self.assertIsInstance(tx, Transaction) self.assertIsInstance(short_tx, ShortTransaction) if i % 2 == 0: self.assertEqual(0, short_tx.full_transaction) self.assertEqual(short_ids[i - 1], parsed_short_ids[short_tx_index]) self.assertEqual(short_tx.transaction_bytes, bytes()) short_tx_index += 1 else: self.assertEqual(1, short_tx.full_transaction) self.assertEqual(short_tx.transaction_bytes, txs_bytes[i - 1]) self.assertEqual(compact_block.chain_difficulty, block_msg.chain_difficulty) @multi_setup() def test_block_to_bx_block__short_ids_min_time(self): txs = [] txs_bytes = [] txs_hashes = [] short_ids = [] used_short_ids = [] tx_count = 150 for i in range(1, tx_count): tx = mock_eth_messages.get_dummy_transaction(1) txs.append(tx) tx_bytes = rlp.encode(tx, Transaction) txs_bytes.append(tx_bytes) tx_hash = tx.hash() txs_hashes.append(tx_hash) self.tx_service.assign_short_id(tx_hash, i) short_ids.append(i) used_short_ids.append(i) block = Block( mock_eth_messages.get_dummy_block_header(1), txs, [ mock_eth_messages.get_dummy_block_header(2), mock_eth_messages.get_dummy_block_header(3), ] ) dummy_chain_difficulty = 10 block_msg = NewBlockEthProtocolMessage(None, block, dummy_chain_difficulty) self.assertTrue(block_msg.rawbytes()) internal_new_block_msg = InternalEthBlockInfo.from_new_block_msg(block_msg) bx_block_msg, block_info = self.eth_message_converter.block_to_bx_block( internal_new_block_msg, self.tx_service, True, 2 ) self.assertEqual(len(txs), block_info.txn_count) self.assertEqual(convert.bytes_to_hex(block.header.prev_hash), block_info.prev_block_hash) self.assertEqual([], list(block_info.short_ids)) self.assertTrue(bx_block_msg) self.assertIsInstance(bx_block_msg, memoryview) block_offsets = compact_block_short_ids_serializer.get_bx_block_offsets(bx_block_msg) parsed_short_ids, short_ids_len = compact_block_short_ids_serializer.deserialize_short_ids_from_buffer( bx_block_msg, block_offsets.short_id_offset ) compact_block = rlp.decode( bx_block_msg[block_offsets.block_begin_offset: block_offsets.short_id_offset].tobytes(), CompactBlock ) self.assertTrue(compact_block) self.assertIsInstance(compact_block, CompactBlock) self.assertEqual([], parsed_short_ids) self._assert_values_equal(compact_block.header, block.header) self._assert_values_equal(compact_block.uncles, block.uncles) self.assertEqual(len(compact_block.transactions), len(block.transactions)) for tx, short_tx, i in zip(block.transactions, compact_block.transactions, range(1, tx_count)): self.assertIsInstance(tx, Transaction) self.assertIsInstance(short_tx, ShortTransaction) self.assertEqual(1, short_tx.full_transaction) self.assertEqual(short_tx.transaction_bytes, txs_bytes[i - 1]) self.assertEqual(compact_block.chain_difficulty, block_msg.chain_difficulty) @multi_setup() def test_block_to_bx_block__empty_block_success(self): block = Block(mock_eth_messages.get_dummy_block_header(8), [], []) dummy_chain_difficulty = 10 block_msg = NewBlockEthProtocolMessage(None, block, dummy_chain_difficulty) self.assertTrue(block_msg.rawbytes()) internal_new_block_msg = InternalEthBlockInfo.from_new_block_msg(block_msg) bx_block_msg, block_info = self.eth_message_converter.block_to_bx_block( internal_new_block_msg, self.tx_service, True, 0 ) self.assertEqual(0, block_info.txn_count) self.assertEqual(convert.bytes_to_hex(block.header.prev_hash), block_info.prev_block_hash) self.assertTrue(bx_block_msg) self.assertIsInstance(bx_block_msg, memoryview) block_offsets = compact_block_short_ids_serializer.get_bx_block_offsets(bx_block_msg) _, short_ids_len = compact_block_short_ids_serializer.deserialize_short_ids_from_buffer( bx_block_msg, block_offsets.short_id_offset ) compact_block = rlp.decode( bx_block_msg[block_offsets.block_begin_offset: block_offsets.short_id_offset].tobytes(), CompactBlock ) self.assertTrue(compact_block) self.assertIsInstance(compact_block, CompactBlock) self._assert_values_equal(compact_block.header, block.header) self.assertEqual(0, len(compact_block.uncles)) self.assertEqual(0, len(compact_block.transactions)) self.assertEqual(compact_block.chain_difficulty, block_msg.chain_difficulty) @multi_setup() def test_bx_block_to_block__success(self): tx_count = 1500 txs = [] short_txs = [] short_ids = [] for i in range(1, tx_count): tx = mock_eth_messages.get_dummy_transaction(1) txs.append(tx) tx_bytes = rlp.encode(tx, Transaction) tx_hash = hashlib.sha256(tx_bytes).digest() self.tx_service.assign_short_id(tx_hash, i) self.tx_service.set_transaction_contents(tx_hash, tx_bytes) short_tx = ShortTransaction(0, bytes()) short_ids.append(i) short_txs.append(short_tx) dummy_chain_difficulty = 2000000 dummy_block_number = 0 compact_block = CompactBlock(mock_eth_messages.get_dummy_block_header(7), short_txs, [ mock_eth_messages.get_dummy_block_header(2), mock_eth_messages.get_dummy_block_header(3) ], dummy_chain_difficulty, dummy_block_number) compact_block_msg_bytes = bytearray(constants.UL_ULL_SIZE_IN_BYTES) compact_block_msg_bytes.extend(rlp.encode(compact_block, CompactBlock)) short_ids_offset = len(compact_block_msg_bytes) struct.pack_into("<Q", compact_block_msg_bytes, 0, short_ids_offset) compact_block_bytes = compact_block_short_ids_serializer.serialize_short_ids_into_bytes(short_ids) compact_block_msg_bytes.extend(compact_block_bytes) compact_block_hash_bytes = hashlib.sha256(compact_block_msg_bytes).digest() compact_block_hash = Sha256Hash(compact_block_hash_bytes) bx_block_msg = BroadcastMessage(compact_block_hash, self.test_network_num, is_encrypted=True, blob=compact_block_msg_bytes) block_msg, block_info, unknown_tx_sids, unknown_tx_hashes = self.eth_message_converter.bx_block_to_block( bx_block_msg.blob(), self.tx_service) self.assertTrue(block_msg) self.assertIsInstance(block_msg, InternalEthBlockInfo) self.assertEqual(block_msg.block_hash(), block_info.block_hash) new_block_msg = block_msg.to_new_block_msg() block = new_block_msg.get_block() self._assert_values_equal(compact_block.header, block.header) self._assert_values_equal(compact_block.uncles, block.uncles) self.assertEqual(len(compact_block.transactions), len(block.transactions)) for block_tx, i in zip(block.transactions, range(0, tx_count - 1)): self.assertIsInstance(block_tx, Transaction) self._assert_values_equal(block_tx, txs[i]) self.assertEqual(compact_block.chain_difficulty, new_block_msg.chain_difficulty) @multi_setup() def test_bx_block_to_block__full_txs_success(self): tx_count = 150 txs = [] short_txs = [] short_ids = [] for i in range(1, tx_count): tx = mock_eth_messages.get_dummy_transaction(1) txs.append(tx) tx_bytes = rlp.encode(tx, Transaction) if i % 2 == 0: tx_hash = hashlib.sha256(tx_bytes).digest() self.tx_service.assign_short_id(tx_hash, i) self.tx_service.set_transaction_contents(tx_hash, tx_bytes) short_tx = ShortTransaction(0, bytes()) short_txs.append(short_tx) short_ids.append(i) else: short_tx = ShortTransaction(1, tx_bytes) short_txs.append(short_tx) dummy_chain_difficulty = 20 dummy_block_number = 10 compact_block = CompactBlock(mock_eth_messages.get_dummy_block_header(8), short_txs, [ mock_eth_messages.get_dummy_block_header(2), mock_eth_messages.get_dummy_block_header(3) ], dummy_chain_difficulty, dummy_block_number) compact_block_msg_bytes = bytearray(constants.UL_ULL_SIZE_IN_BYTES) compact_block_msg_bytes.extend(rlp.encode(compact_block, CompactBlock)) short_ids_offset = len(compact_block_msg_bytes) struct.pack_into("<Q", compact_block_msg_bytes, 0, short_ids_offset) compact_block_bytes = compact_block_short_ids_serializer.serialize_short_ids_into_bytes(short_ids) compact_block_msg_bytes.extend(compact_block_bytes) compact_block_hash_bytes = hashlib.sha256(compact_block_msg_bytes).digest() compact_block_hash = Sha256Hash(compact_block_hash_bytes) bx_block_msg = BroadcastMessage(compact_block_hash, self.test_network_num, is_encrypted=True, blob=compact_block_msg_bytes) block_msg, block_info, unknown_tx_sids, unknown_tx_hashes = self.eth_message_converter.bx_block_to_block( bx_block_msg.blob(), self.tx_service) self.assertTrue(block_msg) self.assertIsInstance(block_msg, InternalEthBlockInfo) new_block_msg = block_msg.to_new_block_msg() block = new_block_msg.get_block() self._assert_values_equal(compact_block.header, block.header) self._assert_values_equal(compact_block.uncles, block.uncles) self.assertEqual(len(compact_block.transactions), len(block.transactions)) for block_tx, i in zip(block.transactions, range(0, tx_count - 1)): self.assertIsInstance(block_tx, Transaction) self._assert_values_equal(block_tx, txs[i]) self.assertEqual(compact_block.chain_difficulty, new_block_msg.chain_difficulty) @multi_setup() def test_block_to_bx_block_then_bx_block_to_block__success(self): txs = [] txs_bytes = [] txs_hashes = [] short_ids = [] tx_count = 150 for i in range(1, tx_count): tx = mock_eth_messages.get_dummy_transaction(i) txs.append(tx) tx_bytes = rlp.encode(tx, Transaction) txs_bytes.append(tx_bytes) tx_hash = tx.hash() txs_hashes.append(tx_hash) self.tx_service.assign_short_id(tx_hash, i) self.tx_service.set_transaction_contents(tx_hash, tx_bytes) short_ids.append(i) block = Block(mock_eth_messages.get_dummy_block_header(100), txs, [mock_eth_messages.get_dummy_block_header(2)]) dummy_chain_difficulty = 40000000 block_msg = NewBlockEthProtocolMessage(None, block, dummy_chain_difficulty) block_msg_bytes = block_msg.rawbytes() self.assertTrue(block_msg_bytes) internal_new_block_msg = InternalEthBlockInfo.from_new_block_msg(block_msg) bx_block_msg, block_info = self.eth_message_converter.block_to_bx_block( internal_new_block_msg, self.tx_service, True, 0 ) self.assertIsNotNone(bx_block_msg) self.assertEqual(len(txs), block_info.txn_count) self.assertEqual(convert.bytes_to_hex(block.header.prev_hash), block_info.prev_block_hash) converted_block_msg, _, _, _ = self.eth_message_converter.bx_block_to_block(bx_block_msg, self.tx_service) self.assertIsNotNone(converted_block_msg) converted_new_block_msg = converted_block_msg.to_new_block_msg() converted_block_msg_bytes = converted_new_block_msg.rawbytes() self.assertEqual(len(converted_block_msg_bytes), len(block_msg_bytes)) self.assertEqual(converted_block_msg_bytes, block_msg_bytes) @multi_setup() def test_block_to_bx_block__no_compressed_block(self): txs = [] txs_bytes = [] txs_hashes = [] short_ids = [] used_short_ids = [] tx_count = 150 for i in range(1, tx_count): tx = mock_eth_messages.get_dummy_transaction(1) txs.append(tx) tx_bytes = rlp.encode(tx, Transaction) txs_bytes.append(tx_bytes) tx_hash = tx.hash() txs_hashes.append(tx_hash) short_ids.append(0) block = Block( mock_eth_messages.get_dummy_block_header(1), txs, [ mock_eth_messages.get_dummy_block_header(2), mock_eth_messages.get_dummy_block_header(3), ] ) dummy_chain_difficulty = 10 block_msg = NewBlockEthProtocolMessage(None, block, dummy_chain_difficulty) self.assertTrue(block_msg.rawbytes()) internal_new_block_msg = InternalEthBlockInfo.from_new_block_msg(block_msg) bx_block_msg, block_info = self.eth_message_converter.block_to_bx_block( internal_new_block_msg, self.tx_service, False, 0 ) self.assertTrue(len(bx_block_msg) >= len(internal_new_block_msg.rawbytes())) self.assertEqual(len(txs), block_info.txn_count) self.assertEqual(convert.bytes_to_hex(block.header.prev_hash), block_info.prev_block_hash) self.assertEqual(used_short_ids, list(block_info.short_ids)) self.assertTrue(bx_block_msg) self.assertIsInstance(bx_block_msg, memoryview) block_offsets = compact_block_short_ids_serializer.get_bx_block_offsets(bx_block_msg) compact_block = rlp.decode( bx_block_msg[block_offsets.block_begin_offset: block_offsets.short_id_offset].tobytes(), CompactBlock ) self.assertTrue(compact_block) self.assertIsInstance(compact_block, CompactBlock) self._assert_values_equal(compact_block.header, block.header) self._assert_values_equal(compact_block.uncles, block.uncles) self.assertEqual(len(compact_block.transactions), len(block.transactions)) for tx, short_tx, i in zip(block.transactions, compact_block.transactions, range(1, tx_count)): self.assertIsInstance(tx, Transaction) self.assertIsInstance(short_tx, ShortTransaction) self.assertEqual(1, short_tx.full_transaction) self.assertEqual(short_tx.transaction_bytes, txs_bytes[i - 1]) self.assertEqual(compact_block.chain_difficulty, block_msg.chain_difficulty) converted_block_msg, _, _, _ = self.eth_message_converter.bx_block_to_block(bx_block_msg, self.tx_service) self.assertIsNotNone(converted_block_msg) def _assert_values_equal(self, actual_value, expected_value, ): if isinstance(expected_value, collections.Iterable) and \ not isinstance(expected_value, bytearray) and \ not isinstance(expected_value, str): for actual_item_value, expected_item_value in zip(actual_value, expected_value): self._assert_values_equal(actual_item_value, expected_item_value) elif isinstance(expected_value, rlp.Serializable): for serializer_field in expected_value.fields: serializer_field_name, _ = serializer_field actual_field_value = getattr(actual_value, serializer_field_name) expected_field_value = getattr(expected_value, serializer_field_name) self._assert_values_equal(actual_field_value, expected_field_value) else: self.assertEqual(actual_value, expected_value) def init(self, use_extensions: bool): opts = Namespace() opts.use_extensions = use_extensions opts.enable_eth_extensions = use_extensions # TODO remove opts.import_extensions = use_extensions opts.tx_mem_pool_bucket_size = DEFAULT_TX_MEM_POOL_BUCKET_SIZE eth_message_converter = converter_factory.create_eth_message_converter(opts=opts) if use_extensions: helpers.set_extensions_parallelism() tx_service = ExtensionTransactionService(MockNode( gateway_helpers.get_gateway_opts(8999)), 0) else: tx_service = TransactionService(MockNode( gateway_helpers.get_gateway_opts(8999)), 0) return tx_service, eth_message_converter