コード例 #1
0
    def test_handle_recovering_block_recovered_quickly(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)

        self.block_queuing_service.push(block_hash_2,
                                        waiting_for_recovery=True)
        self.block_queuing_service.push(block_hash_3, block_3)

        self._assert_no_blocks_sent()

        # block 2 recovers quickly enough, is sent ahead of block 3
        self.block_queuing_service.update_recovered_block(
            block_hash_2, block_2)
        self._assert_block_sent(block_hash_2)

        self._progress_time()
        self._assert_block_sent(block_hash_3)
コード例 #2
0
    def test_accepted_blocks_pushes_next_immediately(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self.block_queuing_service.push(block_hash_2, block_2)
        self.block_queuing_service.push(block_hash_3, block_3)
        self._assert_block_sent(block_hash_1)

        # after block 1 is accepted, block 2 is immediately pushed
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)
        self._assert_block_sent(block_hash_2)

        self._progress_time()
        self._assert_block_sent(block_hash_3)
コード例 #3
0
    def test_handle_recovering_block_timeout(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)

        self.block_queuing_service.push(block_hash_2,
                                        waiting_for_recovery=True)
        self.block_queuing_service.push(block_hash_3, block_3)

        # sent block 3 anyway, block 2 is taking too long to recover
        self._progress_time()
        self._assert_block_sent(block_hash_3)

        # recovery times out in the end, nothing sent and queue cleared
        self._progress_recovery_timeout()
        self._assert_no_blocks_sent()
        self.assertEqual(0, len(self.block_queuing_service))
コード例 #4
0
    def test_handle_out_of_order_blocks(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()

        # second block won't be sent, was somehow not received from BDN
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()

        # third block should still be queued and sent after timeout
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)

        # block 3 sent after a delay, since no block 2 was ever seen
        self.block_queuing_service.push(block_hash_3, block_3)
        self._assert_no_blocks_sent()

        self._progress_time()
        self._assert_block_sent(block_hash_3)
コード例 #5
0
    def test_handle_out_of_order_blocks_confirmed_ancestor(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()

        # block 2 will be received after block 3, but still should be pushed to
        # blockchain node first since block 1 is confirmed and timeout not reached
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)

        self.block_queuing_service.push(block_hash_3, block_3)
        self._assert_no_blocks_sent()

        self.block_queuing_service.push(block_hash_2, block_2)
        self._assert_block_sent(block_hash_2)

        self._progress_time()
        self._assert_block_sent(block_hash_3)
コード例 #6
0
    def test_clear_out_stale_blocks(self):
        self._set_block_queue_in_progress()

        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_2, block_2)
        self.block_queuing_service.push(block_hash_3, block_3)
        self._assert_no_blocks_sent()

        # block 3 marked seen by blockchain node, so eject all earlier blocks (2, 3)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_3, block_3)
        self._assert_no_blocks_sent()

        self.assertEqual(0, len(self.block_queuing_service))
コード例 #7
0
    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))
コード例 #8
0
    def test_partial_chainstate_missing_entries(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        # 2b will never be pushed to block queue
        block_2b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 2, block_hash_1))
        block_hash_2b = block_2b.block_hash()
        block_3b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                4, 3, block_hash_2b))
        block_hash_3b = block_3b.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)
        self.block_queuing_service.push(block_hash_2, block_2)

        # establish an earlier chainstate first, just for testing
        self.block_queuing_service.partial_chainstate(10)

        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_2, block_2)
        self.block_queuing_service.push(block_hash_3b, block_3b)

        expected_result = deque([
            EthBlockInfo(3, block_hash_3b),
        ])
        self.assertEqual(expected_result,
                         self.block_queuing_service.partial_chainstate(10))
コード例 #9
0
    def test_partial_chainstate_missing_entries_in_head(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)

        # establish an earlier chainstate first, just for extending later
        self.block_queuing_service.partial_chainstate(10)

        self.block_queuing_service.push(block_hash_3, block_3)
        self._progress_time()

        expected_result = deque([
            EthBlockInfo(3, block_hash_3),
        ])
        self.assertEqual(expected_result,
                         self.block_queuing_service.partial_chainstate(10))
コード例 #10
0
    def test_handle_recovering_block_recovered_too_slow(self):
        self._set_block_queue_in_progress()

        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()

        self.block_queuing_service.push(block_hash_1,
                                        waiting_for_recovery=True)
        self.block_queuing_service.push(block_hash_2, block_2)

        self._assert_no_blocks_sent()

        # block 1 takes too long to recover, so block 2 is just sent
        self._progress_time()
        self._assert_block_sent(block_hash_2)

        # block 1 is now stale, queue should be empty
        self.block_queuing_service.update_recovered_block(
            block_hash_1, block_1)
        self._assert_no_blocks_sent()

        self._progress_time()
        self._assert_no_blocks_sent()
コード例 #11
0
    def test_handle_out_of_order_blocks_unconfirmed_ancestor(self):
        self._set_block_queue_in_progress()

        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        # block 2 will be received after block 3, but still should be pushed to
        # blockchain node first after timeout (no confirmation on block 1)
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()

        # after another timeout, block 3 will be pushed
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)

        self.block_queuing_service.push(block_hash_3, block_3)
        self._assert_no_blocks_sent()

        self.block_queuing_service.push(block_hash_2, block_2)
        self._assert_no_blocks_sent()

        self._progress_time()
        self._assert_block_sent(block_hash_2)

        self._progress_time()
        self._assert_block_sent(block_hash_3)
コード例 #12
0
    def test_handle_single_block_fork_accepted_later(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2a = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2a = block_2a.block_hash()
        block_2b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 2, block_hash_1))
        block_hash_2b = block_2b.block_hash()

        block_3b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                4, 3, block_hash_2b))
        block_hash_3b = block_3b.block_hash()
        block_4b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                5, 4, block_hash_3b))
        block_hash_4b = block_4b.block_hash()

        # send + accept block 1
        self.block_queuing_service.push(block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)

        # send block 2a
        self.block_queuing_service.push(block_hash_2a, block_2a)
        self._assert_block_sent(block_hash_2a)

        # block 2b will never be sent (despite no confirmation)
        self.block_queuing_service.push(block_hash_2b, block_2b)
        self._assert_no_blocks_sent()

        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_2a, block_2a)

        # block 3b will be sent immediately (block at height 2 confirmed)
        self.block_queuing_service.push(block_hash_3b, block_3b)
        self._assert_block_sent(block_hash_3b)

        # block 4b send later (no confirmation for height 3)
        self.block_queuing_service.push(block_hash_4b, block_4b)
        self._assert_no_blocks_sent()

        self._progress_time()
        self._assert_block_sent(block_hash_4b)
コード例 #13
0
    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()))
コード例 #14
0
    def test_partial_chainstate(self):
        self.assertEqual(deque(),
                         self.block_queuing_service.partial_chainstate(10))

        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)
        self.block_queuing_service.push(block_hash_2, block_2)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_2, block_2)
        self.block_queuing_service.push(block_hash_3, block_3)

        self.assertEqual(0, len(self.block_queuing_service))
        expected_result = deque([
            EthBlockInfo(1, block_hash_1),
            EthBlockInfo(2, block_hash_2),
            EthBlockInfo(3, block_hash_3),
        ])
        self.assertEqual(expected_result,
                         self.block_queuing_service.partial_chainstate(3))

        # returns full chain if requested length is shorter
        self.assertEqual(expected_result,
                         self.block_queuing_service.partial_chainstate(1))

        # not more data, so can't meet asked length
        next_expected_result = deque([
            EthBlockInfo(1, block_hash_1),
            EthBlockInfo(2, block_hash_2),
            EthBlockInfo(3, block_hash_3),
        ])
        self.assertEqual(next_expected_result,
                         self.block_queuing_service.partial_chainstate(10))
コード例 #15
0
    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])
コード例 #16
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))
コード例 #17
0
    def test_dont_send_stale_blocks_newer_block_confirmed(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()

        self._mark_block_seen_by_blockchain_nodes(block_hash_2, block_2)

        # block 1 will be ignored by queue, since block 2 already confirmed
        self.node.block_queuing_service_manager.push(block_hash_1, block_1)

        self._assert_no_blocks_sent()
        self._progress_time()
        self._assert_no_blocks_sent()

        self.assertEqual(0, len(self.block_queuing_service))
コード例 #18
0
    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])
コード例 #19
0
    def test_dont_send_seen_block(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()

        self.node.block_queuing_service_manager.push(block_hash_1, block_1)
        self.node.block_queuing_service_manager.push(block_hash_2, block_2)

        self._assert_block_sent(block_hash_1)
        self._mark_block_seen_by_blockchain_nodes(block_hash_2, block_2)

        # block 2 marked seen by blockchain node, so eject block 2
        self._progress_time()
        self._assert_no_blocks_sent()

        self.assertEqual(0, len(self.block_queuing_service))
コード例 #20
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)
コード例 #21
0
    def test_partial_chainstate_reorganizes(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_2b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 2, block_hash_1))
        block_hash_2b = block_2b.block_hash()
        block_3b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                4, 3, block_hash_2b))
        block_hash_3b = block_3b.block_hash()

        self.block_queuing_service.push(block_hash_1, block_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)
        self.block_queuing_service.push(block_hash_2, block_2)
        self.block_queuing_service.push(block_hash_2b, block_2b)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_2, block_2)

        expected_result = deque([
            EthBlockInfo(1, block_hash_1),
            EthBlockInfo(2, block_hash_2),
        ])
        self.assertEqual(expected_result,
                         self.block_queuing_service.partial_chainstate(10))

        self.block_queuing_service.push(block_hash_3b, block_3b)

        next_expected_result = deque([
            EthBlockInfo(1, block_hash_1),
            EthBlockInfo(2, block_hash_2b),
            EthBlockInfo(3, block_hash_3b),
        ])
        self.assertEqual(next_expected_result,
                         self.block_queuing_service.partial_chainstate(10))
コード例 #22
0
    def test_dont_send_stale_recovered_block(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()

        self._mark_block_seen_by_blockchain_nodes(block_hash_2, block_2)
        self.node.block_queuing_service_manager.push(block_hash_1,
                                                     waiting_for_recovery=True)

        # block 1 will be ignored by queue after recovery (didn't know block
        # number before then), since block 2 already confirmed
        self.node.block_queuing_service_manager.update_recovered_block(
            block_hash_1, block_1)

        self._assert_no_blocks_sent()
        self._progress_time()
        self._assert_no_blocks_sent()

        self.assertEqual(0, len(self.block_queuing_service))
コード例 #23
0
    def test_msg_block_adds_headers_and_bodies(self):
        self.node.opts.max_block_interval = 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.push(
                block_hashes[i], block_messages[i]
            )
            self.node.block_queuing_service.remove_from_queue(block_hashes[i])
        self.node.block_queuing_service.best_sent_block = (1019, block_hashes[-1], 0)

        self.node.send_to_node_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.assertEqual(0, len(self.node.send_to_node_messages))
        self.sut.msg_proxy_request.reset_mock()

        self.sut.msg_block(block_messages[17].to_new_block_msg())
        self.sut.msg_get_block_headers(message)

        self.sut.msg_proxy_request.assert_not_called()
        self.assertEqual(1, len(self.node.send_to_node_messages))

        headers_sent = self.node.send_to_node_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(),
            )
コード例 #24
0
    def test_handle_recovering_block_recovered_ordering(self):
        self._set_block_queue_in_progress()

        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2 = block_2.block_hash()
        block_3 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 3, block_hash_2))
        block_hash_3 = block_3.block_hash()

        # blocks in recovery get added out of order
        self.block_queuing_service.push(block_hash_2,
                                        waiting_for_recovery=True)
        self.block_queuing_service.push(block_hash_1,
                                        waiting_for_recovery=True)
        self.block_queuing_service.push(block_hash_3, block_3)

        self._assert_no_blocks_sent()

        # everything in recovery recovers quickly, so correct order re-established
        self.block_queuing_service.update_recovered_block(
            block_hash_2, block_2)
        self.block_queuing_service.update_recovered_block(
            block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)

        self._progress_time()
        self._assert_block_sent(block_hash_2)

        self._progress_time()
        self._assert_block_sent(block_hash_3)
コード例 #25
0
    def test_bdn_stats_block_new_from_bdn(self):
        block_msg = mock_eth_messages.new_block_eth_protocol_message(21, 1017)
        internal_new_block_msg = InternalEthBlockInfo.from_new_block_msg(
            block_msg)
        msg_bytes, block_info = self.node.message_converter.block_to_bx_block(
            internal_new_block_msg, self.node._tx_service, True,
            self.node.network.min_tx_age_seconds)
        msg_hash = Sha256Hash(crypto.double_sha256(msg_bytes))

        broadcast_msg = BroadcastMessage(message_hash=msg_hash,
                                         network_num=1,
                                         is_encrypted=False,
                                         blob=msg_bytes)
        self.relay_connection.msg_broadcast(broadcast_msg)

        self.assertEqual(
            3,
            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_bdn)
コード例 #26
0
    def setUp(self) -> None:
        self.node = MockGatewayNode(
            gateway_helpers.get_gateway_opts(8000, max_block_interval_s=0))

        self.node.broadcast = MagicMock()

        self.block_queuing_service = EthBlockQueuingService(self.node)
        self.node.block_queuing_service = self.block_queuing_service

        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.block_queuing_service.push(block_hash, block_message)
            prev_block_hash = block_hash

        self.block_processing_service = EthBlockProcessingService(self.node)
        self.node.broadcast.reset_mock()
コード例 #27
0
    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(),
            )
コード例 #28
0
    def test_handle_single_block_fork_already_accepted(self):
        block_1 = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(1, 1))
        block_hash_1 = block_1.block_hash()
        block_2a = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                2, 2, block_hash_1))
        block_hash_2a = block_2a.block_hash()
        block_2b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                3, 2, block_hash_1))
        block_hash_2b = block_2b.block_hash()

        block_3b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                4, 3, block_hash_2b))
        block_hash_3b = block_3b.block_hash()
        block_4b = InternalEthBlockInfo.from_new_block_msg(
            mock_eth_messages.new_block_eth_protocol_message(
                5, 4, block_hash_3b))
        block_hash_4b = block_4b.block_hash()

        # accept block 1
        self.block_queuing_service.push(block_hash_1, block_1)
        self._assert_block_sent(block_hash_1)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_1, block_1)

        # accept block 2a
        self.block_queuing_service.push(block_hash_2a, block_2a)
        self._assert_block_sent(block_hash_2a)
        self.block_queuing_service.mark_block_seen_by_blockchain_node(
            block_hash_2a, block_2a)

        # block 2b will never be sent
        self.block_queuing_service.push(block_hash_2b, block_2b)
        self._assert_no_blocks_sent()

        # block 3b will be sent
        self.block_queuing_service.push(block_hash_3b, block_3b)
        self._assert_block_sent(block_hash_3b)

        # sync triggered, requesting 2a by hash
        self.block_processing_service.try_process_get_block_headers_request(
            GetBlockHeadersEthProtocolMessage(None, block_hash_2a.binary, 1, 0,
                                              0))
        # response is empty
        self._assert_headers_sent([])

        # request block 1 to establish common ancestor
        block_number_bytes = struct.pack(">I", 1)
        self.block_processing_service.try_process_get_block_headers_request(
            GetBlockHeadersEthProtocolMessage(None, block_number_bytes, 1, 0,
                                              0))
        self._assert_headers_sent([block_hash_1])

        # request block 193, 193 + 191, etc to determine chain state
        block_number_bytes = struct.pack(">I", 193)
        self.block_processing_service.try_process_get_block_headers_request(
            GetBlockHeadersEthProtocolMessage(None, block_number_bytes, 128,
                                              191, 0))
        self._assert_headers_sent([])

        # request block 2, 3, 4, ... to compare state
        block_number_bytes = struct.pack(">I", 2)
        self.block_processing_service.try_process_get_block_headers_request(
            GetBlockHeadersEthProtocolMessage(None, block_number_bytes, 192, 0,
                                              0))
        self._assert_headers_sent([block_hash_2b, block_hash_3b])

        # request block 4, 5, 6, ... to compare state
        block_number_bytes = struct.pack(">I", 4)
        self.block_processing_service.try_process_get_block_headers_request(
            GetBlockHeadersEthProtocolMessage(None, block_number_bytes, 192, 0,
                                              0))
        self._assert_headers_sent([])

        # 4b is sent after timeout (presumably Ethereum node didn't send back acceptance
        # because it's resolving chainstate)
        self.block_queuing_service.push(block_hash_4b, block_4b)
        self._assert_no_blocks_sent()

        self._progress_time()
        self._assert_block_sent(block_hash_4b)