2019-12-04 07:29:16 -08:00
|
|
|
#!/usr/bin/env python3
|
2017-09-15 12:59:27 -07:00
|
|
|
# Copyright (c) 2017 The Zcash developers
|
|
|
|
# Distributed under the MIT software license, see the accompanying
|
2019-07-18 07:16:09 -07:00
|
|
|
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
2017-09-15 12:59:27 -07:00
|
|
|
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
|
|
from test_framework.authproxy import JSONRPCException
|
|
|
|
from test_framework.util import assert_equal, initialize_chain_clean, \
|
2017-12-12 23:38:46 -08:00
|
|
|
start_node, connect_nodes_bi, sync_blocks, sync_mempools, \
|
2020-12-17 11:39:58 -08:00
|
|
|
wait_and_assert_operationid_status, get_coinbase_address, DEFAULT_FEE
|
2017-09-15 12:59:27 -07:00
|
|
|
|
|
|
|
from decimal import Decimal
|
|
|
|
|
|
|
|
class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
2018-09-13 15:12:29 -07:00
|
|
|
def __init__(self, addr_type):
|
|
|
|
super(WalletShieldCoinbaseTest, self).__init__()
|
|
|
|
self.addr_type = addr_type
|
2017-09-15 12:59:27 -07:00
|
|
|
|
|
|
|
def setup_chain(self):
|
|
|
|
print("Initializing test directory "+self.options.tmpdir)
|
|
|
|
initialize_chain_clean(self.options.tmpdir, 4)
|
|
|
|
|
|
|
|
def setup_network(self, split=False):
|
2017-10-26 11:29:36 -07:00
|
|
|
args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe']
|
2017-09-15 12:59:27 -07:00
|
|
|
self.nodes = []
|
|
|
|
self.nodes.append(start_node(0, self.options.tmpdir, args))
|
|
|
|
self.nodes.append(start_node(1, self.options.tmpdir, args))
|
2019-07-19 05:10:13 -07:00
|
|
|
self.nodes.append(start_node(2, self.options.tmpdir, args))
|
2017-09-15 12:59:27 -07:00
|
|
|
connect_nodes_bi(self.nodes,0,1)
|
|
|
|
connect_nodes_bi(self.nodes,1,2)
|
|
|
|
connect_nodes_bi(self.nodes,0,2)
|
|
|
|
self.is_network_split=False
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
def run_test (self):
|
2019-12-04 07:29:16 -08:00
|
|
|
print("Mining blocks...")
|
2017-09-15 12:59:27 -07:00
|
|
|
|
|
|
|
self.nodes[0].generate(1)
|
|
|
|
self.nodes[0].generate(4)
|
2019-12-18 12:34:39 -08:00
|
|
|
self.sync_all()
|
2017-09-15 12:59:27 -07:00
|
|
|
walletinfo = self.nodes[0].getwalletinfo()
|
|
|
|
assert_equal(walletinfo['immature_balance'], 50)
|
|
|
|
assert_equal(walletinfo['balance'], 0)
|
|
|
|
self.sync_all()
|
|
|
|
self.nodes[2].generate(1)
|
|
|
|
self.nodes[2].generate(1)
|
|
|
|
self.nodes[2].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(101)
|
|
|
|
self.sync_all()
|
|
|
|
assert_equal(self.nodes[0].getbalance(), 50)
|
|
|
|
assert_equal(self.nodes[1].getbalance(), 10)
|
|
|
|
assert_equal(self.nodes[2].getbalance(), 30)
|
|
|
|
|
2018-03-10 02:19:44 -08:00
|
|
|
do_not_shield_taddr = get_coinbase_address(self.nodes[0], 1)
|
|
|
|
|
2017-09-15 12:59:27 -07:00
|
|
|
# Prepare to send taddr->zaddr
|
2018-03-10 02:19:44 -08:00
|
|
|
mytaddr = get_coinbase_address(self.nodes[0], 4)
|
2018-09-13 15:12:29 -07:00
|
|
|
myzaddr = self.nodes[0].z_getnewaddress(self.addr_type)
|
2017-09-15 12:59:27 -07:00
|
|
|
|
|
|
|
# Shielding will fail when trying to spend from watch-only address
|
|
|
|
self.nodes[2].importaddress(mytaddr)
|
|
|
|
try:
|
|
|
|
self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr)
|
2019-12-04 07:29:16 -08:00
|
|
|
except JSONRPCException as e:
|
2020-01-08 06:53:34 -08:00
|
|
|
errorString = e.error['message']
|
|
|
|
assert_equal("Could not find any coinbase funds to shield" in errorString, True)
|
2017-09-15 12:59:27 -07:00
|
|
|
|
|
|
|
# Shielding will fail because fee is negative
|
|
|
|
try:
|
|
|
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, -1)
|
2019-12-04 07:29:16 -08:00
|
|
|
except JSONRPCException as e:
|
2020-01-08 06:53:34 -08:00
|
|
|
errorString = e.error['message']
|
|
|
|
assert_equal("Amount out of range" in errorString, True)
|
|
|
|
|
2017-09-15 12:59:27 -07:00
|
|
|
# Shielding will fail because fee is larger than MAX_MONEY
|
|
|
|
try:
|
|
|
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('21000000.00000001'))
|
2019-12-04 07:29:16 -08:00
|
|
|
except JSONRPCException as e:
|
2020-01-08 06:53:34 -08:00
|
|
|
errorString = e.error['message']
|
|
|
|
assert_equal("Amount out of range" in errorString, True)
|
|
|
|
|
2017-09-15 12:59:27 -07:00
|
|
|
# Shielding will fail because fee is larger than sum of utxos
|
|
|
|
try:
|
|
|
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, 999)
|
2019-12-04 07:29:16 -08:00
|
|
|
except JSONRPCException as e:
|
2020-01-08 06:53:34 -08:00
|
|
|
errorString = e.error['message']
|
|
|
|
assert_equal("Insufficient coinbase funds" in errorString, True)
|
2017-09-15 12:59:27 -07:00
|
|
|
|
2017-11-01 10:40:24 -07:00
|
|
|
# Shielding will fail because limit parameter must be at least 0
|
|
|
|
try:
|
|
|
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), -1)
|
2019-12-04 07:29:16 -08:00
|
|
|
except JSONRPCException as e:
|
2020-01-08 06:53:34 -08:00
|
|
|
errorString = e.error['message']
|
|
|
|
assert_equal("Limit on maximum number of utxos cannot be negative" in errorString, True)
|
2017-11-01 10:40:24 -07:00
|
|
|
|
|
|
|
# Shielding will fail because limit parameter is absurdly large
|
|
|
|
try:
|
|
|
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), 99999999999999)
|
2019-12-04 07:29:16 -08:00
|
|
|
except JSONRPCException as e:
|
2020-01-08 06:53:34 -08:00
|
|
|
errorString = e.error['message']
|
|
|
|
assert_equal("JSON integer out of range" in errorString, True)
|
2017-11-01 10:40:24 -07:00
|
|
|
|
2020-12-17 11:39:58 -08:00
|
|
|
# Shield coinbase utxos from node 0 of value 40, standard fee
|
2017-09-15 12:59:27 -07:00
|
|
|
result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr)
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], result['opid'])
|
2017-09-15 12:59:27 -07:00
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
# Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone
|
|
|
|
assert_equal(self.nodes[0].getbalance(), 10)
|
|
|
|
assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0'))
|
2020-12-17 11:39:58 -08:00
|
|
|
assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('40.0') - DEFAULT_FEE)
|
2017-09-15 12:59:27 -07:00
|
|
|
assert_equal(self.nodes[1].getbalance(), 20)
|
|
|
|
assert_equal(self.nodes[2].getbalance(), 30)
|
|
|
|
|
|
|
|
# Shield coinbase utxos from any node 2 taddr, and set fee to 0
|
|
|
|
result = self.nodes[2].z_shieldcoinbase("*", myzaddr, 0)
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[2], result['opid'])
|
2017-09-15 12:59:27 -07:00
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
assert_equal(self.nodes[0].getbalance(), 10)
|
2020-12-17 11:39:58 -08:00
|
|
|
assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('70.0') - DEFAULT_FEE)
|
2017-09-15 12:59:27 -07:00
|
|
|
assert_equal(self.nodes[1].getbalance(), 30)
|
|
|
|
assert_equal(self.nodes[2].getbalance(), 0)
|
|
|
|
|
|
|
|
# Generate 800 coinbase utxos on node 0, and 20 coinbase utxos on node 2
|
|
|
|
self.nodes[0].generate(800)
|
|
|
|
self.sync_all()
|
|
|
|
self.nodes[2].generate(20)
|
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(100)
|
|
|
|
self.sync_all()
|
2018-03-10 02:19:44 -08:00
|
|
|
mytaddr = get_coinbase_address(self.nodes[0], 800)
|
2017-09-15 12:59:27 -07:00
|
|
|
|
2018-09-13 15:12:29 -07:00
|
|
|
def verify_locking(first, second, limit):
|
|
|
|
result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, limit)
|
|
|
|
assert_equal(result["shieldingUTXOs"], Decimal(first))
|
|
|
|
assert_equal(result["remainingUTXOs"], Decimal(second))
|
|
|
|
remainingValue = result["remainingValue"]
|
|
|
|
opid1 = result['opid']
|
|
|
|
|
|
|
|
# Verify that utxos are locked (not available for selection) by queuing up another shielding operation
|
|
|
|
result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 0)
|
|
|
|
assert_equal(result["shieldingValue"], Decimal(remainingValue))
|
|
|
|
assert_equal(result["shieldingUTXOs"], Decimal(second))
|
|
|
|
assert_equal(result["remainingValue"], Decimal('0'))
|
|
|
|
assert_equal(result["remainingUTXOs"], Decimal('0'))
|
|
|
|
opid2 = result['opid']
|
|
|
|
|
|
|
|
# wait for both aysnc operations to complete
|
|
|
|
wait_and_assert_operationid_status(self.nodes[0], opid1)
|
|
|
|
wait_and_assert_operationid_status(self.nodes[0], opid2)
|
|
|
|
|
2019-07-19 05:10:13 -07:00
|
|
|
# Shield the 800 utxos over two transactions
|
|
|
|
verify_locking('500', '300', 500)
|
2017-09-15 12:59:27 -07:00
|
|
|
|
|
|
|
# sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected.
|
2017-11-03 00:39:23 -07:00
|
|
|
# So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated
|
|
|
|
# which mines tx1 and tx2, all nodes will have an empty mempool which can then be synced.
|
|
|
|
sync_blocks(self.nodes[:2])
|
|
|
|
sync_mempools(self.nodes[:2])
|
2017-09-15 12:59:27 -07:00
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
|
2017-11-01 10:40:24 -07:00
|
|
|
# Verify maximum number of utxos which node 0 can shield is set by default limit parameter of 50
|
|
|
|
self.nodes[0].generate(200)
|
|
|
|
self.sync_all()
|
2018-03-10 02:19:44 -08:00
|
|
|
mytaddr = get_coinbase_address(self.nodes[0], 100)
|
2020-12-17 11:39:58 -08:00
|
|
|
result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, DEFAULT_FEE)
|
2017-11-01 10:40:24 -07:00
|
|
|
assert_equal(result["shieldingUTXOs"], Decimal('50'))
|
|
|
|
assert_equal(result["remainingUTXOs"], Decimal('50'))
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], result['opid'])
|
2017-11-01 10:40:24 -07:00
|
|
|
|
|
|
|
# Verify maximum number of utxos which node 0 can shield can be set by the limit parameter
|
2020-12-17 11:39:58 -08:00
|
|
|
result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, DEFAULT_FEE, 33)
|
2017-11-01 10:40:24 -07:00
|
|
|
assert_equal(result["shieldingUTXOs"], Decimal('33'))
|
|
|
|
assert_equal(result["remainingUTXOs"], Decimal('17'))
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], result['opid'])
|
2017-11-03 00:39:23 -07:00
|
|
|
# Don't sync node 2 which rejects the tx due to its mempooltxinputlimit
|
|
|
|
sync_blocks(self.nodes[:2])
|
|
|
|
sync_mempools(self.nodes[:2])
|
2017-11-01 10:40:24 -07:00
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|