Beispiel #1
0
    def setUp(self):
        opts = gateway_helpers.get_gateway_opts(8000,
                                                include_default_btc_args=True)
        if opts.use_extensions:
            helpers.set_extensions_parallelism()
        self.node = MockGatewayNode(opts)
        self.node.neutrality_service = MagicMock()

        self.connection = BtcNodeConnection(
            MockSocketConnection(1,
                                 node=self.node,
                                 ip_address=LOCALHOST,
                                 port=123), self.node)
        gateway_helpers.add_blockchain_peer(self.node, self.connection)

        self.tx_hash = BtcObjectHash(buf=helpers.generate_bytearray(32),
                                     length=BTC_SHA_HASH_LEN)
        self.block_hash = BtcObjectHash(buf=helpers.generate_bytearray(32),
                                        length=BTC_SHA_HASH_LEN)

        self.sut = BtcNodeConnectionProtocol(self.connection)

        while self.connection.outputbuf.length > 0:
            initial_bytes = self.connection.get_bytes_to_send()
            self.connection.advance_sent_bytes(len(initial_bytes))
    def setUp(self):
        self.node = MockGatewayNode(gateway_helpers.get_gateway_opts(
            8000,
            include_default_btc_args=True,
            compact_block_min_tx_count=5
        ))
        self.node.block_processing_service = MagicMock()

        self.connection = BtcNodeConnection(
            MockSocketConnection(node=self.node, ip_address=LOCALHOST, port=123), self.node
        )
        self.connection.node = self.node
        self.connection.peer_ip = LOCALHOST
        self.connection.peer_port = 8001
        self.connection.network_num = 2
        self.sut = BtcNodeConnectionProtocol(self.connection)

        full_block_msg = BlockBtcMessage(
            buf=bytearray(convert.hex_to_bytes(self.FULL_BLOCK_BYTES_HEX))
        )
        if self.node.opts.use_extensions:
            transaction_service = ExtensionTransactionService(self.node, 0)
        else:
            transaction_service = TransactionService(self.node, 0)

        short_id = 1
        for tx in full_block_msg.txns():
            tx_hash = btc_common_utils.get_txid(tx)
            transaction_service.set_transaction_contents(tx_hash, tx)
            transaction_service.assign_short_id(tx_hash, short_id)
            short_id += 1

        self.sut.connection.node._tx_service = transaction_service
Beispiel #3
0
class BtcNodeConnectionProtocolTest(AbstractTestCase):
    def setUp(self):
        opts = gateway_helpers.get_gateway_opts(8000,
                                                include_default_btc_args=True)
        if opts.use_extensions:
            helpers.set_extensions_parallelism()
        self.node = MockGatewayNode(opts)
        self.node.neutrality_service = MagicMock()

        self.connection = BtcNodeConnection(
            MockSocketConnection(node=self.node,
                                 ip_address=LOCALHOST,
                                 port=123), self.node)

        self.tx_hash = BtcObjectHash(buf=helpers.generate_bytearray(32),
                                     length=BTC_SHA_HASH_LEN)
        self.block_hash = BtcObjectHash(buf=helpers.generate_bytearray(32),
                                        length=BTC_SHA_HASH_LEN)

        self.sut = BtcNodeConnectionProtocol(self.connection)

        while self.connection.outputbuf.length > 0:
            initial_bytes = self.connection.get_bytes_to_send()
            self.connection.advance_sent_bytes(len(initial_bytes))

    def test_non_segwit_version_received(self):
        self.assertFalse(self.sut.request_witness_data)

        version_msg = self._create_version_msg(0)
        self.sut.msg_version(version_msg)
        self.assertFalse(self.sut.request_witness_data)

    def test_segwit_version_received(self):
        self.assertFalse(self.sut.request_witness_data)

        version_msg = self._create_version_msg(0 | NODE_WITNESS_SERVICE_FLAG)
        self.sut.msg_version(version_msg)
        self.assertTrue(self.sut.request_witness_data)

    def test_get_data_only_new_data(self):
        seen_block_hash = BtcObjectHash(
            buf=helpers.generate_bytearray(BTC_SHA_HASH_LEN),
            length=BTC_SHA_HASH_LEN)
        not_seen_block_hash = BtcObjectHash(
            buf=helpers.generate_bytearray(BTC_SHA_HASH_LEN),
            length=BTC_SHA_HASH_LEN)
        self.node.blocks_seen.add(seen_block_hash)

        inv_message = InvBtcMessage(
            magic=123,
            inv_vects=[(InventoryType.MSG_TX, seen_block_hash),
                       (InventoryType.MSG_BLOCK, not_seen_block_hash),
                       (InventoryType.MSG_BLOCK, seen_block_hash)])
        self.sut.msg_inv(inv_message)

        get_data_msg_bytes = self.sut.connection.get_bytes_to_send()
        get_data_msg = GetDataBtcMessage(buf=get_data_msg_bytes)
        self.assertEqual(2, get_data_msg.count())
        self.assertIn((InventoryType.MSG_TX, seen_block_hash), get_data_msg)
        self.assertIn((InventoryType.MSG_BLOCK, not_seen_block_hash),
                      get_data_msg)

    def test_get_data_segwit(self):
        self._test_get_data(True)

    def test_get_data_non_segwit(self):
        self._test_get_data(False)

    def _test_get_data(self, segwit):
        self.sut.request_witness_data = segwit

        inv_msg = self._create_inv_msg()
        self.sut.msg_inv(inv_msg)

        get_data_msg_bytes = self.sut.connection.get_bytes_to_send()
        get_data_msg = GetDataBtcMessage(buf=get_data_msg_bytes)
        self.assertEqual(2, get_data_msg.count())

        item_index = 0
        for inv_item in get_data_msg:
            if (item_index == 0):
                self.assertEqual(
                    InventoryType.MSG_WITNESS_TX
                    if segwit else InventoryType.MSG_TX, inv_item[0])
                self.assertEqual(self.tx_hash, inv_item[1])
            else:
                self.assertEqual(
                    InventoryType.MSG_WITNESS_BLOCK
                    if segwit else InventoryType.MSG_BLOCK, inv_item[0])
                self.assertEqual(self.block_hash, inv_item[1])

            item_index += 1

    def _create_version_msg(self, service):
        return VersionBtcMessage(magic=123,
                                 version=234,
                                 dst_ip=LOCALHOST,
                                 dst_port=12345,
                                 src_ip=LOCALHOST,
                                 src_port=12345,
                                 nonce=1,
                                 start_height=0,
                                 user_agent=b"dummy_user_agent",
                                 services=service)

    def _create_inv_msg(self):
        return InvBtcMessage(magic=123,
                             inv_vects=[(InventoryType.MSG_TX, self.tx_hash),
                                        (InventoryType.MSG_BLOCK,
                                         self.block_hash)])
    def process_compact_block_recovery(
            self,
            msg: BlockTransactionsBtcMessage,
            failure_result: CompactBlockCompressionResult,
            connection: BtcNodeConnection
    ) -> None:
        """
        Process compact block recovery .
        If no hold exists, compress and broadcast block immediately.
        """
        block_hash = msg.block_hash()

        for txn in msg.transactions():
            failure_result.recovered_transactions.append(txn)

        try:
            recovery_result = self._node.message_converter.recovered_compact_block_to_bx_block(  # pyre-ignore
                failure_result
            )
        except MessageConversionError as e:
            block_stats.add_block_event_by_block_hash(
                e.msg_hash,
                BlockStatEventType.BLOCK_CONVERSION_FAILED,
                network_num=connection.network_num,
                conversion_type=e.conversion_type.value
            )
            logger.warning(log_messages.COMPACT_BLOCK_PROCESSING_FAIL,
                           e.msg_hash, e)
            get_data_msg = GetDataBtcMessage(
                magic=msg.magic(),
                inv_vects=[(InventoryType.MSG_BLOCK, msg.block_hash())]
            )
            connection.enqueue_msg(get_data_msg)
            return
        block_info = recovery_result.block_info

        if recovery_result.success:
            block_stats.add_block_event_by_block_hash(
                block_hash,
                BlockStatEventType.COMPACT_BLOCK_RECOVERY_SUCCESS,
                network_num=connection.network_num,
                start_date_time=block_info.start_datetime,
                end_date_time=block_info.end_datetime,
                duration=block_info.duration_ms / 1000,
                success=recovery_result.success,
                recoverd_txs_count=len(msg.transactions()),
                txs_count=recovery_result.block_info.txn_count,
                prev_block_hash=recovery_result.block_info.prev_block_hash,
                more_info="{:.2f}ms, {:f}".format(
                    block_info.duration_ms,
                    len(msg.transactions())
                )
            )
            prev_block = Sha256Hash(convert.hex_to_bytes(block_info.prev_block_hash))
            self._node.block_cleanup_service.on_new_block_received(block_hash, prev_block)
            self._process_and_broadcast_compressed_block(
                recovery_result.bx_block,
                connection,
                recovery_result.block_info,
                msg.block_hash()
            )
        else:
            start_datetime = block_info.start_datetime
            end_datetime = datetime.utcnow()
            duration = (end_datetime - start_datetime).total_seconds()
            block_stats.add_block_event_by_block_hash(
                block_hash,
                BlockStatEventType.COMPACT_BLOCK_RECOVERY_FAILED,
                network_num=connection.network_num,
                start_date_time=start_datetime,
                end_date_time=end_datetime,
                duration=duration,
                success=recovery_result.success,
                recoverd_txs_count=len(msg.transactions()),
                more_info="{:.2f}ms, {:f}".format(
                    duration * 1000,
                    len(msg.transactions())
                )
            )
            logger.warning(log_messages.COMPACT_BLOCK_RECOVERY_FAIL, msg.block_hash())
            get_data_msg = GetDataBtcMessage(
                magic=msg.magic(),
                inv_vects=[(InventoryType.MSG_BLOCK, msg.block_hash())]
            )
            connection.enqueue_msg(get_data_msg)
Beispiel #5
0
 def build_blockchain_connection(
     self, socket_connection: AbstractSocketConnectionProtocol
 ) -> AbstractGatewayBlockchainConnection:
     return BtcNodeConnection(socket_connection, self)