Esempio n. 1
0
class EthNodeConnectionProtocolTest(AbstractTestCase):
    def setUp(self) -> None:
        pub_key = "a04f30a45aae413d0ca0f219b4dcb7049857bc3f91a6351288cce603a2c9646294a02b987bf6586b370b2c22d74662355677007a14238bb037aedf41c2d08866"
        node_ssl_service = MockNodeSSLService(EthGatewayNode.NODE_TYPE, MagicMock())
        opts = gateway_helpers.get_gateway_opts(
            8000,
            include_default_eth_args=True,
            blockchain_protocol=BlockchainProtocol.ETHEREUM.name,
            blockchain_network_num=5,
            pub_key=pub_key,
        )
        self.node = EthGatewayNode(opts, node_ssl_service)
        self.enqueued_messages = []
        self.broadcast_to_node_messages = []
        self.broadcast_messages = []
        self.node.opts.has_fully_updated_tx_service = True
        self.node.init_live_feeds()

        self.connection = helpers.create_connection(
            EthNodeConnection, self.node, opts, port=opts.blockchain_port
        )

        gateway_helpers.add_blockchain_peer(self.node, self.connection)
        self.block_queuing_service = self.node.block_queuing_service_manager.get_designated_block_queuing_service()

        self.connection.on_connection_established()
        self.node.node_conn = self.connection
        gateway_bdn_performance_stats_service.set_node(self.node)

        def mocked_enqueue_msg(msg, prepend=False):
            self.enqueued_messages.append(msg)

        self.connection.enqueue_msg = mocked_enqueue_msg

        def mocked_broadcast(msg, broadcasting_conn=None, prepend_to_queue=False, connection_types=None):
            if connection_types is None:
                connection_types = [ConnectionType.RELAY_ALL]
            if len(connection_types) == 1 and connection_types[0] == ConnectionType.BLOCKCHAIN_NODE:
                self.broadcast_to_node_messages.append(msg)
            else:
                self.broadcast_messages.append(msg)

        self.node.broadcast = mocked_broadcast

        self.cleanup_service = self.node.block_cleanup_service
        self.node.block_processing_service.queue_block_for_processing = MagicMock()

        self.sut = self.connection.connection_protocol
        self.sut._waiting_checkpoint_headers_request = False
        self.node.opts.ws = True
        self.node.publish_block = MagicMock()

    def test_request_block_bodies(self):
        self.cleanup_service.clean_block_transactions_by_block_components = (
            MagicMock()
        )

        block_hashes_sets = [
            [helpers.generate_object_hash(), helpers.generate_object_hash()],
            [helpers.generate_object_hash()],
            [helpers.generate_object_hash()],
        ]

        block_bodies_messages = [
            BlockBodiesEthProtocolMessage(
                None,
                [
                    mock_eth_messages.get_dummy_transient_block_body(1),
                    mock_eth_messages.get_dummy_transient_block_body(2),
                ],
            ),
            BlockBodiesEthProtocolMessage(
                None, [mock_eth_messages.get_dummy_transient_block_body(3)]
            ),
            BlockBodiesEthProtocolMessage(
                None, [mock_eth_messages.get_dummy_transient_block_body(4)]
            ),
        ]

        transactions = [
            [
                [
                    tx.hash()
                    for tx in BlockBodiesEthProtocolMessage.from_body_bytes(
                        block_body_bytes
                    )
                    .get_blocks()[0]
                    .transactions
                ]
                for block_body_bytes in msg.get_block_bodies_bytes()
            ]
            for msg in block_bodies_messages
        ]

        for block_bodies_message in block_bodies_messages:
            block_bodies_message.serialize()

        for block_hashes_set in block_hashes_sets:
            for block_hash in block_hashes_set:
                self.node.block_cleanup_service._block_hash_marked_for_cleanup.add(
                    block_hash
                )
            self.sut.request_block_body(block_hashes_set)

        self.sut.msg_block_bodies(block_bodies_messages[0])
        call_args_list = (
            self.cleanup_service.clean_block_transactions_by_block_components.call_args_list
        )

        first_call = call_args_list[0]
        first_kwargs = first_call[1]
        self.assertEqual(
            first_kwargs["transaction_service"], self.node.get_tx_service()
        )
        self.assertEqual(first_kwargs["block_hash"], block_hashes_sets[0][0])
        self.assertEqual(
            list(first_kwargs["transactions_list"]), transactions[0][0]
        )

        second_call = call_args_list[1]
        second_kwargs = second_call[1]
        self.assertEqual(
            second_kwargs["transaction_service"], self.node.get_tx_service()
        )
        self.assertEqual(second_kwargs["block_hash"], block_hashes_sets[0][1])
        self.assertEqual(
            list(second_kwargs["transactions_list"]), transactions[0][1]
        )

        self.cleanup_service.clean_block_transactions_by_block_components.reset_mock()
        self.sut.msg_block_bodies(block_bodies_messages[1])
        call_args_list = (
            self.cleanup_service.clean_block_transactions_by_block_components.call_args_list
        )

        first_call = call_args_list[0]
        first_kwargs = first_call[1]
        self.assertEqual(
            first_kwargs["transaction_service"], self.node.get_tx_service()
        )
        self.assertEqual(first_kwargs["block_hash"], block_hashes_sets[1][0])
        self.assertEqual(
            list(first_kwargs["transactions_list"]), transactions[1][0]
        )

        self.cleanup_service.clean_block_transactions_by_block_components.reset_mock()
        self.sut.msg_block_bodies(block_bodies_messages[2])
        call_args_list = (
            self.cleanup_service.clean_block_transactions_by_block_components.call_args_list
        )

        first_call = call_args_list[0]
        first_kwargs = first_call[1]
        self.assertEqual(
            first_kwargs["transaction_service"], self.node.get_tx_service()
        )
        self.assertEqual(first_kwargs["block_hash"], block_hashes_sets[2][0])
        self.assertEqual(
            list(first_kwargs["transactions_list"]), transactions[2][0]
        )

    def test_msg_get_block_headers_unknown(self):
        block_hash = helpers.generate_hash()
        self.sut.msg_proxy_request = MagicMock()
        message = GetBlockHeadersEthProtocolMessage(None, block_hash, 1, 0, 0)

        self.sut.msg_get_block_headers(message)
        self.sut.msg_proxy_request.assert_called_once()

    def test_msg_get_block_headers_known_single(self):
        header = mock_eth_messages.get_dummy_block_header(12)
        block = mock_eth_messages.get_dummy_block(1, header)
        raw_hash = header.hash()
        block_hash = header.hash_object()
        new_block_message = NewBlockEthProtocolMessage(None, block, 10)
        eth_block_info = InternalEthBlockInfo.from_new_block_msg(
            new_block_message
        )

        self.node.block_queuing_service_manager.push(block_hash, eth_block_info)
        self.enqueued_messages.clear()

        self.sut.msg_proxy_request = MagicMock()
        message = GetBlockHeadersEthProtocolMessage(None, raw_hash, 1, 0, 0)
        self.sut.msg_get_block_headers(message)

        self.sut.msg_proxy_request.assert_not_called()
        self.assertEqual(1, len(self.enqueued_messages))

        headers_sent = self.enqueued_messages[0]
        self.assertIsInstance(headers_sent, BlockHeadersEthProtocolMessage)
        self.assertEqual(1, len(headers_sent.get_block_headers()))
        self.assertEqual(
            block_hash, headers_sent.get_block_headers()[0].hash_object()
        )

        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash, eth_block_info
        )
        self.sut.msg_get_block_headers(message)
        self.sut.msg_proxy_request.assert_not_called()
        self.assertEqual(2, len(self.enqueued_messages))

    def test_msg_get_block_headers_block_number(self):
        block_number = 123456
        header = mock_eth_messages.get_dummy_block_header(
            12, block_number=block_number
        )
        block = mock_eth_messages.get_dummy_block(1, header)
        block_hash = header.hash_object()
        new_block_message = NewBlockEthProtocolMessage(None, block, 10)
        eth_block_info = InternalEthBlockInfo.from_new_block_msg(
            new_block_message
        )

        self.node.block_queuing_service_manager.push(block_hash, eth_block_info)
        self.enqueued_messages.clear()

        self.sut.msg_proxy_request = MagicMock()

        block_number_bytes = struct.pack(">I", block_number)
        message = GetBlockHeadersEthProtocolMessage(
            None, block_number_bytes, 1, 0, 0
        )

        self.sut.msg_get_block_headers(message)
        self.sut.msg_proxy_request.assert_not_called()
        self.assertEqual(1, len(self.enqueued_messages))

        headers_sent = self.enqueued_messages[0]
        self.assertIsInstance(headers_sent, BlockHeadersEthProtocolMessage)
        self.assertEqual(1, len(headers_sent.get_block_headers()))
        self.assertEqual(
            block_hash, headers_sent.get_block_headers()[0].hash_object()
        )

    def test_msg_get_block_headers_known_many(self):
        self.node.opts.max_block_interval_s = 0

        block_hashes = []
        block_hash = None
        for i in range(20):
            block_message = InternalEthBlockInfo.from_new_block_msg(
                mock_eth_messages.new_block_eth_protocol_message(
                    i, i + 1000, block_hash
                )
            )
            block_hash = block_message.block_hash()
            block_hashes.append(block_hash)
            self.node.block_queuing_service_manager.push(block_hash, block_message)
        self.block_queuing_service.best_sent_block = (1019, block_hashes[-1], 0)

        self.enqueued_messages.clear()

        self.sut.msg_proxy_request = MagicMock()
        message = GetBlockHeadersEthProtocolMessage(
            None, block_hashes[10].binary, 10, 0, 0
        )
        self.sut.msg_get_block_headers(message)

        self.sut.msg_proxy_request.assert_not_called()
        self.assertEqual(1, len(self.enqueued_messages))

        headers_sent = self.enqueued_messages[0]
        self.assertIsInstance(headers_sent, BlockHeadersEthProtocolMessage)
        self.assertEqual(10, len(headers_sent.get_block_headers()))

        for i in range(10):
            self.assertEqual(
                block_hashes[i + 10],
                headers_sent.get_block_headers()[i].hash_object(),
            )

    def test_msg_get_block_headers_fork(self):
        self.node.opts.max_block_interval_s = 0

        block_hashes = []
        for i in range(20):
            block_message = InternalEthBlockInfo.from_new_block_msg(
                mock_eth_messages.new_block_eth_protocol_message(i, i + 1000)
            )
            block_hash = block_message.block_hash()
            block_hashes.append(block_hash)
            self.node.block_queuing_service_manager.push(block_hash, block_message)

        # create fork
        block_message = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(34, 1017)
        )
        block_hash = block_message.block_hash()
        block_hashes.append(block_hash)
        self.node.block_queuing_service_manager.push(block_hash, block_message)

        self.enqueued_messages.clear()

        self.sut.msg_proxy_request = MagicMock()
        message = GetBlockHeadersEthProtocolMessage(
            None, block_hashes[-1].binary, 10, 0, 1
        )
        self.sut.msg_get_block_headers(message)

        self.sut.msg_proxy_request.assert_called_once()
        self.assertEqual(0, len(self.enqueued_messages))

    def test_msg_get_block_headers_missing_block(self):
        self.node.opts.max_block_interval_s = 0

        block_hashes = []
        for i in (j for j in range(20) if j != 17):
            block_message = InternalEthBlockInfo.from_new_block_msg(
                mock_eth_messages.new_block_eth_protocol_message(i, i + 1000)
            )
            block_hash = block_message.block_hash()
            block_hashes.append(block_hash)
            self.node.block_queuing_service_manager.push(block_hash, block_message)

        self.enqueued_messages.clear()

        self.sut.msg_proxy_request = MagicMock()
        message = GetBlockHeadersEthProtocolMessage(
            None, block_hashes[-1].binary, 10, 0, 1
        )
        self.sut.msg_get_block_headers(message)

        self.sut.msg_proxy_request.assert_called_once()
        self.assertEqual(0, len(self.enqueued_messages))

    def test_msg_get_block_headers_future_block(self):
        self.node.opts.max_block_interval_s = 0

        block_hashes = []
        block_heights = []
        for i in range(20):
            block_message = InternalEthBlockInfo.from_new_block_msg(
                mock_eth_messages.new_block_eth_protocol_message(i, i + 1000)
            )
            block_hash = block_message.block_hash()
            block_heights.append(block_message.block_number())
            block_hashes.append(block_hash)
            self.node.block_queuing_service_manager.push(block_hash, block_message)

        self.enqueued_messages.clear()
        self.sut.msg_proxy_request = MagicMock()

        block_height_bytes = block_heights[-1] + 4
        block_height_bytes = block_height_bytes.to_bytes(8, "big")

        message = GetBlockHeadersEthProtocolMessage(
            None, block_height_bytes, 1, 0, 0
        )
        self.sut.msg_get_block_headers(message)

        self.sut.msg_proxy_request.assert_not_called()
        self.assertEqual(1, len(self.enqueued_messages))
        headers_sent = self.enqueued_messages[0]
        self.assertIsInstance(headers_sent, BlockHeadersEthProtocolMessage)
        self.assertEqual(0, len(headers_sent.get_block_headers()))

    def test_msg_block_adds_headers_and_bodies(self):
        self.node.opts.max_block_interval_s = 0
        self.sut.is_valid_block_timestamp = MagicMock(return_value=True)

        block_hashes = []
        block_messages = []
        block_hash = None
        for i in range(20):
            block_message = InternalEthBlockInfo.from_new_block_msg(
                mock_eth_messages.new_block_eth_protocol_message(i, i + 1000, block_hash)
            )
            block_hash = block_message.block_hash()
            block_hashes.append(block_hash)
            block_messages.append(block_message)

        # push all blocks, except for # 17
        for i in (j for j in range(20) if j != 17):
            self.node.block_queuing_service_manager.push(
                block_hashes[i], block_messages[i]
            )
            self.block_queuing_service.remove_from_queue(block_hashes[i])
        self.block_queuing_service.best_sent_block = (1019, block_hashes[-1], 0)

        self.enqueued_messages.clear()
        self.sut.msg_proxy_request = MagicMock()
        message = GetBlockHeadersEthProtocolMessage(
            None, block_hashes[10].binary, 10, 0, 0
        )
        self.sut.msg_get_block_headers(message)

        self.sut.msg_proxy_request.assert_called_once()
        self.sut.msg_proxy_request.reset_mock()

        self.sut.msg_block(block_messages[17].to_new_block_msg())
        self.node.publish_block.assert_called()

        self.sut.msg_get_block_headers(message)
        self.sut.msg_proxy_request.assert_not_called()
        self.assertEqual(1, len(self.enqueued_messages))

        headers_sent = self.enqueued_messages[0]
        self.assertIsInstance(headers_sent, BlockHeadersEthProtocolMessage)
        self.assertEqual(10, len(headers_sent.get_block_headers()))

        for i in range(10):
            self.assertEqual(
                block_hashes[i + 10],
                headers_sent.get_block_headers()[i].hash_object(),
            )

    def test_msg_tx(self):
        self.node.feed_manager.publish_to_feed = MagicMock()
        self.node.opts.ws = True
        self.node.opts.transaction_validation = False

        transaction = mock_eth_messages.get_dummy_transaction(1)
        transaction_hash = transaction.hash()
        transaction_contents = transaction.contents()
        messages = TransactionsEthProtocolMessage(None, [transaction])

        self.sut.msg_tx(messages)

        # published to both feeds
        self.node.feed_manager.publish_to_feed.assert_has_calls(
            [
                call(
                    FeedKey(EthNewTransactionFeed.NAME),
                    EthRawTransaction(
                        transaction_hash, transaction_contents, FeedSource.BLOCKCHAIN_SOCKET, local_region=True
                    )
                ),
                call(
                    FeedKey(EthPendingTransactionFeed.NAME),
                    EthRawTransaction(
                        transaction_hash, transaction_contents, FeedSource.BLOCKCHAIN_SOCKET, local_region=True
                    )
                ),
            ]
        )

        # broadcast transactions
        self.assertEqual(1, len(self.broadcast_messages))
        self.assertEqual(1, len(self.broadcast_to_node_messages))

    def test_handle_tx_with_an_invalid_signature(self):
        tx_bytes = \
            b"\xf8k" \
            b"!" \
            b"\x85\x0b\xdf\xd6>\x00" \
            b"\x82R\x08\x94" \
            b"\xf8\x04O\xf8$\xc2\xdc\xe1t\xb4\xee\x9f\x95\x8c*s\x84\x83\x18\x9e" \
            b"\x87\t<\xaf\xacj\x80\x00\x80" \
            b"!" \
            b"\xa0-\xbf,\xa9+\xae\xabJ\x03\xcd\xfa\xe3<\xbf$\x00e\xe2N|\xc9\xf7\xe2\xa9\x9c>\xdfn\x0cO\xc0\x16" \
            b"\xa0)\x11K=;\x96X}a\xd5\x00\x06eSz\xd1,\xe4>\xa1\x8c\xf8\x7f>\x0e:\xd1\xcd\x00?'?"

        result = transaction_validation.validate_transaction(
            tx_bytes,
            BlockchainProtocol(self.node.network.protocol.lower()),
            self.node.get_network_min_transaction_fee()
        )

        self.assertEqual(TxValidationStatus.INVALID_SIGNATURE, result)

    def test_handle_tx_with_an_invalid_format(self):
        tx_bytes = \
            b"\xf8k" \
            b"!" \
            b"\x85\x0b\xdf\xd6>\x00\x82R\x08\x94\xf8\x04O\xf8$\xc2\xdc\xe1t\xb4\xee\x9f\x95\x8c*s\x84\x83" \
            b"\x18\x9e\x87\t<\xaf\xacj\x80\x00\x80&\xa0-\xbf,\xa9+\xae\xabJ\x03\xcd\xfa\xe3<\xbf$\x00e\xe2N|\xc9" \
            b"\xf7\xe2\xa9\x9c>\xdfn\x0cO\xc0\x16"

        result = transaction_validation.validate_transaction(
            tx_bytes,
            BlockchainProtocol(self.node.network.protocol.lower()),
            self.node.get_network_min_transaction_fee()
        )

        self.assertEqual(TxValidationStatus.INVALID_FORMAT, result)

    def test_handle_tx_with_low_fee(self):
        self.node.feed_manager.publish_to_feed = MagicMock()
        self.node.opts.ws = False

        tx_bytes = \
            b"\xf8k" \
            b"!" \
            b"\x85\x0b\xdf\xd6>\x00\x82R\x08\x94\xf8\x04O\xf8$\xc2\xdc\xe1t\xb4\xee\x9f\x95\x8c*s\x84\x83" \
            b"\x18\x9e\x87\t<\xaf\xacj\x80\x00\x80" \
            b"&" \
            b"\xa0" \
            b"-\xbf,\xa9+\xae\xabJ\x03\xcd\xfa\xe3<\xbf$\x00e\xe2N|\xc9\xf7\xe2\xa9\x9c>\xdfn\x0cO\xc0\x16" \
            b"\xa0)\x11K=;\x96X}a\xd5\x00\x06eSz\xd1,\xe4>\xa1\x8c\xf8\x7f>\x0e:\xd1\xcd\x00?'\x15"

        result = transaction_validation.validate_transaction(
            tx_bytes,
            BlockchainProtocol(self.node.network.protocol.lower()),
            510000000000
        )
        self.assertEqual(TxValidationStatus.LOW_FEE, result)

    def test_complete_header_body_fetch(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.sut.msg_block_headers(header_message)
        self.sut.msg_block_bodies(bodies_message)

        self.node.block_queuing_service_manager.push.assert_called_once()
        self.node.on_block_seen_by_blockchain_node.assert_called_once()
        self.node.block_processing_service.queue_block_for_processing.assert_called_once()

    def test_complete_header_body_fetch_already_seen(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()
        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.blocks_seen.add(block_hash)
        self.sut.msg_block_headers(header_message)
        self.sut.msg_block_bodies(bodies_message)

        self.node.block_queuing_service_manager.push.assert_not_called()
        self.node.on_block_seen_by_blockchain_node.assert_called_once()
        self.node.block_processing_service.queue_block_for_processing.assert_not_called()

    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 test_header_body_fetch_abort_from_bdn(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)])
        internal_block_info = InternalEthBlockInfo.from_new_block_msg(NewBlockEthProtocolMessage(None, block, 1))

        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.node.on_block_received_from_bdn(block_hash, internal_block_info)

        self.sut.msg_block_headers(header_message)
        self.sut.msg_block_bodies(bodies_message)

        self.node.block_processing_service.queue_block_for_processing.assert_not_called()
Esempio n. 2
0
class GatewaySubscribeRpcRequestTest(AbstractTestCase):
    @async_test
    async def setUp(self) -> None:
        pub_key = "a04f30a45aae413d0ca0f219b4dcb7049857bc3f91a6351288cce603a2c9646294a02b987bf6586b370b2c22d74662355677007a14238bb037aedf41c2d08866"
        opts = gateway_helpers.get_gateway_opts(
            8000,
            include_default_eth_args=True,
            pub_key=pub_key,
        )
        if opts.use_extensions:
            helpers.set_extensions_parallelism()
        node_ssl_service = MockNodeSSLService(EthGatewayNode.NODE_TYPE,
                                              MagicMock())
        self.node = EthGatewayNode(opts, node_ssl_service)
        self.feed_manager = FeedManager(self.node)
        self.node.feed_manager = self.feed_manager
        self.rpc = SubscriptionRpcHandler(self.node, self.feed_manager,
                                          Case.SNAKE)
        self.feed_name = NewTransactionFeed.NAME
        self.node.init_live_feeds()

        self.feed_service_model = FeedServiceModelBase(
            allow_filtering=True, available_fields=["all"])
        self.base_feed_service_model = BdnFeedServiceModelConfigBase(
            expire_date="2999-01-01", feed=self.feed_service_model)
        self.node.account_model = BdnAccountModelBase(
            account_id="account_id",
            certificate="",
            logical_account_name="test",
            new_transaction_streaming=self.base_feed_service_model,
        )

    @async_test
    async def tearDown(self) -> None:
        pass

    @async_test
    async def test_subscribe_to_feed_with_no_includes_specified(self):
        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            [self.feed_name, {}],
        )

        rpc_handler = self.rpc.get_request_handler(subscribe_request1)
        result = await rpc_handler.process_request()
        self.assertTrue(result)

    @async_test
    async def test_subscribe_to_feed_with_all_available_fields(self):
        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            [
                self.feed_name, {
                    "include": ["tx_hash", "tx_contents.gas_price"]
                }
            ],
        )

        rpc_handler = self.rpc.get_request_handler(subscribe_request1)
        result = await rpc_handler.process_request()
        self.assertTrue(result)

    @async_test
    async def test_subscribe_to_feed_with_specific_available_field(self):
        feed_service_model = FeedServiceModelBase(
            allow_filtering=True, available_fields=["tx_contents.nonce"])
        base_feed_service_model = BdnFeedServiceModelConfigBase(
            expire_date="2999-01-01", feed=feed_service_model)
        self.node.account_model.new_transaction_streaming = base_feed_service_model

        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            [self.feed_name, {
                "include": ["tx_contents.nonce"]
            }],
        )

        rpc_handler = self.rpc.get_request_handler(subscribe_request1)
        result = await rpc_handler.process_request()
        self.assertTrue(result)

    @async_test
    async def test_subscribe_to_feed_with_unavailable_field(self):
        feed_service_model = FeedServiceModelBase(
            allow_filtering=True,
            available_fields=["tx_hash", "tx_contents.nonce"])
        base_feed_service_model = BdnFeedServiceModelConfigBase(
            expire_date="2999-01-01", feed=feed_service_model)
        self.node.account_model.new_transaction_streaming = base_feed_service_model

        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            [
                self.feed_name, {
                    "include": ["tx_hash", "tx_contents.gas_price"]
                }
            ],
        )

        with self.assertRaises(RpcInvalidParams):
            rpc_handler = self.rpc.get_request_handler(subscribe_request1)
            await rpc_handler.process_request()

    @async_test
    async def test_subscribe_to_feed_with_feed_not_set_in_account(self):
        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            ["pendingTxs", {}],
        )

        with self.assertRaises(RpcAccountIdError):
            rpc_handler = self.rpc.get_request_handler(subscribe_request1)
            await rpc_handler.process_request()

    @async_test
    async def test_subscribe_to_feed_no_feed_service(self):
        # allow feed if service is not defined (old account)
        self.node.account_model.new_transaction_streaming = BdnFeedServiceModelConfigBase(
            expire_date="2999-01-01")

        subscribe_request1 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            [self.feed_name, {}],
        )
        subscribe_request2 = BxJsonRpcRequest(
            "1",
            RpcRequestType.SUBSCRIBE,
            [
                self.feed_name, {
                    "include": ["tx_hash", "tx_contents.gas_price"]
                }
            ],
        )

        rpc_handler = self.rpc.get_request_handler(subscribe_request1)
        result = await rpc_handler.process_request()
        self.assertTrue(result)
        rpc_handler = self.rpc.get_request_handler(subscribe_request2)
        result = await rpc_handler.process_request()
        self.assertTrue(result)