def test_recover_multiple_iterations(self): for tx_message in self.transactions: helpers.receive_node_message(self.node1, self.relay_fileno, tx_message.rawbytes()) helpers.clear_node_buffer(self.node1, self.blockchain_fileno) get_txs_message = self._send_compressed_block_to_node_1() txs_message = self._build_txs_message( get_txs_message.get_short_ids()[:5]) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1() time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_RECOVERY_INTERVAL_S[0]) self.node1.alarm_queue.fire_alarms() get_txs_bytes_2 = helpers.get_queued_node_bytes( self.node1, self.relay_fileno, GetTxsMessage.MESSAGE_TYPE) get_txs_message_2 = GetTxsMessage(buf=get_txs_bytes_2.tobytes()) self.assertEqual(5, len(get_txs_message_2.get_short_ids())) txs_message = self._build_txs_message( get_txs_message_2.get_short_ids()[:-1]) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) # retry again in a longer interval bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1() time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_RECOVERY_INTERVAL_S[0]) self.node1.alarm_queue.fire_alarms() bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1() time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_RECOVERY_INTERVAL_S[1]) self.node1.alarm_queue.fire_alarms() get_txs_bytes_3 = helpers.get_queued_node_bytes( self.node1, self.relay_fileno, GetTxsMessage.MESSAGE_TYPE) get_txs_message_3 = GetTxsMessage(buf=get_txs_bytes_3.tobytes()) self.assertEqual(1, len(get_txs_message_3.get_short_ids())) txs_message = self._build_txs_message( get_txs_message_3.get_short_ids()) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) self._assert_sent_block_node_1()
def test_recover_from_single_tx_short_id(self): for tx_message in self.transactions_with_short_ids[:-1]: helpers.receive_node_message(self.node1, self.relay_fileno, tx_message.rawbytes()) helpers.clear_node_buffer(self.node1, self.blockchain_fileno) _get_txs_message = self._send_compressed_block_to_node_1() helpers.receive_node_message( self.node1, self.relay_fileno, self.transactions_with_short_ids[-1].rawbytes()) self._assert_sent_block_node_1()
def test_recover_all_short_ids(self): for tx_message in self.transactions: helpers.receive_node_message(self.node1, self.relay_fileno, tx_message.rawbytes()) helpers.clear_node_buffer(self.node1, self.blockchain_fileno) get_txs_message = self._send_compressed_block_to_node_1() self.assertEqual(10, len(get_txs_message.get_short_ids())) txs_message = self._build_txs_message(get_txs_message.get_short_ids()) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) self._assert_sent_block_node_1()
def _send_compressed_block_to_node_1(self): for tx_message_with_short_id in self.transactions_with_short_ids: helpers.receive_node_message(self.node2, self.relay_fileno, tx_message_with_short_id.rawbytes()) helpers.clear_node_buffer(self.node1, self.blockchain_fileno) helpers.receive_node_message(self.node2, self.blockchain_fileno, self.block.rawbytes()) broadcast_bytes = helpers.get_queued_node_bytes( self.node2, self.relay_fileno, BroadcastMessage.MESSAGE_TYPE) helpers.receive_node_message(self.node1, self.relay_fileno, broadcast_bytes) get_txs_bytes = helpers.get_queued_node_bytes( self.node1, self.relay_fileno, GetTxsMessage.MESSAGE_TYPE) get_txs_message = GetTxsMessage(buf=get_txs_bytes.tobytes()) self._assert_no_block_node_1() return get_txs_message
def clear_all_buffers(self): helpers.clear_node_buffer(self.node1, self.blockchain_fileno) helpers.clear_node_buffer(self.node1, self.relay_fileno) helpers.clear_node_buffer(self.node1, self.gateway_fileno) helpers.clear_node_buffer(self.node2, self.blockchain_fileno) helpers.clear_node_buffer(self.node2, self.relay_fileno) helpers.clear_node_buffer(self.node2, self.gateway_fileno)
def test_recover_give_up(self): gateway_constants.BLOCK_RECOVERY_MAX_RETRY_ATTEMPTS = 3 for tx_message in self.transactions: helpers.receive_node_message(self.node1, self.relay_fileno, tx_message.rawbytes()) helpers.clear_node_buffer(self.node1, self.blockchain_fileno) self._send_compressed_block_to_node_1() txs_message = self._build_txs_message([]) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) # retry, first attempt bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1() time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_RECOVERY_INTERVAL_S[0]) self.node1.alarm_queue.fire_alarms() get_txs_bytes_2 = helpers.get_queued_node_bytes( self.node1, self.relay_fileno, GetTxsMessage.MESSAGE_TYPE) get_txs_message_2 = GetTxsMessage(buf=get_txs_bytes_2.tobytes()) self.assertEqual(10, len(get_txs_message_2.get_short_ids())) txs_message = self._build_txs_message([]) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) # retry, attempt 2 bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1() time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_RECOVERY_INTERVAL_S[1]) self.node1.alarm_queue.fire_alarms() get_txs_bytes_3 = helpers.get_queued_node_bytes( self.node1, self.relay_fileno, GetTxsMessage.MESSAGE_TYPE) get_txs_message_3 = GetTxsMessage(buf=get_txs_bytes_3.tobytes()) self.assertEqual(10, len(get_txs_message_3.get_short_ids())) txs_message = self._build_txs_message([]) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) # retry, attempt 3 bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1() time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_RECOVERY_INTERVAL_S[2]) self.node1.alarm_queue.fire_alarms() get_txs_bytes_4 = helpers.get_queued_node_bytes( self.node1, self.relay_fileno, GetTxsMessage.MESSAGE_TYPE) get_txs_message_4 = GetTxsMessage(buf=get_txs_bytes_4.tobytes()) self.assertEqual(10, len(get_txs_message_4.get_short_ids())) txs_message = self._build_txs_message([]) helpers.receive_node_message(self.node1, self.relay_fileno, txs_message.rawbytes()) # retry given up bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1() time.time = MagicMock( return_value=time.time() + gateway_constants.BLOCK_RECOVERY_RECOVERY_INTERVAL_S[3] * 20) self.node1.alarm_queue.fire_alarms() # no bytes, even after timeout bytes_to_send = self.node1.get_bytes_to_send(self.relay_fileno) self.assertEqual(0, len(bytes_to_send)) self._assert_no_block_node_1()
def test_request_block_propagation(self): block = btc_block().rawbytes() # propagate block helpers.receive_node_message(self.node1, self.blockchain_fileno, block) block_hold_request_relay = self.node1.get_bytes_to_send( self.relay_fileno) self.assertIn(BlockHoldingMessage.MESSAGE_TYPE, block_hold_request_relay.tobytes()) self.node1.on_bytes_sent(self.relay_fileno, len(block_hold_request_relay)) relayed_block = self.node1.get_bytes_to_send(self.relay_fileno) self.assertIn(BroadcastMessage.MESSAGE_TYPE, relayed_block.tobytes()) block_hold_request_gateway = self.node1.get_bytes_to_send( self.gateway_fileno) self.assertIn(BlockHoldingMessage.MESSAGE_TYPE, block_hold_request_gateway.tobytes()) self.clear_all_buffers() # receipt timeout time.time = MagicMock( return_value=time.time() + gateway_constants.NEUTRALITY_BROADCAST_BLOCK_TIMEOUT_S) self.node1.alarm_queue.fire_alarms() key_msg_gateway = self.node1.get_bytes_to_send(self.gateway_fileno) self.assertIn(KeyMessage.MESSAGE_TYPE, key_msg_gateway.tobytes()) self.node1.on_bytes_sent(self.gateway_fileno, len(key_msg_gateway)) block_prop_request = self.node1.get_bytes_to_send(self.gateway_fileno) self.assertIn(BlockPropagationRequestMessage.MESSAGE_TYPE, block_prop_request.tobytes()) self.clear_all_buffers() # get new block to send helpers.receive_node_message(self.node2, self.gateway_fileno, block_prop_request) new_relayed_block = self.node2.get_bytes_to_send(self.relay_fileno) self.assertIn(BroadcastMessage.MESSAGE_TYPE, new_relayed_block.tobytes()) helpers.clear_node_buffer(self.node2, self.relay_fileno) # receive new block helpers.receive_node_message(self.node1, self.relay_fileno, new_relayed_block) block_receipt = self.node1.get_bytes_to_send(self.gateway_fileno) self.assertIn(BlockReceivedMessage.MESSAGE_TYPE, block_receipt.tobytes()) # receive block receipt helpers.receive_node_message(self.node2, self.gateway_fileno, block_receipt) key_message = self.node2.get_bytes_to_send(self.relay_fileno) self.assertIn(KeyMessage.MESSAGE_TYPE, key_message.tobytes()) # receive key, but already seen so dont forward to blockchain helpers.receive_node_message(self.node1, self.relay_fileno, key_message) bytes_to_blockchain = self.node1.get_bytes_to_send( self.blockchain_fileno) self.assertEqual(OutputBuffer.EMPTY, bytes_to_blockchain) # clear blocks seen, rereceive self.node1.blocks_seen = ExpiringSet( self.node1.alarm_queue, gateway_constants.GATEWAY_BLOCKS_SEEN_EXPIRATION_TIME_S, "testset") helpers.receive_node_message(self.node1, self.relay_fileno, key_message) # ignore key message even if block is not in "blocks_seen" bytes_to_blockchain = self.node1.get_bytes_to_send( self.blockchain_fileno) self.assertEqual(OutputBuffer.EMPTY, bytes_to_blockchain)