2019-12-04 07:29:16 -08:00
|
|
|
#!/usr/bin/env python3
|
2016-12-03 00:22:42 -08:00
|
|
|
# Copyright (c) 2016 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 .
|
2016-12-03 00:22:42 -08:00
|
|
|
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
2017-06-20 13:09:33 -07:00
|
|
|
from test_framework.util import assert_equal, initialize_chain_clean, \
|
2018-03-10 02:19:44 -08:00
|
|
|
start_nodes, connect_nodes_bi, wait_and_assert_operationid_status, \
|
2020-12-17 11:39:58 -08:00
|
|
|
get_coinbase_address, DEFAULT_FEE
|
2016-12-03 00:22:42 -08:00
|
|
|
|
2017-06-20 13:09:33 -07:00
|
|
|
import time
|
|
|
|
from decimal import Decimal
|
2016-12-03 00:22:42 -08:00
|
|
|
|
|
|
|
class WalletTreeStateTest (BitcoinTestFramework):
|
|
|
|
|
|
|
|
def setup_chain(self):
|
|
|
|
print("Initializing test directory "+self.options.tmpdir)
|
|
|
|
initialize_chain_clean(self.options.tmpdir, 4)
|
|
|
|
|
2019-11-28 13:36:29 -08:00
|
|
|
# Start nodes with -regtestshieldcoinbase to set fCoinbaseMustBeShielded to true.
|
2016-12-03 00:22:42 -08:00
|
|
|
def setup_network(self, split=False):
|
2019-11-28 13:36:29 -08:00
|
|
|
self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestshieldcoinbase','-debug=zrpc']] * 3 )
|
2016-12-03 00:22:42 -08: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...")
|
2016-12-03 00:22:42 -08:00
|
|
|
|
|
|
|
self.nodes[0].generate(100)
|
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(101)
|
|
|
|
self.sync_all()
|
|
|
|
|
2019-01-28 10:45:48 -08:00
|
|
|
mytaddr = get_coinbase_address(self.nodes[0])
|
2020-10-16 09:46:44 -07:00
|
|
|
myzaddr = self.nodes[0].z_getnewaddress()
|
2016-12-03 00:22:42 -08:00
|
|
|
|
2020-12-17 11:39:58 -08:00
|
|
|
# Spend coinbase utxos to create three notes of 10 ZEC minus default fee each
|
2016-12-03 00:22:42 -08:00
|
|
|
recipients = []
|
2020-12-17 11:39:58 -08:00
|
|
|
recipients.append({"address": myzaddr, "amount": Decimal('10.0') - DEFAULT_FEE})
|
2016-12-03 00:22:42 -08:00
|
|
|
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], myopid)
|
2016-12-03 00:22:42 -08:00
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], myopid)
|
2016-12-03 00:22:42 -08:00
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], myopid)
|
2016-12-03 00:22:42 -08:00
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
# Check balance
|
|
|
|
resp = self.nodes[0].z_getbalance(myzaddr)
|
2020-12-17 11:39:58 -08:00
|
|
|
assert_equal(Decimal(resp), (Decimal('10.0') - DEFAULT_FEE) * 3)
|
2016-12-03 00:22:42 -08:00
|
|
|
|
|
|
|
# We want to test a real-world situation where during the time spent creating a transaction
|
|
|
|
# with joinsplits, other transactions containing joinsplits have been mined into new blocks,
|
|
|
|
# which result in the treestate changing whilst creating the transaction.
|
|
|
|
|
|
|
|
# Tx 1 will change the treestate while Tx 2 containing chained joinsplits is still being generated
|
|
|
|
recipients = []
|
2020-12-17 11:39:58 -08:00
|
|
|
recipients.append({"address": self.nodes[2].z_getnewaddress(), "amount": Decimal('10.0') - DEFAULT_FEE})
|
2016-12-03 00:22:42 -08:00
|
|
|
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], myopid)
|
2016-12-03 00:22:42 -08:00
|
|
|
|
|
|
|
# Tx 2 will consume all three notes, which must take at least two joinsplits. This is regardless of
|
|
|
|
# the z_sendmany implementation because there are only two inputs per joinsplit.
|
|
|
|
recipients = []
|
2020-12-17 11:39:58 -08:00
|
|
|
recipients.append({"address": self.nodes[2].z_getnewaddress(), "amount": Decimal('18.0')})
|
|
|
|
recipients.append({"address": self.nodes[2].z_getnewaddress(), "amount": Decimal('12.0') - 4*DEFAULT_FEE})
|
2016-12-03 00:22:42 -08:00
|
|
|
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
|
|
|
|
|
|
|
|
# Wait for Tx 2 to begin executing...
|
2019-12-04 07:29:16 -08:00
|
|
|
for x in range(1, 60):
|
2016-12-03 00:22:42 -08:00
|
|
|
results = self.nodes[0].z_getoperationstatus([myopid])
|
|
|
|
status = results[0]["status"]
|
|
|
|
if status == "executing":
|
|
|
|
break
|
2017-06-20 13:09:33 -07:00
|
|
|
time.sleep(1)
|
2016-12-03 00:22:42 -08:00
|
|
|
|
|
|
|
# Now mine Tx 1 which will change global treestate before Tx 2's second joinsplit begins processing
|
|
|
|
self.sync_all()
|
|
|
|
self.nodes[1].generate(1)
|
|
|
|
self.sync_all()
|
|
|
|
|
|
|
|
# Wait for Tx 2 to be created
|
2017-12-12 23:38:46 -08:00
|
|
|
wait_and_assert_operationid_status(self.nodes[0], myopid)
|
2016-12-03 00:22:42 -08:00
|
|
|
|
|
|
|
# Note that a bug existed in v1.0.0-1.0.3 where Tx 2 creation would fail with an error:
|
|
|
|
# "Witness for spendable note does not have same anchor as change input"
|
|
|
|
|
|
|
|
# Check balance
|
|
|
|
resp = self.nodes[0].z_getbalance(myzaddr)
|
|
|
|
assert_equal(Decimal(resp), Decimal('0.0'))
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
WalletTreeStateTest().main()
|