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)
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
    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
예제 #7
0
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