zcashd/qa/rpc-tests/wallet_sendmany_any_taddr.py

130 lines
4.8 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright (c) 2020 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
connect_nodes_bi,
start_nodes,
sync_blocks,
wait_and_assert_operationid_status,
)
TX_EXPIRY_DELTA = 10
TX_EXPIRING_SOON_THRESHOLD = 3
# Test ANY_TADDR special string in z_sendmany
class WalletSendManyAnyTaddr(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(self.num_nodes, self.options.tmpdir,
[[
"-txexpirydelta=%d" % TX_EXPIRY_DELTA,
]] * self.num_nodes)
def run_test(self):
# Sanity-check the test harness
assert_equal(self.nodes[0].getblockcount(), 200)
# Create the addresses we will be using.
recipient = self.nodes[1].z_getnewaddress()
node2zaddr = self.nodes[2].z_getnewaddress()
node2taddr1 = self.nodes[2].getnewaddress()
node3zaddr = self.nodes[3].z_getnewaddress()
node3taddr1 = self.nodes[3].getnewaddress()
node3taddr2 = self.nodes[3].getnewaddress()
# Prepare some non-coinbase UTXOs
wait_and_assert_operationid_status(
self.nodes[3],
self.nodes[3].z_shieldcoinbase("*", node3zaddr, 0)['opid'],
)
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
assert_equal(self.nodes[3].z_getbalance(node3zaddr), 250)
wait_and_assert_operationid_status(
self.nodes[3],
self.nodes[3].z_sendmany(
node3zaddr,
[
{'address': node3taddr1, 'amount': 60},
{'address': node3taddr2, 'amount': 75},
],
1
),
)
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
# Check the various balances.
assert_equal(self.nodes[1].z_getbalance(recipient), 0)
assert_equal(self.nodes[3].z_getbalance(node3taddr1), 60)
assert_equal(self.nodes[3].z_getbalance(node3taddr2), 75)
# We should be able to spend multiple UTXOs at once
wait_and_assert_operationid_status(
self.nodes[3],
self.nodes[3].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 100}], 1),
)
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
# The recipient has their funds!
assert_equal(self.nodes[1].z_getbalance(recipient), 100)
# Change is sent to a new t-address.
assert_equal(self.nodes[3].z_getbalance(node3taddr1), 0)
assert_equal(self.nodes[3].z_getbalance(node3taddr2), 0)
# Send from a change t-address.
wait_and_assert_operationid_status(
self.nodes[3],
self.nodes[3].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 20}], 1),
)
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
# The recipient has their funds!
assert_equal(self.nodes[1].z_getbalance(recipient), 120)
# Check that ANY_TADDR note selection doesn't attempt a double-spend
myopid = self.nodes[3].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 20}], 1)
wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "Insufficient funds: have 14.99998, need 20.00001")
# Create an expired transaction on node 3.
self.split_network()
expire_transparent = self.nodes[3].sendtoaddress(node2taddr1, 14)
assert(expire_transparent in self.nodes[3].getrawmempool())
self.sync_all()
assert_equal('waiting', self.nodes[2].gettransaction(expire_transparent)['status'])
self.nodes[0].generate(TX_EXPIRY_DELTA + TX_EXPIRING_SOON_THRESHOLD)
self.sync_all()
connect_nodes_bi(self.nodes, 1, 2)
sync_blocks(self.nodes[1:3])
assert_equal('expired', self.nodes[2].gettransaction(expire_transparent)['status'])
# Ensure that node 2 has no transparent funds.
self.nodes[2].generate(100) # To ensure node 2's pending coinbase is spendable
self.sync_all()
wait_and_assert_operationid_status(
self.nodes[2],
self.nodes[2].z_shieldcoinbase("*", node2zaddr, 0)['opid'],
)
self.sync_all()
assert_equal(0, self.nodes[2].getbalance())
# Check that ANY_TADDR doesn't select an expired output.
wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 13}]), "failed", "Insufficient funds: have 0.00, need 13.00001")
if __name__ == '__main__':
WalletSendManyAnyTaddr().main()