2 # Copyright (c) 2017 The Zcash developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 from test_framework.test_framework import BitcoinTestFramework
7 from test_framework.authproxy import JSONRPCException
8 from test_framework.util import assert_equal, initialize_chain_clean, \
9 start_node, connect_nodes_bi, sync_blocks, sync_mempools
12 from decimal import Decimal
14 class WalletShieldCoinbaseTest (BitcoinTestFramework):
16 def setup_chain(self):
17 print("Initializing test directory "+self.options.tmpdir)
18 initialize_chain_clean(self.options.tmpdir, 4)
20 def setup_network(self, split=False):
21 args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe']
23 self.nodes.append(start_node(0, self.options.tmpdir, args))
24 self.nodes.append(start_node(1, self.options.tmpdir, args))
25 args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', "-mempooltxinputlimit=7"]
26 self.nodes.append(start_node(2, self.options.tmpdir, args2))
27 connect_nodes_bi(self.nodes,0,1)
28 connect_nodes_bi(self.nodes,1,2)
29 connect_nodes_bi(self.nodes,0,2)
30 self.is_network_split=False
33 # Returns txid if operation was a success or None
34 def wait_and_assert_operationid_status(self, nodeid, myopid, in_status='success', in_errormsg=None):
35 print('waiting for async operation {}'.format(myopid))
42 for x in xrange(1, timeout):
43 results = self.nodes[nodeid].z_getoperationresult(opids)
47 status = results[0]["status"]
48 if status == "failed":
49 errormsg = results[0]['error']['message']
50 elif status == "success":
51 txid = results[0]['result']['txid']
53 print('...returned status: {}'.format(status))
54 assert_equal(in_status, status)
55 if errormsg is not None:
56 assert(in_errormsg is not None)
57 assert_equal(in_errormsg in errormsg, True)
58 print('...returned error: {}'.format(errormsg))
62 print "Mining blocks..."
64 self.nodes[0].generate(1)
65 do_not_shield_taddr = self.nodes[0].getnewaddress()
67 self.nodes[0].generate(4)
68 walletinfo = self.nodes[0].getwalletinfo()
69 assert_equal(walletinfo['immature_balance'], 50)
70 assert_equal(walletinfo['balance'], 0)
72 self.nodes[2].generate(1)
73 self.nodes[2].getnewaddress()
74 self.nodes[2].generate(1)
75 self.nodes[2].getnewaddress()
76 self.nodes[2].generate(1)
78 self.nodes[1].generate(101)
80 assert_equal(self.nodes[0].getbalance(), 50)
81 assert_equal(self.nodes[1].getbalance(), 10)
82 assert_equal(self.nodes[2].getbalance(), 30)
84 # Prepare to send taddr->zaddr
85 mytaddr = self.nodes[0].getnewaddress()
86 myzaddr = self.nodes[0].z_getnewaddress()
88 # Shielding will fail when trying to spend from watch-only address
89 self.nodes[2].importaddress(mytaddr)
91 self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr)
92 except JSONRPCException,e:
93 errorString = e.error['message']
94 assert_equal("Could not find any coinbase funds to shield" in errorString, True)
96 # Shielding will fail because fee is negative
98 self.nodes[0].z_shieldcoinbase("*", myzaddr, -1)
99 except JSONRPCException,e:
100 errorString = e.error['message']
101 assert_equal("Amount out of range" in errorString, True)
103 # Shielding will fail because fee is larger than MAX_MONEY
105 self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('21000000.00000001'))
106 except JSONRPCException,e:
107 errorString = e.error['message']
108 assert_equal("Amount out of range" in errorString, True)
110 # Shielding will fail because fee is larger than sum of utxos
112 self.nodes[0].z_shieldcoinbase("*", myzaddr, 999)
113 except JSONRPCException,e:
114 errorString = e.error['message']
115 assert_equal("Insufficient coinbase funds" in errorString, True)
117 # Shielding will fail because limit parameter must be at least 0
119 self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), -1)
120 except JSONRPCException,e:
121 errorString = e.error['message']
122 assert_equal("Limit on maximum number of utxos cannot be negative" in errorString, True)
124 # Shielding will fail because limit parameter is absurdly large
126 self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), 99999999999999)
127 except JSONRPCException,e:
128 errorString = e.error['message']
129 assert_equal("JSON integer out of range" in errorString, True)
131 # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000
132 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr)
133 self.wait_and_assert_operationid_status(0, result['opid'])
135 self.nodes[1].generate(1)
138 # Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone
139 assert_equal(self.nodes[0].getbalance(), 10)
140 assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0'))
141 assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000'))
142 assert_equal(self.nodes[1].getbalance(), 20)
143 assert_equal(self.nodes[2].getbalance(), 30)
145 # Shield coinbase utxos from any node 2 taddr, and set fee to 0
146 result = self.nodes[2].z_shieldcoinbase("*", myzaddr, 0)
147 self.wait_and_assert_operationid_status(2, result['opid'])
149 self.nodes[1].generate(1)
152 assert_equal(self.nodes[0].getbalance(), 10)
153 assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('69.99990000'))
154 assert_equal(self.nodes[1].getbalance(), 30)
155 assert_equal(self.nodes[2].getbalance(), 0)
157 # Generate 800 coinbase utxos on node 0, and 20 coinbase utxos on node 2
158 self.nodes[0].generate(800)
160 self.nodes[2].generate(20)
162 self.nodes[1].generate(100)
164 mytaddr = self.nodes[0].getnewaddress()
166 # Shielding the 800 utxos will occur over two transactions, since max tx size is 100,000 bytes.
167 # We don't verify shieldingValue as utxos are not selected in any specific order, so value can change on each test run.
168 # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of utxos.
169 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 99999)
170 assert_equal(result["shieldingUTXOs"], Decimal('662'))
171 assert_equal(result["remainingUTXOs"], Decimal('138'))
172 remainingValue = result["remainingValue"]
173 opid1 = result['opid']
175 # Verify that utxos are locked (not available for selection) by queuing up another shielding operation
176 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 0)
177 assert_equal(result["shieldingValue"], Decimal(remainingValue))
178 assert_equal(result["shieldingUTXOs"], Decimal('138'))
179 assert_equal(result["remainingValue"], Decimal('0'))
180 assert_equal(result["remainingUTXOs"], Decimal('0'))
181 opid2 = result['opid']
183 # wait for both aysnc operations to complete
184 self.wait_and_assert_operationid_status(0, opid1)
185 self.wait_and_assert_operationid_status(0, opid2)
187 # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected.
188 # So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated
189 # which mines tx1 and tx2, all nodes will have an empty mempool which can then be synced.
190 sync_blocks(self.nodes[:2])
191 sync_mempools(self.nodes[:2])
192 self.nodes[1].generate(1)
195 # Verify maximum number of utxos which node 2 can shield is limited by option -mempooltxinputlimit
196 # This option is used when the limit parameter is set to 0.
197 mytaddr = self.nodes[2].getnewaddress()
198 result = self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 0)
199 assert_equal(result["shieldingUTXOs"], Decimal('7'))
200 assert_equal(result["remainingUTXOs"], Decimal('13'))
201 self.wait_and_assert_operationid_status(2, result['opid'])
203 self.nodes[1].generate(1)
206 # Verify maximum number of utxos which node 0 can shield is set by default limit parameter of 50
207 self.nodes[0].generate(200)
209 mytaddr = self.nodes[0].getnewaddress()
210 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'))
211 assert_equal(result["shieldingUTXOs"], Decimal('50'))
212 assert_equal(result["remainingUTXOs"], Decimal('50'))
213 self.wait_and_assert_operationid_status(0, result['opid'])
215 # Verify maximum number of utxos which node 0 can shield can be set by the limit parameter
216 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 33)
217 assert_equal(result["shieldingUTXOs"], Decimal('33'))
218 assert_equal(result["remainingUTXOs"], Decimal('17'))
219 self.wait_and_assert_operationid_status(0, result['opid'])
220 # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit
221 sync_blocks(self.nodes[:2])
222 sync_mempools(self.nodes[:2])
223 self.nodes[1].generate(1)
226 if __name__ == '__main__':
227 WalletShieldCoinbaseTest().main()