2 # Copyright (c) 2018 The Zcash developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or https://www.opensource.org/licenses/mit-license.php .
6 import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x."
8 from test_framework.test_framework import BitcoinTestFramework
9 from test_framework.util import (
13 initialize_chain_clean,
15 wait_and_assert_operationid_status,
18 from decimal import Decimal
20 SAPLING_TREE_EMPTY_ROOT = "3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb"
21 NULL_FIELD = "0000000000000000000000000000000000000000000000000000000000000000"
23 # Verify block header field 'hashFinalSaplingRoot' (returned in rpc as 'finalsaplingroot')
24 # is updated when Sapling transactions with outputs (commitments) are mined into a block.
25 class FinalSaplingRootTest(BitcoinTestFramework):
27 def setup_chain(self):
28 print("Initializing test directory "+self.options.tmpdir)
29 initialize_chain_clean(self.options.tmpdir, 4)
31 def setup_network(self, split=False):
32 self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[[
33 '-nuparams=5ba81b19:100', # Overwinter
34 '-nuparams=76b809bb:200', # Sapling
35 '-txindex' # Avoid JSONRPC error: No information available about transaction
37 connect_nodes_bi(self.nodes,0,1)
38 connect_nodes_bi(self.nodes,1,2)
39 connect_nodes_bi(self.nodes,0,2)
40 connect_nodes_bi(self.nodes,0,3)
41 self.is_network_split=False
45 # Activate Overwinter and Sapling
46 self.nodes[0].generate(200)
49 # Verfify genesis block contains null field for what is now called the final sapling root field.
50 blk = self.nodes[0].getblock("0")
51 assert_equal(blk["finalsaplingroot"], NULL_FIELD)
53 # Verify all generated blocks contain the empty root of the Sapling tree.
54 blockcount = self.nodes[0].getblockcount()
55 for height in xrange(1, blockcount + 1):
56 blk = self.nodes[0].getblock(str(height))
57 assert_equal(blk["finalsaplingroot"], SAPLING_TREE_EMPTY_ROOT)
59 # Node 0 shields some funds
60 taddr0 = get_coinbase_address(self.nodes[0])
61 saplingAddr0 = self.nodes[0].z_getnewaddress('sapling')
63 recipients.append({"address": saplingAddr0, "amount": Decimal('20')})
64 myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0)
65 mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
68 self.nodes[0].generate(1)
71 # Verify the final Sapling root has changed
72 blk = self.nodes[0].getblock("201")
73 root = blk["finalsaplingroot"]
74 assert(root is not SAPLING_TREE_EMPTY_ROOT)
75 assert(root is not NULL_FIELD)
77 # Verify there is a Sapling output description (its commitment was added to tree)
78 result = self.nodes[0].getrawtransaction(mytxid, 1)
79 assert_equal(len(result["vShieldedOutput"]), 1)
81 # Mine an empty block and verify the final Sapling root does not change
83 self.nodes[0].generate(1)
85 assert_equal(root, self.nodes[0].getblock("202")["finalsaplingroot"])
87 # Mine a block with a transparent tx and verify the final Sapling root does not change
88 taddr1 = self.nodes[1].getnewaddress()
89 self.nodes[0].sendtoaddress(taddr1, Decimal("1.23"))
92 self.nodes[0].generate(1)
95 assert_equal(len(self.nodes[0].getblock("203")["tx"]), 2)
96 assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal("1.23"))
97 assert_equal(root, self.nodes[0].getblock("203")["finalsaplingroot"])
99 # Mine a block with a Sprout shielded tx and verify the final Sapling root does not change
100 zaddr1 = self.nodes[1].z_getnewaddress('sprout')
102 recipients.append({"address": zaddr1, "amount": Decimal('10')})
103 myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0)
104 wait_and_assert_operationid_status(self.nodes[0], myopid)
107 self.nodes[0].generate(1)
110 assert_equal(len(self.nodes[0].getblock("204")["tx"]), 2)
111 assert_equal(self.nodes[1].z_getbalance(zaddr1), Decimal("10"))
112 assert_equal(root, self.nodes[0].getblock("204")["finalsaplingroot"])
114 # Mine a block with a Sapling shielded recipient and verify the final Sapling root changes
115 saplingAddr1 = self.nodes[1].z_getnewaddress("sapling")
117 recipients.append({"address": saplingAddr1, "amount": Decimal('12.34')})
118 myopid = self.nodes[0].z_sendmany(saplingAddr0, recipients, 1, 0)
119 mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
122 self.nodes[0].generate(1)
125 assert_equal(len(self.nodes[0].getblock("205")["tx"]), 2)
126 assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal("12.34"))
127 assert(root is not self.nodes[0].getblock("205")["finalsaplingroot"])
129 # Verify there is a Sapling output description (its commitment was added to tree)
130 result = self.nodes[0].getrawtransaction(mytxid, 1)
131 assert_equal(len(result["vShieldedOutput"]), 2) # there is Sapling shielded change
133 # Mine a block with a Sapling shielded sender and transparent recipient and verify the final Sapling root doesn't change
134 taddr2 = self.nodes[0].getnewaddress()
136 recipients.append({"address": taddr2, "amount": Decimal('12.34')})
137 myopid = self.nodes[1].z_sendmany(saplingAddr1, recipients, 1, 0)
138 mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid)
141 self.nodes[0].generate(1)
144 assert_equal(len(self.nodes[0].getblock("206")["tx"]), 2)
145 assert_equal(self.nodes[0].z_getbalance(taddr2), Decimal("12.34"))
147 blk = self.nodes[0].getblock("206")
148 root = blk["finalsaplingroot"]
149 assert_equal(root, self.nodes[0].getblock("205")["finalsaplingroot"])
152 if __name__ == '__main__':
153 FinalSaplingRootTest().main()