class OntBlockQueuingServiceTest(AbstractTestCase):
    def setUp(self):
        self.node = MockGatewayNode(
            gateway_helpers.get_gateway_opts(8000, max_block_interval=0))

        self.node_connection = Mock()
        self.node_connection.is_active = MagicMock(return_value=True)
        self.node.set_known_total_difficulty = MagicMock()

        self.node.node_conn = self.node_connection

        self.block_queuing_service = OntBlockQueuingService(self.node)

        self.block_hashes = []
        self.block_msg = self._get_sample_block()
        self.block_queuing_service.store_block_data(
            self.block_msg.block_hash(), self.block_msg)

    def test_get_recent_blocks(self):
        recent_blocks = list(
            self.block_queuing_service.iterate_recent_block_hashes(10))
        self.assertEqual(len(recent_blocks), 1)
        self.assertEqual(recent_blocks[0], self.block_msg.block_hash())

    def _get_sample_block(self, file_path=__file__):
        root_dir = os.path.dirname(
            os.path.dirname(os.path.dirname(os.path.abspath(file_path))))
        with open(os.path.join(root_dir,
                               "ont_sample_block.txt")) as sample_file:
            ont_block = sample_file.read().strip("\n")
        buf = bytearray(convert.hex_to_bytes(ont_block))
        parsed_block = BlockOntMessage(buf=buf)
        return parsed_block

    def test_tracked_block_cleanup(self):
        self.node.block_queuing_service = self.block_queuing_service
        tx_service = self.node.get_tx_service()
        for block_hash in self.block_queuing_service.iterate_recent_block_hashes(
                10):
            tx_service.track_seen_short_ids(block_hash, [])
        self.node._tracked_block_cleanup()
Exemplo n.º 2
0
class EthBlockQueuingServiceFetchingTest(AbstractTestCase):
    def setUp(self):
        self.node = MockGatewayNode(
            gateway_helpers.get_gateway_opts(8000, max_block_interval_s=0))
        self.node.block_parts_storage = ExpiringDict(
            self.node.alarm_queue,
            gateway_constants.MAX_BLOCK_CACHE_TIME_S,
            "eth_block_queue_parts",
        )

        self.node_connection = Mock()
        self.node_connection.is_active = MagicMock(return_value=True)
        self.node.set_known_total_difficulty = MagicMock()

        self.node_conn = self.node_connection

        self.block_queuing_service = EthBlockQueuingService(
            self.node, self.node_conn)
        self.node.block_queuing_service_manager.add_block_queuing_service(
            self.node_conn, self.block_queuing_service)
        self.node_conn.enqueue_msg = MagicMock()

        self.block_hashes = []
        self.block_messages = []
        self.block_headers = []
        self.block_bodies = []

        # block numbers: 1000-1019
        prev_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, prev_block_hash=prev_block_hash))
            block_hash = block_message.block_hash()
            self.block_hashes.append(block_hash)
            self.block_messages.append(block_message)

            block_parts = block_message.to_new_block_parts()
            self.block_headers.append(
                BlockHeadersEthProtocolMessage.from_header_bytes(
                    block_parts.block_header_bytes).get_block_headers()[0])
            self.block_bodies.append(
                BlockBodiesEthProtocolMessage.from_body_bytes(
                    block_parts.block_body_bytes).get_blocks()[0])

            self.node.block_queuing_service_manager.push(
                block_hash, block_message)
            prev_block_hash = block_hash

        for block_hash in self.block_hashes:
            self.block_queuing_service.remove_from_queue(block_hash)

        self.block_queuing_service.best_sent_block = (1019,
                                                      self.block_hashes[-1],
                                                      time.time())
        self.block_queuing_service.best_accepted_block = (
            1019, self.block_hashes[-1])

    def test_get_block_hashes_from_hash(self):
        # request: start: 1019, count: 1
        # result: 1019
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_hash(
            self.block_hashes[19], 1, 0, False)
        self.assertTrue(success)
        self.assertEqual(1, len(hashes))
        self.assertEqual(self.block_hashes[19], hashes[0])

        # request: start: 1010, count: 10
        # result: 1010, 1011, .. 1019
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_hash(
            self.block_hashes[10], 10, 0, False)
        self.assertTrue(success)
        self.assertEqual(10, len(hashes))
        for i, block_hash in enumerate(hashes):
            self.assertEqual(self.block_hashes[i + 10], hashes[i])

        # request: start: 1010, count: 2, skip: 5
        # result: 1010, 1016
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_hash(
            self.block_hashes[10], 2, 5, False)
        self.assertTrue(success)
        self.assertEqual(2, len(hashes))
        self.assertEqual(self.block_hashes[10], hashes[0])
        self.assertEqual(self.block_hashes[16], hashes[1])

        # request: start: 1010, count: 2, skip: 5, reverse = True
        # result: 1010, 1004
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_hash(
            self.block_hashes[10], 2, 5, True)
        self.assertTrue(success)
        self.assertEqual(2, len(hashes))
        self.assertEqual(self.block_hashes[10], hashes[0])
        self.assertEqual(self.block_hashes[4], hashes[1])

    def test_get_block_hashes_from_height(self):
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_height(
            1019, 1, 0, False)
        self.assertTrue(success)
        self.assertEqual(1, len(hashes))
        self.assertEqual(self.block_hashes[19], hashes[0])

    def test_get_block_by_hash_orphaned_not_found(self):
        # create fork at block 17
        block_message = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(21, 1017))
        block_hash = block_message.block_hash()
        self.block_queuing_service.push(block_hash, block_message)
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_hash(
            block_hash, 1, 0, False)
        self.assertTrue(success)
        self.assertEqual(0, len(hashes))

    def test_get_block_by_number_ambiguous_succeeds(self):
        # create fork at block 17
        block_message = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(21, 1017))
        block_hash = block_message.block_hash()
        self.block_queuing_service.push(block_hash, block_message)

        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_height(
            1017, 1, 0, False)
        self.assertTrue(success)
        self.assertEqual(self.block_hashes[17], hashes[0])

    def test_get_block_hashes_fork_follows_last_sent(self):
        # create fork at block 17
        block_message = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(21, 1017))
        block_hash = block_message.block_hash()
        self.block_queuing_service.push(block_hash, block_message)
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_hash(
            self.block_hashes[15], 5, 0, False)
        self.assertTrue(success)
        self.assertEqual(5, len(hashes))
        self.assertEqual(self.block_hashes[15:20], hashes)

    def test_get_blocks_from_height_not_all_found_at_end(self):
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_height(
            1018, 5, 0, False)
        self.assertTrue(success)
        self.assertEqual(2, len(hashes))
        self.assertEqual(self.block_hashes[18], hashes[0])
        self.assertEqual(self.block_hashes[19], hashes[1])

    def test_get_blocks_from_height_not_all_found_at_beginning(self):
        success, hashes = self.block_queuing_service.get_block_hashes_starting_from_height(
            950, 5, 0, False)
        self.assertFalse(success)
        self.assertEqual(0, len(hashes))

    def test_iterate_recent_block_hashes(self):
        top_blocks = list(
            self.block_queuing_service.iterate_recent_block_hashes(
                max_count=10))
        block_hash = top_blocks[0]
        self.assertEqual(
            self.block_queuing_service._height_by_block_hash[block_hash],
            self.block_queuing_service._highest_block_number)
        self.assertEqual(10, len(top_blocks))

    def test_get_transactions_hashes_from_message(self):
        last_block_hash = list(
            self.block_queuing_service._block_hashes_by_height[
                self.block_queuing_service._highest_block_number])[0]
        self.assertIsNotNone(
            self.block_queuing_service.get_block_body_from_message(
                last_block_hash))
        self.assertIsNone(
            self.block_queuing_service.get_block_body_from_message(bytes(64)))

    def test_tracked_block_cleanup(self):
        from bxgateway.services.eth.eth_normal_block_cleanup_service import EthNormalBlockCleanupService
        self.node.block_cleanup_service = EthNormalBlockCleanupService(
            self.node, 1)
        tx_service = self.node.get_tx_service()
        for block_hash in self.block_queuing_service.iterate_recent_block_hashes(
                self.node.network.block_confirmations_count + 2):
            tx_service.track_seen_short_ids(block_hash, [])

        self.node.block_cleanup_service.block_cleanup_request = MagicMock()
        self.node._tracked_block_cleanup()
        self.node.block_cleanup_service.block_cleanup_request.assert_called_once(
        )

    def test_try_send_headers_to_node_success(self):
        self.node_conn.enqueue_msg.reset_mock()
        result = self.block_queuing_service.try_send_headers_to_node(
            self.block_hashes[:4])

        self.assertTrue(result)
        self.node_conn.enqueue_msg.assert_called_once_with(
            BlockHeadersEthProtocolMessage(None, self.block_headers[:4]))

    def test_try_send_headers_to_node_unknown_block(self):
        self.node.broadcast = MagicMock()
        result = self.block_queuing_service.try_send_headers_to_node(
            [self.block_hashes[0],
             helpers.generate_object_hash()])

        self.assertFalse(result)
        self.node.broadcast.assert_not_called()

    def test_try_send_bodies_to_node_success(self):
        self.node_conn.enqueue_msg.reset_mock()
        result = self.block_queuing_service.try_send_bodies_to_node(
            self.block_hashes[:4])

        self.assertTrue(result)
        self.node_conn.enqueue_msg.assert_called_once_with(
            BlockBodiesEthProtocolMessage(None, self.block_bodies[:4]))

    def test_try_send_bodies_to_node_unknown_block(self):
        self.node_conn.enqueue_msg.reset_mock()
        result = self.block_queuing_service.try_send_bodies_to_node(
            [self.block_hashes[0],
             helpers.generate_object_hash()])

        self.assertFalse(result)
        self.node_conn.enqueue_msg.assert_not_called()