Пример #1
0
    def test_calc_allowed_decimals(self):
        decimal = Transaction.calc_allowed_decimals(10000000000000000000)
        self.assertEqual(decimal, 0)

        decimal = Transaction.calc_allowed_decimals(1)
        self.assertEqual(decimal, 19)

        decimal = Transaction.calc_allowed_decimals(2)
        self.assertEqual(decimal, 18)
Пример #2
0
    def rollback_tx_metadata(state: State, block, batch):
        fee_reward = 0
        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            fee_reward += txn.fee
            TransactionMetadata.remove_tx_metadata(state, txn, batch)

        txn = Transaction.from_pbdata(
            block.transactions[0])  # Coinbase Transaction
        state._update_total_coin_supply(fee_reward - txn.amount, batch)
        LastTransactions._remove_last_tx(state, block, batch)
Пример #3
0
def tx_push(ctx, txblob):
    """
    Sends a signed transaction blob to a node
    """
    tx = None
    try:
        txbin = parse_hexblob(txblob)
        pbdata = xrd_pb2.Transaction()
        pbdata.ParseFromString(txbin)
        tx = Transaction.from_pbdata(pbdata)
    except Exception as e:
        click.echo("tx blob is not valid")
        quit(1)

    tmp_json = tx.to_json()
    # FIXME: binary fields are represented in base64. Improve output
    print(tmp_json)
    if len(tx.signature) == 0:
        click.echo('Signature missing')
        quit(1)

    stub = ctx.obj.get_stub_public_api()
    pushTransactionReq = xrd_pb2.PushTransactionReq(transaction_signed=tx.pbdata)
    pushTransactionResp = stub.PushTransaction(pushTransactionReq, timeout=CONNECTION_TIMEOUT)
    print(pushTransactionResp.error_code)
Пример #4
0
    def update_tx_metadata(state: State, block, batch) -> bool:
        fee_reward = 0

        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            fee_reward += txn.fee
            if not TransactionMetadata.put_tx_metadata(
                    state, txn, block.block_number, block.timestamp, batch):
                return False

        txn = Transaction.from_pbdata(
            block.transactions[0])  # Coinbase Transaction
        state._update_total_coin_supply(txn.amount - fee_reward, batch)
        LastTransactions._update_last_tx(state, block, batch)

        return True
Пример #5
0
    def test_from_json(self, m_logger):
        tx = Transaction.from_json(test_json_TransferToken)
        tx.sign(self.alice)

        self.assertIsInstance(tx, TransferTokenTransaction)

        # Test that common Transaction components were copied over.
        self.assertEqual(
            '010300a1da274e68c88b0ccf448e0b1916fa789b01eb2ed4e9ad565ce264c9390782a9c61ac02f',
            bin2hstr(tx.addr_from))
        self.assertEqual(
            '01030038ea6375069f8272cc1a6601b3c76c21519455603d370036b97c779ada356'
            '5854e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e',
            bin2hstr(tx.PK))
        self.assertEqual(b'000000000000000', tx.token_txhash)
        self.assertEqual(200000, tx.total_amount)
        self.assertEqual(
            '390b159b34cffd29d4271a19679ff227df2ccd471078f177a7b58ca5f5d999f0',
            bin2hstr(tx.txhash))
        self.assertEqual(10, tx.ots_key)

        # z = bin2hstr(tx.signature)
        # print('"', end='')
        # for i in range(len(z)):
        #     print(z[i], end='')
        #     if (i + 1) % 64 == 0:
        #         print('" \\', end='')
        #         print('')
        #         print(' ' * len('test_signature_TransferToken = '), end='')
        #         print('"', end='')

        self.assertEqual(test_signature_TransferToken, bin2hstr(tx.signature))

        self.assertEqual(1, tx.fee)
Пример #6
0
    def test_from_json(self, m_logger):
        tx = Transaction.from_json(test_json_Token)
        tx.sign(self.alice)
        self.assertIsInstance(tx, TokenTransaction)

        # Test that common Transaction components were copied over.
        self.assertEqual('010300a1da274e68c88b0ccf448e0b1916fa789b01eb2ed4e9ad565ce264c9390782a9c61ac02f',
                         bin2hstr(tx.addr_from))
        self.assertEqual('01030038ea6375069f8272cc1a6601b3c76c21519455603d370036b97c779ada356'
                         '5854e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e',
                         bin2hstr(tx.PK))
        self.assertEqual(b'xrd', tx.symbol)
        self.assertEqual(b'Quantum Resistant Ledger', tx.name)
        self.assertEqual('010317463dcd581b679b4754f46c6425125489a2826894e3c42a590efb6806450ce6bf52716c',
                         bin2hstr(tx.owner))
        self.assertEqual('ff84da605e9c9cd04d68503be7922110b4cc147837f8687ad18aa54b7bc5632d', bin2hstr(tx.txhash))
        self.assertEqual(10, tx.ots_key)

        self.assertEqual(test_signature_Token, bin2hstr(tx.signature))

        total_supply = 0
        for initial_balance in tx.initial_balances:
            total_supply += initial_balance.amount
        self.assertEqual(600000000, total_supply)

        self.assertEqual(1, tx.fee)
Пример #7
0
    def test_from_json(self, m_logger):
        tx = Transaction.from_json(test_json_Simple)
        tx.sign(self.alice)
        self.assertIsInstance(tx, TransferTransaction)

        # Test that common Transaction components were copied over.
        self.assertEqual(0, tx.nonce)
        self.assertEqual(
            '010300a1da274e68c88b0ccf448e0b1916fa789b01eb2ed4e9ad565ce264c9390782a9c61ac02f',
            bin2hstr(tx.addr_from))
        self.assertEqual(
            '01030038ea6375069f8272cc1a6601b3c76c21519455603d370036b97c779ada356'
            '5854e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e',
            bin2hstr(tx.PK))
        self.assertEqual(
            '554f546305d4aed6ec71c759942b721b904ab9d65eeac3c954c08c652181c4e8',
            bin2hstr(tx.txhash))
        self.assertEqual(10, tx.ots_key)

        self.assertEqual(test_signature_Simple, bin2hstr(tx.signature))

        # Test that specific content was copied over.
        self.assertEqual(
            '0103001d65d7e59aed5efbeae64246e0f3184d7c42411421eb385ba30f2c1c005a85ebc4419cfd',
            bin2hstr(tx.addrs_to[0]))
        self.assertEqual(100, tx.total_amount)
        self.assertEqual(1, tx.fee)
Пример #8
0
    def PushTransaction(self, request: xrd_pb2.PushTransactionReq,
                        context) -> xrd_pb2.PushTransactionResp:
        logger.debug("[PublicAPI] PushTransaction")
        answer = xrd_pb2.PushTransactionResp()

        try:
            tx = Transaction.from_pbdata(request.transaction_signed)
            tx.update_txhash()

            # FIXME: Full validation takes too much time. At least verify there is a signature
            # the validation happens later in the tx pool
            if len(tx.signature) > 1000:
                self.xrdnode.submit_send_tx(tx)
                answer.error_code = xrd_pb2.PushTransactionResp.SUBMITTED
                answer.tx_hash = tx.txhash
            else:
                answer.error_description = 'Signature too short'
                answer.error_code = xrd_pb2.PushTransactionResp.VALIDATION_FAILED

        except Exception as e:
            error_str = traceback.format_exception(None, e, e.__traceback__)
            answer.error_description = str(''.join(error_str))
            answer.error_code = xrd_pb2.PushTransactionResp.ERROR

        return answer
Пример #9
0
 def get_tx_metadata(state: State, txhash: bytes):
     try:
         tx_metadata = TransactionMetadata.deserialize(
             state._db.get_raw(txhash))
         data, block_number = tx_metadata.transaction, tx_metadata.block_number
         return Transaction.from_pbdata(data), block_number
     except Exception:
         return None
Пример #10
0
    def test_validate_tx2(self, m_logger):
        tx = Transaction.from_json(test_json_MessageTransaction)
        tx.sign(self.alice)

        self.assertTrue(tx.validate_or_raise())

        tx._data.transaction_hash = b'abc'

        # Should fail, as we have modified with invalid transaction_hash
        with self.assertRaises(ValueError):
            tx.validate_or_raise()
Пример #11
0
 def test_update_mining_address(self):
     self.block.update_mining_address(dev_config=config.dev,
                                      mining_address=bob.address)
     coinbase_tx = Transaction.from_pbdata(self.block.transactions[0])
     self.assertTrue(isinstance(coinbase_tx, CoinBase))
     self.assertEqual(coinbase_tx.addr_to, bob.address)
     hashedtransactions = []
     for tx in self.block.transactions:
         hashedtransactions.append(tx.transaction_hash)
     self.assertEqual(self.block.blockheader.tx_merkle_root,
                      merkle_tx_hash(hashedtransactions))
Пример #12
0
 def add_tx_from_block_to_pool(self, block: Block, current_block_number):
     """
     Move all transactions from block to transaction pool.
     :param block:
     :return:
     """
     for protobuf_tx in block.transactions[1:]:
         if not self.add_tx_to_pool(Transaction.from_pbdata(protobuf_tx), current_block_number):
             logger.warning('Failed to Add transaction into transaction pool')
             logger.warning('Block #%s %s', block.block_number, bin2hstr(block.headerhash))
             return
Пример #13
0
    def update_mining_address(self, dev_config: DevConfig,
                              mining_address: bytes):
        coinbase_tx = Transaction.from_pbdata(self.transactions[0])
        coinbase_tx.update_mining_address(mining_address)
        hashedtransactions = []

        for tx in self.transactions:
            hashedtransactions.append(tx.transaction_hash)

        self.blockheader.update_merkle_root(dev_config,
                                            merkle_tx_hash(hashedtransactions))

        self._data.header.MergeFrom(self.blockheader.pbdata)
Пример #14
0
    def _remove_last_tx(state: State, block: Block, batch):
        if len(block.transactions) == 0:
            return

        try:
            last_txn = LastTransactions.deserialize(
                state._db.get_raw(b'last_txn'))
        except KeyError:
            return

        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            i = 0
            while i < len(last_txn.tx_metadata):
                tx = Transaction.from_pbdata(
                    last_txn.tx_metadata[i].transaction)
                if txn.txhash == tx.txhash:
                    del last_txn.tx_metadata[i]
                    break
                i += 1

        state._db.put_raw(b'last_txn', last_txn.serialize(), batch)
Пример #15
0
def get_genesis_with_only_coin_base_txn(coin_base_reward_addr, dev_config):
    g = GenesisBlock()

    coin_base_tx = Transaction.from_pbdata(g.transactions[0])
    coin_base_tx.update_mining_address(coin_base_reward_addr)

    # Remove all other transaction except CoinBase txn
    del g.transactions[:]

    g.pbdata.transactions.extend([coin_base_tx.pbdata])
    g.blockheader.generate_headerhash(dev_config)

    return g
Пример #16
0
def valid_payment_permission(public_stub, master_address_state, payment_xmss,
                             json_slave_txn):
    access_type = master_address_state.get_slave_permission(payment_xmss.pk)

    if access_type == -1:
        tx = Transaction.from_json(json_slave_txn)
        public_stub.PushTransaction(request=xrd_pb2.PushTransactionReq(
            transaction_signed=tx.pbdata))
        return None

    if access_type == 0:
        return True

    return False
Пример #17
0
def tx_inspect(ctx, txblob):
    """
    Inspected a transaction blob
    """
    tx = None
    try:
        txbin = parse_hexblob(txblob)
        pbdata = xrd_pb2.Transaction()
        pbdata.ParseFromString(txbin)
        tx = Transaction.from_pbdata(pbdata)
    except Exception as e:
        click.echo("tx blob is not valid")
        quit(1)

    tmp_json = tx.to_json()
    # FIXME: binary fields are represented in base64. Improve output
    print(tmp_json)
Пример #18
0
    def get_last_txs(state: State):
        try:
            last_txn = LastTransactions.deserialize(
                state._db.get_raw(b'last_txn'))
        except KeyError:
            return []
        except Exception as e:  # noqa
            logger.warning("[get_last_txs] Exception during call %s", e)
            return []

        txs = []
        for tx_metadata in last_txn.tx_metadata:
            data = tx_metadata.transaction
            tx = Transaction.from_pbdata(data)
            txs.append(tx)

        return txs
Пример #19
0
    def _update_last_tx(state: State, block: Block, batch):
        if len(block.transactions) == 0:
            return
        last_txn = LastTransactions()

        try:
            last_txn = LastTransactions.deserialize(
                state._db.get_raw(b'last_txn'))
        except KeyError:
            pass

        for protobuf_txn in block.transactions[-20:]:
            txn = Transaction.from_pbdata(protobuf_txn)
            if isinstance(txn, CoinBase):
                continue
            last_txn.add(txn, block.block_number, block.timestamp)

        state._db.put_raw(b'last_txn', last_txn.serialize(), batch)
Пример #20
0
    def remove_tx_in_block_from_pool(self, block_obj: Block):
        for protobuf_tx in block_obj.transactions[1:]:  # Ignore first transaction, as it is a coinbase txn
            tx = Transaction.from_pbdata(protobuf_tx)
            if tx.ots_key < config.dev.max_ots_tracking_index:
                idx = self.get_tx_index_from_pool(tx.txhash)
                if idx > -1:
                    del self.transaction_pool[idx]
            else:
                i = 0
                while i < len(self.transaction_pool):
                    txn = self.transaction_pool[i][1].transaction
                    if txn.PK == tx.PK:
                        if txn.ots_key >= config.dev.max_ots_tracking_index:
                            if txn.ots_key <= tx.ots_key:
                                del self.transaction_pool[i]
                                continue
                    i += 1

        heapq.heapify(self.transaction_pool)
Пример #21
0
    def test_from_json(self, m_logger):
        tx = Transaction.from_json(test_json_MessageTransaction)
        tx.sign(self.alice)

        self.assertIsInstance(tx, MessageTransaction)

        # Test that common Transaction components were copied over.
        self.assertEqual('010300a1da274e68c88b0ccf448e0b1916fa789b01eb2ed4e9ad565ce264c9390782a9c61ac02f',
                         bin2hstr(tx.addr_from))
        self.assertEqual('01030038ea6375069f8272cc1a6601b3c76c21519455603d370036b97c779ada356'
                         '5854e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e',
                         bin2hstr(tx.PK))
        self.assertEqual(b'Test Message', tx.message_hash)
        self.assertEqual('cbe7c40a86e82b8b6ac4e7df812f882183bd85d60f335cd83483d6831e61f4ec', bin2hstr(tx.txhash))
        self.assertEqual(10, tx.ots_key)

        self.assertEqual(test_signature_MessageTransaction, bin2hstr(tx.signature))

        self.assertEqual(1, tx.fee)
Пример #22
0
    def handle_token_transaction(source, message: xrdlegacy_pb2.LegacyMessage):
        """
        Token Transaction
        This function processes whenever a Transaction having
        subtype TOKEN is received.
        :return:
        """
        P2PBaseObserver._validate_message(message,
                                          xrdlegacy_pb2.LegacyMessage.TK)
        try:
            tx = Transaction.from_pbdata(message.tkData)
        except Exception as e:
            logger.error(
                'Token Txn rejected - unable to decode serialised data - closing connection'
            )
            logger.exception(e)
            source.loseConnection()
            return

        if source.factory.master_mr.isRequested(tx.get_message_hash(), source):
            source.factory.add_unprocessed_txn(tx, source.peer.ip)
Пример #23
0
    def handle_tx(source, message: xrdlegacy_pb2.LegacyMessage):
        """
        Transaction
        Executed whenever a new TX type message is received.
        :return:
        """
        P2PBaseObserver._validate_message(message,
                                          xrdlegacy_pb2.LegacyMessage.TX)
        try:
            tx = Transaction.from_pbdata(message.txData)
        except Exception as e:
            logger.error(
                'Message Txn rejected - unable to decode serialised data - closing connection'
            )
            logger.exception(e)
            source.loseConnection()
            return

        # NOTE: Connects to MR
        if source.factory.master_mr.isRequested(tx.get_message_hash(), source):
            source.factory.add_unprocessed_txn(tx, source.peer.ip)
Пример #24
0
    def handle_lattice(source, message: xrdlegacy_pb2.LegacyMessage):
        """
        Receives Lattice Public Key Transaction
        :param source:
        :param message:
        :return:
        """
        P2PBaseObserver._validate_message(message,
                                          xrdlegacy_pb2.LegacyMessage.LT)
        try:
            tx = Transaction.from_pbdata(message.ltData)
        except Exception as e:
            logger.error(
                'lattice_public_key rejected - unable to decode serialised data - closing connection'
            )
            logger.exception(e)
            source.loseConnection()
            return

        if source.factory.master_mr.isRequested(tx.get_message_hash(), source):
            source.factory.add_unprocessed_txn(tx, source.peer.ip)
Пример #25
0
    def handle_multi_sig_vote(source, message: xrdlegacy_pb2.LegacyMessage):
        """
        Handles Multi Sig Transaction
        :param source:
        :param message:
        :return:
        """
        P2PBaseObserver._validate_message(message,
                                          xrdlegacy_pb2.LegacyMessage.MV)
        try:
            tx = Transaction.from_pbdata(message.mvData)
        except Exception as e:
            logger.error(
                'multi_sig_vote txn rejected - unable to decode serialised data - closing connection'
            )
            logger.exception(e)
            source.loseConnection()
            return

        if source.factory.master_mr.isRequested(tx.get_message_hash(), source):
            source.factory.add_unprocessed_txn(tx, source.peer.ip)
Пример #26
0
    def create_block(self, last_block, mining_nonce, tx_pool: TransactionPool,
                     miner_address) -> Optional[Block]:
        seed_block = self._chain_manager.get_block_by_number(
            self._qn.get_seed_height(last_block.block_number + 1))
        dev_config = self._chain_manager.get_config_by_block_number(
            block_number=last_block.block_number + 1)

        dummy_block = Block.create(dev_config=dev_config,
                                   block_number=last_block.block_number + 1,
                                   prev_headerhash=last_block.headerhash,
                                   prev_timestamp=last_block.timestamp,
                                   transactions=[],
                                   miner_address=miner_address,
                                   seed_height=seed_block.block_number,
                                   seed_hash=seed_block.headerhash)
        dummy_block.set_nonces(dev_config, mining_nonce, 0)

        t_pool2 = tx_pool.transactions

        block_size = dummy_block.size
        block_size_limit = self._chain_manager.get_block_size_limit(
            last_block, dev_config)

        transactions = []
        state_container = self._chain_manager.new_state_container(
            set(), last_block.block_number, True, None)
        for tx_set in t_pool2:
            tx = tx_set[1].transaction

            # Skip Transactions for later, which doesn't fit into block
            if block_size + tx.size + dev_config.tx_extra_overhead > block_size_limit:
                continue

            if not self._chain_manager.update_state_container(
                    tx, state_container):
                logger.error("[create_block] Error updating state_container")
                return None

            if not tx.validate_all(state_container, check_nonce=False):
                if not state_container.revert_update():
                    return None
                tx_pool.remove_tx_from_pool(tx)
                continue
            if not self._chain_manager.apply_txn(tx, state_container):
                logger.error("[create_block] Failed to apply txn")
                if not state_container.revert_update():
                    return None
                continue

            addr_from_pk_state = state_container.addresses_state[tx.addr_from]
            addr_from_pk = Transaction.get_slave(tx)
            if addr_from_pk:
                addr_from_pk_state = state_container.addresses_state[
                    addr_from_pk]

            tx._data.nonce = addr_from_pk_state.nonce
            block_size += tx.size + dev_config.tx_extra_overhead
            transactions.append(tx)

        block = Block.create(dev_config=dev_config,
                             block_number=last_block.block_number + 1,
                             prev_headerhash=last_block.headerhash,
                             prev_timestamp=last_block.timestamp,
                             transactions=transactions,
                             miner_address=miner_address,
                             seed_height=seed_block.block_number,
                             seed_hash=seed_block.headerhash)

        return block
Пример #27
0
    def validate(self, chain_manager, future_blocks: OrderedDict) -> bool:
        if chain_manager.get_block_is_duplicate(self):
            logger.warning('Duplicate Block #%s %s', self.block_number,
                           bin2hstr(self.headerhash))
            return False

        parent_block = chain_manager.get_block(self.prev_headerhash)
        dev_config = chain_manager.get_config_by_block_number(
            self.block_number)

        # If parent block not found in state, then check if its in the future block list
        if not parent_block:
            try:
                parent_block = future_blocks[self.prev_headerhash]
            except KeyError:
                logger.warning('Parent block not found')
                logger.warning('Parent block headerhash %s',
                               bin2hstr(self.prev_headerhash))
                return False

        if not self._validate_parent_child_relation(parent_block):
            logger.warning('Failed to validate blocks parent child relation')
            return False

        if not chain_manager.validate_mining_nonce(self.blockheader,
                                                   dev_config):
            logger.warning('Failed PoW Validation')
            return False

        if len(self.transactions) == 0:
            return False

        try:
            state_container = chain_manager.new_state_container(
                set(), self.block_number, False, None)

            coinbase_txn = Transaction.from_pbdata(self.transactions[0])
            coinbase_amount = coinbase_txn.amount

            if not coinbase_txn.validate_all(state_container):
                return False

        except Exception as e:
            logger.warning('Exception %s', e)
            return False

        # Build transaction merkle tree, calculate fee reward, and then see if BlockHeader also agrees.
        hashedtransactions = []

        for tx in self.transactions:
            tx = Transaction.from_pbdata(tx)
            hashedtransactions.append(tx.txhash)

        fee_reward = 0
        for index in range(1, len(self.transactions)):
            fee_reward += self.transactions[index].fee

        qn = Qryptonight()
        seed_block = chain_manager.get_block_by_number(
            qn.get_seed_height(self.block_number))

        self.blockheader._seed_height = seed_block.block_number
        self.blockheader._seed_hash = seed_block.headerhash

        if not self.blockheader.validate(fee_reward, coinbase_amount,
                                         merkle_tx_hash(hashedtransactions),
                                         dev_config):
            return False

        return True
Пример #28
0
def gen_blocks(block_count, state, miner_address):
    blocks = []
    block = None
    with mock.patch('xrd.core.misc.ntp.getTime') as time_mock:
        time_mock.return_value = 1615270948
        addresses_state = dict()
        for i in range(0, block_count):
            if i == 0:
                block = GenesisBlock()
                for genesis_balance in GenesisBlock().genesis_balance:
                    bytes_addr = genesis_balance.address
                    addresses_state[
                        bytes_addr] = OptimizedAddressState.get_default(
                            bytes_addr)
                    addresses_state[
                        bytes_addr]._data.balance = genesis_balance.balance
            else:
                block = Block.create(dev_config=config.dev,
                                     block_number=i,
                                     prev_headerhash=block.headerhash,
                                     prev_timestamp=block.timestamp,
                                     transactions=[],
                                     miner_address=miner_address,
                                     seed_height=None,
                                     seed_hash=None)
                addresses_set = ChainManager.set_affected_address(block)
                coin_base_tx = Transaction.from_pbdata(block.transactions[0])
                coin_base_tx.set_affected_address(addresses_set)

                chain_manager = ChainManager(state)
                state_container = chain_manager.new_state_container(
                    addresses_set, block.block_number, False, None)
                coin_base_tx.apply(state, state_container)

                for tx_idx in range(1, len(block.transactions)):
                    tx = Transaction.from_pbdata(block.transactions[tx_idx])
                    if not chain_manager.update_state_container(
                            tx, state_container):
                        return False
                    tx.apply(state, state_container)

                block.set_nonces(dev_config=config.dev,
                                 mining_nonce=10,
                                 extra_nonce=0)
            blocks.append(block)

            metadata = BlockMetadata()
            metadata.set_block_difficulty(StringToUInt256('256'))
            BlockMetadata.put_block_metadata(state, block.headerhash, metadata,
                                             None)

            Block.put_block(state, block, None)
            bm = xrd_pb2.BlockNumberMapping(
                headerhash=block.headerhash,
                prev_headerhash=block.prev_headerhash)

            Block.put_block_number_mapping(state, block.block_number, bm, None)
            state.update_mainchain_height(block.block_number, None)
            OptimizedAddressState.put_optimized_addresses_state(
                state, addresses_state)

    return blocks
Пример #29
0
    def GetObject(self, request: xrd_pb2.GetObjectReq,
                  context) -> xrd_pb2.GetObjectResp:
        logger.debug("[PublicAPI] GetObject")
        answer = xrd_pb2.GetObjectResp()
        answer.found = False

        # FIXME: We need a unified way to access and validate data.
        query = bytes(
            request.query
        )  # query will be as a string, if Q is detected convert, etc.

        try:
            if AddressState.address_is_valid(query):
                if self.xrdnode.get_address_is_used(query):
                    address_state = self.xrdnode.get_optimized_address_state(
                        query)
                    if address_state is not None:
                        answer.found = True
                        answer.address_state.CopyFrom(address_state.pbdata)
                        return answer
        except ValueError:
            pass

        transaction_block_number = self.xrdnode.get_transaction(query)
        transaction = None
        blockheader = None
        if transaction_block_number:
            transaction, block_number = transaction_block_number
            answer.found = True
            block = self.xrdnode.get_block_from_index(block_number)
            blockheader = block.blockheader.pbdata
            timestamp = block.blockheader.timestamp
        else:
            transaction_timestamp = self.xrdnode.get_unconfirmed_transaction(
                query)
            if transaction_timestamp:
                transaction, timestamp = transaction_timestamp
                answer.found = True

        if transaction:
            txextended = xrd_pb2.TransactionExtended(
                header=blockheader,
                tx=transaction.pbdata,
                addr_from=transaction.addr_from,
                size=transaction.size,
                timestamp_seconds=timestamp)
            answer.transaction.CopyFrom(txextended)
            return answer

        # NOTE: This is temporary, indexes are accepted for blocks
        try:
            block = self.xrdnode.get_block_from_hash(query)
            if block is None or (block.block_number == 0
                                 and block.prev_headerhash !=
                                 config.user.genesis_prev_headerhash):
                query_str = query.decode()
                query_index = int(query_str)
                block = self.xrdnode.get_block_from_index(query_index)
                if not block:
                    return answer

            answer.found = True
            block_extended = xrd_pb2.BlockExtended()
            block_extended.header.CopyFrom(block.blockheader.pbdata)
            block_extended.size = block.size
            for transaction in block.transactions:
                tx = Transaction.from_pbdata(transaction)
                extended_tx = xrd_pb2.TransactionExtended(
                    tx=transaction,
                    addr_from=tx.addr_from,
                    size=tx.size,
                    timestamp_seconds=block.blockheader.timestamp)
                block_extended.extended_transactions.extend([extended_tx])
            answer.block_extended.CopyFrom(block_extended)
            return answer
        except Exception:
            pass

        return answer
    def test_messageTxn_sign(self):
        with set_xrd_dir('wallet_ver1'):
            with State() as db_state:
                p2p_factory = Mock(spec=P2PFactory)
                p2p_factory.pow = Mock(spec=POW)
                chain_manager = ChainManager(db_state)

                xrdnode = xrdNode(mining_address=b'')
                xrdnode.set_chain_manager(chain_manager)
                xrdnode._p2pfactory = p2p_factory
                xrdnode._pow = p2p_factory.pow
                xrdnode._peer_addresses = ['127.0.0.1', '192.168.1.1']

                service = PublicAPIService(xrdnode)

                context = Mock(spec=ServicerContext)

                alice = get_alice_xmss()
                my_message = b'Hello xrd!'

                request = xrd_pb2.MessageTxnReq(
                    message=my_message,
                    fee=12,
                    xmss_pk=alice.pk
                )

                response = service.GetMessageTxn(request=request, context=context)
                context.set_code.assert_not_called()
                context.set_details.assert_not_called()

                self.assertIsNotNone(response)
                self.assertIsNotNone(response.extended_transaction_unsigned.tx)
                self.assertEqual('message', response.extended_transaction_unsigned.tx.WhichOneof('transactionType'))

                self.assertEqual(12, response.extended_transaction_unsigned.tx.fee)
                self.assertEqual(alice.pk, response.extended_transaction_unsigned.tx.public_key)
                self.assertEqual(0, response.extended_transaction_unsigned.tx.nonce)
                self.assertEqual(b'', response.extended_transaction_unsigned.tx.signature)
                self.assertEqual(b'', response.extended_transaction_unsigned.tx.transaction_hash)
                self.assertEqual(my_message, response.extended_transaction_unsigned.tx.message.message_hash)

                tmp_hash_pre = response.extended_transaction_unsigned.tx.master_addr
                tmp_hash_pre += response.extended_transaction_unsigned.tx.fee.to_bytes(8, byteorder='big', signed=False)
                tmp_hash_pre += response.extended_transaction_unsigned.tx.message.message_hash

                tmp_hash = sha256(tmp_hash_pre)
                hash_found = bin2hstr(Transaction.from_pbdata(response.extended_transaction_unsigned.tx).
                                      get_data_hash())
                self.assertEqual(hash_found,
                                 bin2hstr(tmp_hash))

                signed_transaction = response.extended_transaction_unsigned.tx
                signed_transaction.signature = alice.sign(tmp_hash)

                req_push = xrd_pb2.PushTransactionReq(transaction_signed=signed_transaction)

                resp_push = service.PushTransaction(req_push, context=context)
                context.set_code.assert_not_called()
                context.set_details.assert_not_called()

                self.assertIsNotNone(resp_push)
                self.assertEqual(xrd_pb2.PushTransactionResp.SUBMITTED,
                                 resp_push.error_code)
                self.assertEqual('b7ee814a548a6bbb8d97b2d3a0eb9e1f8b6ceee49b764e3c7b23d104aca6abeb',
                                 bin2hstr(resp_push.tx_hash))