def test_handle_message_transaction(self, m_Transaction):
        """
        This handler handles a MessageTransaction type Transaction.
        :param m_Transaction:
        :return:
        """
        m_Transaction.from_pbdata.return_value = Mock(
            autospec=MessageTransaction, txhash=b'12345')
        self.channel.factory.master_mr.isRequested.return_value = True  # Yes, this is a Message which we have requested
        self.channel.factory.buffered_chain.tx_pool.pending_tx_pool_hash = [
        ]  # No, we haven't processed this TX before

        mtData = qrl_pb2.Transaction()
        msg = make_message(func_name=qrllegacy_pb2.LegacyMessage.MT,
                           mtData=mtData)

        P2PTxManagement.handle_message_transaction(self.channel, msg)

        self.channel.factory.add_unprocessed_txn.assert_called()

        # What if we ended up parsing a Transaction that we never requested in the first place?
        self.channel.factory.add_unprocessed_txn.reset_mock()
        self.channel.factory.master_mr.isRequested.return_value = False
        P2PTxManagement.handle_message_transaction(self.channel, msg)
        self.channel.factory.add_unprocessed_txn.assert_not_called()
Exemple #2
0
    def test_tx_transfer_encrypted_wallet(self, mock_stub):
        tx_pbdata_serialized_to_string = b"\n\x02\\n\x1aC\x01\x02\x00\x80\x9dg/U\xb1N\xf2_\x0e~j%\xb2\x15\x05\xa7y\x19\x8f\xc0>\x05`\x90\xe3>\xaa\x9a(\xd3\xc7U\x91\xbab\x90{\xaa^\xadQ\xca\xbf\xd3\xbc\xd9\x93\xf0:D\xca\xd8v\x97\x08\xa8x\x9c-\n4\xd6e:,\n'\x01\x06\x00\x95O\x16\xafx\xe3\x94Y\rc\x7f\x10D\xcd\x9f\xaf<\xc7\xf4\xa2\x93f\xaa\r\x8c\xa3 \xe40\x0bZ\xfe\xb0xy\xbb\x12\x01\x00"  # noqa
        mock_tx = qrl_pb2.Transaction()
        mock_tx.ParseFromString(tx_pbdata_serialized_to_string)

        m_transferCoinsResp = mock.MagicMock(name='a fake transferCoinsResp')
        m_transferCoinsResp.extended_transaction_unsigned.tx = mock_tx

        m_pushTransactionResp = mock.MagicMock(name='a fake pushTransactionResp', error_code=3)

        attrs = {
            "name": "my fake stub",
            "TransferCoins.return_value": m_transferCoinsResp,
            "PushTransaction.return_value": m_pushTransactionResp
        }
        mock_stub_instance = mock.MagicMock(**attrs)

        mock_stub.name = 'a fake qrl_pb2_grpc.PublicAPIStub'
        mock_stub.return_value = mock_stub_instance

        # Simplest use case
        self.runner.invoke(qrl_cli, ["wallet_encrypt"], input='password\npassword\n')
        result = self.runner.invoke(qrl_cli, ["tx_transfer", "--src=0", "--master=", "--dsts={}".format(qaddr_1),
                                              "--amounts=1", "--fee=0", "--ots_key_index=0"],
                                    input='password\n')
        self.assertEqual(result.exit_code, 0)
        self.assertIn('a fake pushTransactionResp', result.output.strip())
Exemple #3
0
def tx_push(ctx, txblob):
    """
    Sends a signed transaction blob to a node
    """
    tx = None
    try:
        txbin = parse_hexblob(txblob)
        pbdata = qrl_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 = qrl_pb2.PushTransactionReq(
        transaction_signed=tx.pbdata)
    pushTransactionResp = stub.PushTransaction(pushTransactionReq,
                                               timeout=CONNECTION_TIMEOUT)
    print(pushTransactionResp.error_code)
Exemple #4
0
    def test_getTransaction(self):
        with set_qrl_dir("wallet_ver1"):
            walletd = WalletD()
            service = WalletAPIService(walletd)

            tx = qrl_pb2.Transaction()
            tx.fee = 10
            tx.transaction_hash = b'1234'
            tx.message.message_hash = b'hello'
            pk = '01020016ecb9f39b9f4275d5a49e232346a15ae2fa8c50a2927daeac189b8c5f2d1' \
                 '8bc4e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e'
            tx.public_key = bytes(hstr2bin(pk))

            walletd._public_stub.GetTransaction = Mock(
                return_value=qrl_pb2.GetTransactionResp(tx=tx,
                                                        confirmations=10))

            resp = service.GetTransaction(
                qrlwallet_pb2.TransactionReq(tx_hash=tx.transaction_hash),
                context=None)

            self.assertEqual(resp.code, 0)
            self.assertIsNotNone(resp.tx)
            self.assertEqual(bin2hstr(tx.transaction_hash),
                             resp.tx.transaction_hash)
 def test_handle_slave_error_parsing_transaction(self, m_Transaction,
                                                 m_logger):
     m_Transaction.from_pbdata.side_effect = Exception
     msg = make_message(func_name=qrllegacy_pb2.LegacyMessage.SL,
                        slData=qrl_pb2.Transaction())
     P2PTxManagement.handle_slave(self.channel, msg)
     self.channel.factory.add_unprocessed_txn.assert_not_called()
     m_logger.exception.assert_called()
     self.channel.loseConnection.assert_called()
Exemple #6
0
    def create(staking_address: bytes, block_number: int, reveal_hash: bytes,
               prevblock_headerhash: bytes, transactions: list,
               duplicate_transactions: OrderedDict, vote: VoteMetadata,
               signing_xmss: XMSS, nonce: int):

        block = Block()
        block._data.transactions.extend([qrl_pb2.Transaction()
                                         ])  # FIXME: Empty for coinbase?

        # Process transactions
        hashedtransactions = []
        fee_reward = 0

        for tx in transactions:
            if tx.subtype == qrl_pb2.Transaction.TRANSFER:
                fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            block._data.transactions.extend(
                [tx.pbdata])  # copy memory rather than sym link

        if not hashedtransactions:
            hashedtransactions = [sha256(b'')]

        txs_hash = merkle_tx_hash(
            hashedtransactions)  # FIXME: Find a better name, type changes

        for tx in duplicate_transactions.values(
        ):  # TODO: Add merkle hash for dup txn
            block._data.duplicate_transactions.extend([tx.pbdata])

        for staker in vote.stake_validator_vote:  # TODO: Add merkle hash for vote
            block._data.vote.extend([vote.stake_validator_vote[staker].pbdata])

        tmp_blockheader = BlockHeader.create(
            staking_address=staking_address,
            blocknumber=block_number,
            reveal_hash=reveal_hash,
            prev_blockheaderhash=prevblock_headerhash,
            hashedtransactions=txs_hash,
            fee_reward=fee_reward)

        block._data.header.MergeFrom(tmp_blockheader.pbdata)

        # Prepare coinbase tx
        coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss)
        coinbase_tx.pbdata.nonce = nonce
        coinbase_tx.sign(signing_xmss)  # Sign after nonce has been set

        # Replace first tx
        block._data.transactions[0].CopyFrom(coinbase_tx.pbdata)

        return block
Exemple #7
0
def tx_sign(ctx, src, txblob):
    """
    Sign a tx blob
    """
    txbin = bytes(hstr2bin(txblob))
    pbdata = qrl_pb2.Transaction()
    pbdata.ParseFromString(txbin)
    tx = Transaction.from_pbdata(pbdata)

    address_src, address_xmss = _select_wallet(ctx, src)
    tx.sign(address_xmss)

    txblob = bin2hstr(tx.pbdata.SerializeToString())
    print(txblob)
    def test_handle_message_transaction_invalid_transaction(
            self, m_Transaction, logger):
        """
        If the Transaction was so malformed that parsing it caused an exception, the peer should be disconnected.
        :param m_Transaction:
        :param logger:
        :return:
        """
        m_Transaction.from_pbdata.side_effect = Exception

        mtData = qrl_pb2.Transaction()
        msg = make_message(func_name=qrllegacy_pb2.LegacyMessage.MT,
                           mtData=mtData)

        P2PTxManagement.handle_message_transaction(self.channel, msg)

        self.channel.loseConnection.assert_called()
Exemple #9
0
    def test_tx_transfer_invalid_input(self, mock_stub):
        tx_pbdata_serialized_to_string = b"\n\x02\\n\x1aC\x01\x02\x00\x80\x9dg/U\xb1N\xf2_\x0e~j%\xb2\x15\x05\xa7y\x19\x8f\xc0>\x05`\x90\xe3>\xaa\x9a(\xd3\xc7U\x91\xbab\x90{\xaa^\xadQ\xca\xbf\xd3\xbc\xd9\x93\xf0:D\xca\xd8v\x97\x08\xa8x\x9c-\n4\xd6e:,\n'\x01\x06\x00\x95O\x16\xafx\xe3\x94Y\rc\x7f\x10D\xcd\x9f\xaf<\xc7\xf4\xa2\x93f\xaa\r\x8c\xa3 \xe40\x0bZ\xfe\xb0xy\xbb\x12\x01\x00"  # noqa
        mock_tx = qrl_pb2.Transaction()
        mock_tx.ParseFromString(tx_pbdata_serialized_to_string)

        m_transfer_coins_resp = mock.MagicMock(name='a fake transferCoinsResp')
        m_transfer_coins_resp.extended_transaction_unsigned.tx = mock_tx

        m_push_transaction_resp = mock.MagicMock(name='a fake pushTransactionResp', error_code=3)

        attrs = {
            "name": "my fake stub",
            "TransferCoins.return_value": m_transfer_coins_resp,
            "PushTransaction.return_value": m_push_transaction_resp
        }
        mock_stub_instance = mock.MagicMock(**attrs)

        mock_stub.name = 'a fake qrl_pb2_grpc.PublicAPIStub'
        mock_stub.return_value = mock_stub_instance

        # What if I use a ots_key_index larger than the wallet's tree height?
        result = self.runner.invoke(qrl_cli, [
            "tx_transfer",
            "--src=0",
            "--master=",
            "--dsts={}".format(qaddr_1),
            "--amounts=1",
            "--fee=0",
            "--ots_key_index=16"], input='16')
        self.assertEqual(result.exit_code, 1)
        self.assertIn('OTS key index must be between 0 and 15', result.output.strip())

        # dsts and amounts with different lengths should fail
        dsts = [qaddr_1, qaddr_2, qaddr_3]
        amounts = ["1", "2"]
        result = self.runner.invoke(qrl_cli, [
            "tx_transfer",
            "--src=0",
            "--master=",
            "--dsts={}".format(" ".join(dsts)),
            "--amounts={}".format(" ".join(amounts)),
            "--fee=0",
            "--ots_key_index=0"
        ])
        self.assertEqual(result.exit_code, 1)
        self.assertIn('dsts and amounts should be the same length', result.output.strip())
Exemple #10
0
def tx_inspect(ctx, txblob):
    """
    Inspected a transaction blob
    """
    tx = None
    try:
        txbin = parse_hexblob(txblob)
        pbdata = qrl_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)
    def create(block_number: int, prevblock_headerhash: bytes,
               transactions: list, signing_xmss: XMSS, master_address: bytes,
               nonce: int):

        block = Block()
        block._data.transactions.extend([qrl_pb2.Transaction()
                                         ])  # FIXME: Empty for coinbase?

        # Process transactions
        hashedtransactions = []
        fee_reward = 0

        for tx in transactions:
            fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            block._data.transactions.extend(
                [tx.pbdata])  # copy memory rather than sym link

        if not hashedtransactions:
            hashedtransactions = [sha256(b'')]

        txs_hash = merkle_tx_hash(
            hashedtransactions)  # FIXME: Find a better name, type changes

        tmp_blockheader = BlockHeader.create(
            blocknumber=block_number,
            PK=signing_xmss.pk,
            prev_blockheaderhash=prevblock_headerhash,
            hashedtransactions=txs_hash,
            fee_reward=fee_reward)

        block._data.header.MergeFrom(tmp_blockheader.pbdata)

        # Prepare coinbase tx
        coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss,
                                      master_address)
        coinbase_tx.pbdata.nonce = nonce
        coinbase_tx.sign(signing_xmss)  # Sign after nonce has been set

        # Replace first tx
        block._data.transactions[0].CopyFrom(coinbase_tx.pbdata)

        return block
Exemple #12
0
def tx_push(ctx, txblob):
    tx = None
    try:
        txbin = bytes(hstr2bin(txblob))
        pbdata = qrl_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)

    channel = grpc.insecure_channel(ctx.obj.node_public_address)
    stub = qrl_pb2_grpc.PublicAPIStub(channel)
    pushTransactionReq = qrl_pb2.PushTransactionReq(transaction_signed=tx.pbdata)
    pushTransactionResp = stub.PushTransaction(pushTransactionReq, timeout=5)
    print(pushTransactionResp.error_code)
Exemple #13
0
 def deserialize(data):
     pbdata = qrl_pb2.Transaction()
     pbdata.ParseFromString(bytes(data))
     tx = Transaction(pbdata)
     return tx
Exemple #14
0
 def from_json(json_data):
     pbdata = qrl_pb2.Transaction()
     Parse(json_data, pbdata)
     return Transaction.from_pbdata(pbdata)
Exemple #15
0
 def __init__(self, protobuf_transaction=None):
     self._data = protobuf_transaction  # This object cointains persistable data
     if protobuf_transaction is None:
         self._data = qrl_pb2.Transaction()
Exemple #16
0
    def test_tx_transfer(self, mock_stub):
        tx_pbdata_serialized_to_string = b"\n\x02\\n\x1aC\x01\x02\x00\x80\x9dg/U\xb1N\xf2_\x0e~j%\xb2\x15\x05\xa7y\x19\x8f\xc0>\x05`\x90\xe3>\xaa\x9a(\xd3\xc7U\x91\xbab\x90{\xaa^\xadQ\xca\xbf\xd3\xbc\xd9\x93\xf0:D\xca\xd8v\x97\x08\xa8x\x9c-\n4\xd6e:,\n'\x01\x06\x00\x95O\x16\xafx\xe3\x94Y\rc\x7f\x10D\xcd\x9f\xaf<\xc7\xf4\xa2\x93f\xaa\r\x8c\xa3 \xe40\x0bZ\xfe\xb0xy\xbb\x12\x01\x00"  # noqa
        mock_tx = qrl_pb2.Transaction()
        mock_tx.ParseFromString(tx_pbdata_serialized_to_string)

        m_transfer_coins_resp = mock.MagicMock(name='a fake transferCoinsResp')
        m_transfer_coins_resp.extended_transaction_unsigned.tx = mock_tx
        m_push_transaction_resp = mock.MagicMock(name='a fake pushTransactionResp', error_code=3)

        attrs = {
            "name": "my fake stub",
            "TransferCoins.return_value": m_transfer_coins_resp,
            "PushTransaction.return_value": m_push_transaction_resp
        }
        mock_stub_instance = mock.MagicMock(**attrs)

        mock_stub.name = 'a fake qrl_pb2_grpc.PublicAPIStub'
        mock_stub.return_value = mock_stub_instance

        wallet = open_wallet()

        # Simplest use case
        result = self.runner.invoke(qrl_cli, [
            "tx_transfer",
            "--src=0",
            "--master=",
            "--dsts={}".format(qaddr_1),
            "--amounts=1",
            "--fee=0",
            "--ots_key_index=0"
        ])
        self.assertEqual(result.exit_code, 0)
        print(result.output)
        self.assertIn('a fake pushTransactionResp', result.output.strip())

        # Should work with src=Qaddress as well
        result = self.runner.invoke(qrl_cli, [
            "tx_transfer",
            "--src={}".format(wallet["addresses"][0]["address"]),
            "--master=",
            "--dsts={}".format(qaddr_1),
            "--amounts=1",
            "--fee=0",
            "--ots_key_index=0"
        ])
        self.assertEqual(result.exit_code, 0)
        self.assertIn('a fake pushTransactionResp', result.output.strip())

        # Master should also work with a Qaddress.
        result = self.runner.invoke(qrl_cli, [
            "tx_transfer",
            "--src={}".format(wallet["addresses"][0]["address"]),
            "--master={}".format(qaddr_2),
            "--dsts={}".format(qaddr_1),
            "--amounts=1",
            "--fee=0",
            "--ots_key_index=0"
        ])
        self.assertEqual(result.exit_code, 0)
        self.assertIn('a fake pushTransactionResp', result.output.strip())

        # Multiple dsts should work too
        dsts = [qaddr_1, qaddr_2, qaddr_3]
        amounts = ["1", "2", "3"]
        result = self.runner.invoke(qrl_cli, [
            "tx_transfer",
            "--src=0",
            "--master=",
            "--dsts={}".format(" ".join(dsts)),
            "--amounts={}".format(" ".join(amounts)),
            "--fee=0",
            "--ots_key_index=0"
        ])
        self.assertEqual(result.exit_code, 0)
        self.assertIn('a fake pushTransactionResp', result.output.strip())
 def test_handle_slave(self, m_Transaction, m_logger):
     msg = make_message(func_name=qrllegacy_pb2.LegacyMessage.SL,
                        slData=qrl_pb2.Transaction())
     P2PTxManagement.handle_slave(self.channel, msg)
     self.channel.factory.add_unprocessed_txn.assert_called()