def test_block_removed_with_ttl_check(self): self.node.has_active_blockchain_peer = MagicMock(return_value=False) block_hash_start = Sha256Hash(helpers.generate_hash()) block_msg_start = helpers.create_block_message(block_hash_start) block_hash_end = Sha256Hash(helpers.generate_hash()) block_msg_end = helpers.create_block_message(block_hash_end) self.node.block_queuing_service_manager.push(block_hash_start, block_msg_start) for i in range(2, BLOCK_QUEUE_LENGTH_LIMIT + 1): block_hash = Sha256Hash(helpers.generate_hash()) block_msg = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.push(block_hash, block_msg) self.assertEqual(BLOCK_QUEUE_LENGTH_LIMIT, len(self.block_queuing_service)) self._assert_length_of_enqueued_messages(0) self.node.has_active_blockchain_peer = MagicMock(return_value=True) time.time = MagicMock( return_value=time.time() + MAX_BLOCK_CACHE_TIME_S * 2 ) self.assertEqual(BLOCK_QUEUE_LENGTH_LIMIT, len(self.block_queuing_service._block_queue)) self.node.block_queuing_service_manager.push(block_hash_end, block_msg_end) self._mark_blocks_seen_by_blockchain_nodes([block_hash_end]) self.assertEqual(0, len(self.block_queuing_service._block_queue))
def test_block_added_waiting_for_previous_block_confirmation(self): block_hash_1 = Sha256Hash(helpers.generate_hash()) block_msg_1 = helpers.create_block_message(block_hash_1) block_hash_2 = Sha256Hash(helpers.generate_hash()) block_msg_2 = helpers.create_block_message(block_hash_2, block_hash_1) # first block gets sent immediately self.node.block_queuing_service_manager.push(block_hash_1, block_msg_1) self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg_1, 0) self._assert_len_of_block_queuing_services(0) self._assert_block_in_queuing_services(block_hash_1) # no confirmation, wait on block 1 self.node.block_queuing_service_manager.push(block_hash_2, block_msg_2) self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg_1, 0) self._assert_len_of_block_queuing_services(1) self._assert_block_in_queuing_services(block_hash_1) self._assert_block_in_queuing_services(block_hash_2) self._mark_blocks_seen_by_blockchain_nodes( [block_hash_1] ) self._assert_length_of_enqueued_messages(2) self._assert_block_in_enqueued_messages_index(block_msg_2, 1) self._assert_len_of_block_queuing_services(0)
def test_block_queue_continues_after_timeout(self): block_hash_1 = helpers.generate_object_hash() block_msg_1 = helpers.create_block_message(block_hash_1) block_hash_2 = helpers.generate_object_hash() block_msg_2 = helpers.create_block_message(block_hash_2, block_hash_1) block_hash_3 = helpers.generate_object_hash() block_msg_3 = helpers.create_block_message(block_hash_3, block_hash_2) self.node.has_active_blockchain_peer = MagicMock(return_value=False) self.node.block_queuing_service_manager.push(block_hash_1, block_msg_1) time.time = MagicMock(return_value=time.time() + 150) self.node.block_queuing_service_manager.push(block_hash_2, block_msg_2) self.node.block_queuing_service_manager.push(block_hash_3, block_msg_3) time.time = MagicMock(return_value=time.time() + TTL - 150 + 1) # too much time has elapsed for the first message self.node.has_active_blockchain_peer = MagicMock(return_value=True) self.node.alarm_queue.fire_alarms() self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg_2, 0)
def test_waiting_recovery_last_block_is_removed(self): block_hash1 = Sha256Hash(helpers.generate_hash()) block_msg1 = helpers.create_block_message(block_hash1) block_hash2 = Sha256Hash(helpers.generate_hash()) block_msg2 = helpers.create_block_message(block_hash2, block_hash1) block_hash3 = Sha256Hash(helpers.generate_hash()) block_msg3 = helpers.create_block_message(block_hash3, block_hash2) self.node.block_queuing_service_manager.push( block_hash1, block_msg1, waiting_for_recovery=False) self.node.block_queuing_service_manager.push( block_hash2, block_msg2, waiting_for_recovery=False) self.node.block_queuing_service_manager.push(block_hash3, block_msg3, waiting_for_recovery=True) self._assert_length_of_enqueued_messages(1) self._assert_len_of_block_queuing_services(2) self._assert_block_in_enqueued_messages_index(block_msg1, 0) self._reset_enqueue_msg_mocks() self.block_queuing_service.remove(block_hash3) self.block_queuing_service_2.remove(block_hash3) self._assert_length_of_enqueued_messages(0) self._assert_len_of_block_queuing_services(1) self._mark_blocks_seen_by_blockchain_nodes([block_hash1]) self._assert_length_of_enqueued_messages(1) self._assert_len_of_block_queuing_services(0) self._assert_block_in_enqueued_messages_index(block_msg2, 0)
def test_waiting_confirmation_timeout(self): block_hash_1 = Sha256Hash(helpers.generate_hash()) block_msg_1 = helpers.create_block_message(block_hash_1) block_hash_2 = Sha256Hash(helpers.generate_hash()) block_msg_2 = helpers.create_block_message(block_hash_2, block_hash_1) # first block gets sent immediately self.node.block_queuing_service_manager.push(block_hash_1, block_msg_1) self.node.block_queuing_service_manager.push(block_hash_2, block_msg_2) self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg_1, 0) self._assert_len_of_block_queuing_services(1) self._assert_block_in_queuing_services(block_hash_1) self._assert_block_in_queuing_services(block_hash_2) time.time = MagicMock( return_value=time.time() + gateway_constants.MAX_INTERVAL_BETWEEN_BLOCKS_S ) self.node.alarm_queue.fire_alarms() self._assert_length_of_enqueued_messages(2) self._assert_block_in_enqueued_messages_index(block_msg_2, 1) self._assert_len_of_block_queuing_services(0) self._assert_block_in_queuing_services(block_hash_1) self._assert_block_in_queuing_services(block_hash_2)
def test_last_block_is_recovered(self): block_hash1 = Sha256Hash(helpers.generate_hash()) block_msg1 = helpers.create_block_message() block_hash2 = Sha256Hash(helpers.generate_hash()) block_msg2 = helpers.create_block_message(block_hash2, block_hash1) block_hash3 = Sha256Hash(helpers.generate_hash()) block_msg3 = helpers.create_block_message(block_hash3, block_hash2) self.node.block_queuing_service_manager.push( block_hash1, block_msg1, waiting_for_recovery=False ) self._mark_block_seen_by_blockchain_nodes( block_hash1, None ) self.node.block_queuing_service_manager.push( block_hash2, block_msg2, waiting_for_recovery=False ) self._mark_block_seen_by_blockchain_nodes( block_hash2, None ) self.node.block_queuing_service_manager.push( block_hash3, block_msg3, waiting_for_recovery=True ) self._assert_length_of_enqueued_messages(2) self._assert_len_of_block_queuing_services(1) self._assert_block_in_enqueued_messages_index(block_msg1, 0) self._assert_block_in_enqueued_messages_index(block_msg2, 1) self._reset_enqueue_msg_mocks() self._reset_enqueue_msg_mocks() # don't send, since not recovered enough though timeout time.time = MagicMock( return_value=time.time() + MAX_INTERVAL_BETWEEN_BLOCKS_S ) self.node.alarm_queue.fire_alarms() self._assert_length_of_enqueued_messages(0) self._assert_len_of_block_queuing_services(1) self.node.block_queuing_service_manager.update_recovered_block( block_hash3, block_msg3 ) self._assert_length_of_enqueued_messages(1) self._assert_len_of_block_queuing_services(0) self._assert_block_in_enqueued_messages_index(block_msg3, 0)
def test_update_recovered_block(self): block_queuing_service = self.node.build_block_queuing_service( self.node_conn) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn, block_queuing_service) block_queuing_service.update_recovered_block = MagicMock() block_queuing_service_2 = self.node.build_block_queuing_service( self.node_conn_2) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn_2, block_queuing_service_2) block_queuing_service_2.update_recovered_block = MagicMock() block_queuing_service_3 = self.node.build_block_queuing_service( self.node_conn_3) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn_3, block_queuing_service_3) block_queuing_service_3.update_recovered_block = MagicMock() self.assertEqual( len(self.node.block_queuing_service_manager. blockchain_peer_to_block_queuing_service), 3) block_hash = Sha256Hash(helpers.generate_hash()) block_msg = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.update_recovered_block( block_hash, block_msg) block_queuing_service.update_recovered_block.assert_called_with( block_hash, block_msg) block_queuing_service_2.update_recovered_block.assert_called_with( block_hash, block_msg) block_queuing_service_3.update_recovered_block.assert_called_with( block_hash, block_msg) self.assertIn(block_hash, self.node.block_storage) self.assertEqual(block_msg, self.node.block_storage[block_hash])
def test_remove_block(self): block_queuing_service = self.node.build_block_queuing_service( self.node_conn) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn, block_queuing_service) block_queuing_service.remove = MagicMock() block_queuing_service_2 = self.node.build_block_queuing_service( self.node_conn_2) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn_2, block_queuing_service_2) block_queuing_service_2.remove = MagicMock() block_hash = Sha256Hash(helpers.generate_hash()) block_msg = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.store_block_data( block_hash, block_msg) block_queuing_service._blocks.add(block_hash) block_queuing_service_2._blocks.add(block_hash) self.assertIn(block_hash, self.node.block_storage) self.assertEqual(block_msg, self.node.block_storage[block_hash]) self.node.block_queuing_service_manager.remove(block_hash) self.assertNotIn(block_hash, self.node.block_storage) block_queuing_service.remove.assert_called_with(block_hash) block_queuing_service_2.remove.assert_called_with(block_hash)
def test_waiting_recovery__timeout(self): block_hash1 = Sha256Hash(helpers.generate_hash()) block_hash2 = Sha256Hash(helpers.generate_hash()) block_msg2 = helpers.create_block_message(block_hash2) block_hash3 = Sha256Hash(helpers.generate_hash()) block_msg3 = helpers.create_block_message(block_hash3) self.node.block_queuing_service_manager.push( block_hash1, None, waiting_for_recovery=True ) self.node.block_queuing_service_manager.push( block_hash2, block_msg2, waiting_for_recovery=False ) self.node.block_queuing_service_manager.push( block_hash3, block_msg3, waiting_for_recovery=False ) self._assert_length_of_enqueued_messages(0) self._assert_len_of_block_queuing_services(3) self._assert_block_in_queuing_services(block_hash1) self._assert_block_in_queuing_services(block_hash2) self._assert_block_in_queuing_services(block_hash3) # fire alarm when block recovery not expired time.time = MagicMock( return_value=time.time() + BLOCK_RECOVERY_MAX_QUEUE_TIME / 2 + 1 ) self.node.alarm_queue.fire_alarms() self._assert_length_of_enqueued_messages(0) self._assert_len_of_block_queuing_services(3) self._assert_block_in_queuing_services(block_hash1) self._assert_block_in_queuing_services(block_hash2) self._assert_block_in_queuing_services(block_hash3) # fire alarm after recovery expires and is not successful time.time = MagicMock( return_value=time.time() + BLOCK_RECOVERY_MAX_QUEUE_TIME ) self.node.alarm_queue.fire_alarms() self._assert_length_of_enqueued_messages(1) self._assert_len_of_block_queuing_services(1) self._assert_block_in_enqueued_messages_index(block_msg2, 0) self.assertNotIn(block_hash1, self.block_queuing_service) self._assert_block_in_queuing_services(block_hash2) self._assert_block_in_queuing_services(block_hash3)
def test_waiting_recovery_top_block_timeout(self): block_hash1 = Sha256Hash(helpers.generate_hash()) block_hash2 = Sha256Hash(helpers.generate_hash()) block_msg2 = helpers.create_block_message(block_hash2, block_hash1) block_hash3 = Sha256Hash(helpers.generate_hash()) block_msg3 = helpers.create_block_message(block_hash3, block_hash2) self.node.block_queuing_service_manager.push( block_hash1, None, waiting_for_recovery=True ) self.node.block_queuing_service_manager.push( block_hash2, block_msg2, waiting_for_recovery=False ) self.node.block_queuing_service_manager.push( block_hash3, block_msg3, waiting_for_recovery=False ) self._assert_length_of_enqueued_messages(0) self._assert_len_of_block_queuing_services(3) self._assert_block_in_queuing_services(block_hash1) self._assert_block_in_queuing_services(block_hash2) self._assert_block_in_queuing_services(block_hash3) # trigger automatic removal of top block recovery time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_MAX_QUEUE_TIME ) self.node.alarm_queue.fire_alarms() self._assert_length_of_enqueued_messages(1) self._assert_len_of_block_queuing_services(1) self._assert_block_in_enqueued_messages_index(block_msg2, 0) self._reset_enqueue_msg_mocks() self._mark_blocks_seen_by_blockchain_nodes( [block_hash2] ) self._assert_length_of_enqueued_messages(1) self._assert_len_of_block_queuing_services(0) self._assert_block_in_enqueued_messages_index(block_msg3, 0)
def test_store_block_data(self): block_queuing_service = self.node.build_block_queuing_service( self.node_conn) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn, block_queuing_service) block_hash = Sha256Hash(helpers.generate_hash()) block_msg = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.store_block_data( block_hash, block_msg) self.assertIn(block_hash, self.node.block_storage) self.assertEqual(block_msg, self.node.block_storage[block_hash])
def test_block_added_send_immediately_with_confirmation(self): block_hash_1 = Sha256Hash(helpers.generate_hash()) block_msg_1 = helpers.create_block_message(block_hash_1) block_hash_2 = Sha256Hash(helpers.generate_hash()) block_msg_2 = helpers.create_block_message(block_hash_2, block_hash_1) # first block gets sent immediately self.node.block_queuing_service_manager.push(block_hash_1, block_msg_1) self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg_1, 0) self._assert_len_of_block_queuing_services(0) self._assert_block_in_queuing_services(block_hash_1) # confirmed, send immediately self._mark_block_seen_by_blockchain_nodes(block_hash_1, None) self.node.block_queuing_service_manager.push(block_hash_2, block_msg_2) self._assert_length_of_enqueued_messages(2) self._assert_block_in_enqueued_messages_index(block_msg_2, 1) self._assert_len_of_block_queuing_services(0) self._assert_block_in_queuing_services(block_hash_1) self._assert_block_in_queuing_services(block_hash_2)
def test_push_block_queuing_service(self): block_queuing_service = self.node.build_block_queuing_service( self.node_conn) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn, block_queuing_service) block_queuing_service.push = MagicMock() block_queuing_service_2 = self.node.build_block_queuing_service( self.node_conn_2) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn_2, block_queuing_service_2) block_queuing_service_2.push = MagicMock() block_queuing_service_3 = self.node.build_block_queuing_service( self.node_conn_3) self.node.block_queuing_service_manager.add_block_queuing_service( self.node_conn_3, block_queuing_service_3) block_queuing_service_3.push = MagicMock() block_hash = Sha256Hash(helpers.generate_hash()) block_msg = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.push(block_hash, block_msg) block_queuing_service.push.assert_called_with(block_hash, block_msg, False) block_queuing_service_2.push.assert_called_with( block_hash, block_msg, False) block_queuing_service_3.push.assert_called_with( block_hash, block_msg, False) block_hash2 = Sha256Hash(helpers.generate_hash()) block_msg2 = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.push(block_hash2, block_msg2, waiting_for_recovery=True) block_queuing_service.push.assert_called_with(block_hash2, block_msg2, True) block_queuing_service_2.push.assert_called_with( block_hash2, block_msg2, True) block_queuing_service_3.push.assert_called_with( block_hash2, block_msg2, True)
def test_sending_block_timed_out(self): block_hash_1 = Sha256Hash(helpers.generate_hash()) block_msg_1 = helpers.create_block_message(block_hash_1) block_hash_2 = Sha256Hash(helpers.generate_hash()) block_msg_2 = helpers.create_block_message(block_hash_2, block_hash_1) # first block gets sent immediately self.node.block_queuing_service_manager.push(block_hash_1, block_msg_1) self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg_1, 0) self._assert_len_of_block_queuing_services(0) self._assert_block_in_queuing_services(block_hash_1) self.node.block_queuing_service_manager.push(block_hash_2, block_msg_2) time.time = MagicMock(return_value=time.time() + 350) # too much time has elapsed, message is dropped self.node.alarm_queue.fire_alarms() self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg_1, 0) self._assert_len_of_block_queuing_services(0)
def test_sending_headers_to_node(self): block_hash = Sha256Hash(helpers.generate_hash()) block_message = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.push(block_hash, block_message) success = self.block_queuing_service.try_send_header_to_node(block_hash) self.assertTrue(success) success = self.block_queuing_service_2.try_send_header_to_node(block_hash) self.assertTrue(success) self._assert_length_of_enqueued_messages(2) block_header_message = self._get_enqueued_messages(self.node_conn)[1] self.assertIsInstance(block_header_message, TestBlockHeaderMessage) self.assertEqual(block_hash, block_header_message.block_hash) block_header_message = self._get_enqueued_messages(self.node_conn_2)[1] self.assertIsInstance(block_header_message, TestBlockHeaderMessage) self.assertEqual(block_hash, block_header_message.block_hash)
def test_block_added_to_empty_queue(self): block_hash = Sha256Hash(helpers.generate_hash()) block_msg = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.push( block_hash, block_msg, waiting_for_recovery=False) self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg, 0) self._assert_len_of_block_queuing_services(0) self._assert_len_of_blocks_sent(1) self.assertEqual(block_hash, self.block_queuing_service.blocks_sent[0]) # block still in service after confirmation self._assert_block_in_queuing_services(block_hash) self._mark_block_seen_by_blockchain_nodes(block_hash, None) self._assert_block_in_queuing_services(block_hash)
def test_block_added_when_node_is_not_ready(self): self.node.has_active_blockchain_peer = MagicMock(return_value=False) block_hash = Sha256Hash(helpers.generate_hash()) block_msg = helpers.create_block_message(block_hash) self.node.block_queuing_service_manager.push( block_hash, block_msg, waiting_for_recovery=False ) self._assert_length_of_enqueued_messages(0) self._assert_len_of_block_queuing_services(1) self._assert_block_in_queuing_services(block_hash) time.time = MagicMock( return_value=time.time() + NODE_READINESS_FOR_BLOCKS_CHECK_INTERVAL_S ) self.node.alarm_queue.fire_alarms() # verify that item is still in the queue if node connection # is still not available self._assert_length_of_enqueued_messages(0) self._assert_len_of_block_queuing_services(1) self._assert_block_in_queuing_services(block_hash) self.node.has_active_blockchain_peer = MagicMock(return_value=True) time.time = MagicMock( return_value=time.time() + NODE_READINESS_FOR_BLOCKS_CHECK_INTERVAL_S * 2 ) self.node.alarm_queue.fire_alarms() # verify that is sent to node once connection to node is active self._assert_length_of_enqueued_messages(1) self._assert_block_in_enqueued_messages_index(block_msg, 0) self._assert_len_of_block_queuing_services(0) # verify item still cached, since confirmation not received self._assert_block_in_queuing_services(block_hash)