def z_send(from_node, from_addr, to_addr, amount): global fee opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}], 1, fee) wait_and_assert_operationid_status(from_node, opid) self.sync_all() miner.generate(1) self.sync_all()
def run_test(self): taddr = self.nodes[1].getnewaddress() zaddr1 = self.nodes[1].z_getnewaddress() zaddr2 = self.nodes[1].z_getnewaddress() self.nodes[0].sendtoaddress(taddr, Decimal('1.0')) self.generate_and_sync() # Send 1 ZEC to a zaddr wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1.0, 'memo': 'c0ffee01'}], 1, 0)) self.generate_and_sync() # Check that we have received 1 note which is not change receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) listunspent = self.nodes[1].z_listunspent() assert_equal(1, len(receivedbyaddress), "Should have received 1 note") assert_false(receivedbyaddress[0]['change'], "Note should not be change") assert_equal(1, len(listunspent), "Should have 1 unspent note") assert_false(listunspent[0]['change'], "Unspent note should not be change") # Generate some change wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{'address': zaddr2, 'amount': 0.6, 'memo': 'c0ffee02'}], 1, 0)) self.generate_and_sync() # Check zaddr1 received sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr1, 0), key = lambda received: received['amount']) assert_equal(2, len(sortedreceived1), "zaddr1 Should have received 2 notes") assert_equal(Decimal('0.4'), sortedreceived1[0]['amount']) assert_true(sortedreceived1[0]['change'], "Note valued at 0.4 should be change") assert_equal(Decimal('1.0'), sortedreceived1[1]['amount']) assert_false(sortedreceived1[1]['change'], "Note valued at 1.0 should not be change") # Check zaddr2 received sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr2, 0), key = lambda received: received['amount']) assert_equal(1, len(sortedreceived2), "zaddr2 Should have received 1 notes") assert_equal(Decimal('0.6'), sortedreceived2[0]['amount']) assert_false(sortedreceived2[0]['change'], "Note valued at 0.6 should not be change") # Check unspent sortedunspent = sorted(self.nodes[1].z_listunspent(), key = lambda received: received['amount']) assert_equal(2, len(sortedunspent), "Should have 2 unspent notes") assert_equal(Decimal('0.4'), sortedunspent[0]['amount']) assert_true(sortedunspent[0]['change'], "Unspent note valued at 0.4 should be change") assert_equal(Decimal('0.6'), sortedunspent[1]['amount']) assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change") # Give node 0 a viewing key viewing_key = self.nodes[1].z_exportviewingkey(zaddr1) self.nodes[0].z_importviewingkey(viewing_key) received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0) assert_equal(2, len(received_node0)) unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True) assert_equal(2, len(unspent_node0)) # node 0 only has a viewing key so does not see the change field assert_false('change' in received_node0[0]) assert_false('change' in received_node0[1]) assert_false('change' in unspent_node0[0]) assert_false('change' in unspent_node0[1])
def run_test (self): print "Mining blocks..." self.nodes[0].setmocktime(starttime) self.nodes[0].generate(101) mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Send 10 coins to our zaddr. recipients = [] recipients.append({"address":myzaddr, "amount":Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.nodes[0].generate(1) # Ensure the block times of the latest blocks exceed the variability self.nodes[0].setmocktime(starttime + 3000) self.nodes[0].generate(1) self.nodes[0].setmocktime(starttime + 6000) self.nodes[0].generate(1) self.nodes[0].setmocktime(starttime + 9000) self.nodes[0].generate(1) # Confirm the balance on node 0. resp = self.nodes[0].z_getbalance(myzaddr) assert_equal(Decimal(resp), Decimal('10.0') - Decimal('0.0001')) # Export the key for the zaddr from node 0. key = self.nodes[0].z_exportkey(myzaddr) # Start the new wallet self.add_second_node() self.nodes[1].getnewaddress() self.nodes[1].z_getnewaddress('sprout') self.nodes[1].generate(101) self.sync_all() # Import the key on node 1, only scanning the last few blocks. # (uses 'true' to test boolean fallback) self.nodes[1].z_importkey(key, 'true', self.nodes[1].getblockchaininfo()['blocks'] - 100) # Confirm that the balance on node 1 is zero, as we have not # rescanned over the older transactions resp = self.nodes[1].z_getbalance(myzaddr) assert_equal(Decimal(resp), 0) # Re-import the key on node 1, scanning from before the transaction. self.nodes[1].z_importkey(key, 'yes', self.nodes[1].getblockchaininfo()['blocks'] - 110) # Confirm that the balance on node 1 is valid now (node 1 must # have rescanned) resp = self.nodes[1].z_getbalance(myzaddr) assert_equal(Decimal(resp), Decimal('10.0') - Decimal('0.0001'))
def run_test (self): print "Mining blocks..." self.nodes[0].generate(1) do_not_shield_taddr = self.nodes[0].getnewaddress() self.nodes[0].generate(4) 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].getnewaddress() self.nodes[2].generate(1) self.nodes[2].getnewaddress() 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) # Shield the coinbase myzaddr = self.nodes[0].z_getnewaddress() result = self.nodes[0].z_shieldcoinbase("*", myzaddr, 0) wait_and_assert_operationid_status(self.nodes[0], result['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Prepare some UTXOs and notes for merging mytaddr = self.nodes[0].getnewaddress() mytaddr2 = self.nodes[0].getnewaddress() mytaddr3 = self.nodes[0].getnewaddress() result = self.nodes[0].z_sendmany(myzaddr, [ {'address': do_not_shield_taddr, 'amount': 10}, {'address': mytaddr, 'amount': 10}, {'address': mytaddr2, 'amount': 10}, {'address': mytaddr3, 'amount': 10}, ], 1, 0) wait_and_assert_operationid_status(self.nodes[0], result) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Merging will fail because from arguments need to be in an array try: self.nodes[0].z_mergetoaddress("*", myzaddr) assert(False) except JSONRPCException,e: errorString = e.error['message']
def run_test(self): self.nodes[0].generate(1) self.sync_all() taddr = self.nodes[1].getnewaddress() zaddr1 = self.nodes[1].z_getnewaddress('sprout') self.nodes[0].sendtoaddress(taddr, 2.0) self.nodes[0].generate(1) self.sync_all() # Create and sign Overwinter transaction. # If the incorrect consensus branch id is selected, there will be a signing error. opid = self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1}]) wait_and_assert_operationid_status(self.nodes[1], opid)
def run_test(self): self.nodes[1].generate(100) self.sync_all() # Mine 97 blocks. After this, nodes[1] blocks # 1 to 97 are spend-able. self.nodes[0].generate(97) self.sync_all() # Shield some ZEC node1_taddr = get_coinbase_address(self.nodes[1]) node0_zaddr = self.nodes[0].z_getnewaddress('sprout') recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] myopid = self.nodes[1].z_sendmany(node1_taddr, recipients, 1, Decimal('0')) print wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() # Mempool checks for activation of upgrade Y at height H on base X def nu_activation_checks(): # Mine block H - 2. After this, the mempool expects # block H - 1, which is the last X block. self.nodes[0].generate(1) self.sync_all() # Mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # Check node 0 shielded balance assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) # Fill the mempool with twice as many transactions as can fit into blocks node0_taddr = self.nodes[0].getnewaddress() x_txids = [] info = self.nodes[0].getblockchaininfo() chaintip_branchid = info["consensus"]["chaintip"] while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000: try: x_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001'))) assert_equal(chaintip_branchid, "00000000") except JSONRPCException: # This fails due to expiring soon threshold, which applies from Overwinter onwards. assert_equal(info["upgrades"][chaintip_branchid]["name"], "Overwinter") break self.sync_all() # Spends should be in the mempool x_mempool = set(self.nodes[0].getrawmempool()) assert_equal(x_mempool, set(x_txids)) # Mine block H - 1. After this, the mempool expects # block H, which is the first Y block. self.nodes[0].generate(1) self.sync_all() # mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # When transitioning from Sprout to Overwinter, where expiring soon threshold does not apply: # Block H - 1 should contain a subset of the original mempool # (with all other transactions having been dropped) block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx'] if chaintip_branchid is "00000000": assert(len(block_txids) < len(x_txids)) for txid in block_txids[1:]: # Exclude coinbase assert(txid in x_txids) # Create some transparent Y transactions y_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)] self.sync_all() # Create a shielded Y transaction recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0')) shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) assert(shielded != None) y_txids.append(shielded) self.sync_all() # Spends should be in the mempool assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids)) # Node 0 note should be unspendable assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0')) # Invalidate block H - 1. block_hm1 = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(block_hm1) # BUG: Ideally, the mempool should now only contain the transactions # that were in block H - 1, the Y transactions having been dropped. # However, because chainActive is not updated until after the transactions # in the disconnected block have been re-added to the mempool, the height # seen by AcceptToMemoryPool is one greater than it should be. This causes # the block H - 1 transactions to be validated against the Y rules, # and rejected because they (obviously) fail. #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:])) assert_equal(set(self.nodes[0].getrawmempool()), set()) # Node 0 note should be spendable again assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) # Reconsider block H - 1. self.nodes[0].reconsiderblock(block_hm1) # Mine blocks on node 1, so that the Y transactions in its mempool # will be cleared. self.nodes[1].generate(6) self.sync_all() print('Testing Sprout -> Overwinter activation boundary') # Current height = 197 nu_activation_checks() # Current height = 205 self.nodes[0].generate(2) self.sync_all() print('Testing Overwinter -> Sapling activation boundary') # Current height = 207 nu_activation_checks()
def run_test (self): # add zaddr to node 0 myzaddr0 = self.nodes[0].z_getnewaddress() # send node 0 taddr to zaddr to get out of coinbase # Tests using the default cached chain have one address per coinbase output mytaddr = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({"address":myzaddr0, "amount":Decimal('10.0')-Decimal('0.0001')}) # utxo amount less fee wait_and_assert_operationid_status(self.nodes[0], self.nodes[0].z_sendmany(mytaddr, recipients), timeout=120) self.sync_all() self.nodes[0].generate(1) self.sync_all() # add zaddr to node 2 myzaddr = self.nodes[2].z_getnewaddress() # import node 2 zaddr into node 1 myzkey = self.nodes[2].z_exportkey(myzaddr) self.nodes[1].z_importkey(myzkey) # encrypt node 1 wallet and wait to terminate self.nodes[1].encryptwallet("test") bitcoind_processes[1].wait() # restart node 1 self.nodes[1] = start_node(1, self.options.tmpdir) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) self.sync_all() # send node 0 zaddr to note 2 zaddr recipients = [] recipients.append({"address":myzaddr, "amount":7.0}) wait_and_assert_operationid_status(self.nodes[0], self.nodes[0].z_sendmany(myzaddr0, recipients), timeout=120) self.sync_all() self.nodes[0].generate(1) self.sync_all() # check zaddr balance zsendmanynotevalue = Decimal('7.0') assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue) assert_equal(self.nodes[1].z_getbalance(myzaddr), zsendmanynotevalue) # add zaddr to node 3 myzaddr3 = self.nodes[3].z_getnewaddress() # send node 2 zaddr to note 3 zaddr recipients = [] recipients.append({"address":myzaddr3, "amount":2.0}) wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(myzaddr, recipients), timeout=120) self.sync_all() self.nodes[2].generate(1) self.sync_all() # check zaddr balance zsendmany2notevalue = Decimal('2.0') zsendmanyfee = Decimal('0.0001') zaddrremaining = zsendmanynotevalue - zsendmany2notevalue - zsendmanyfee assert_equal(self.nodes[3].z_getbalance(myzaddr3), zsendmany2notevalue) assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining) # Parallel encrypted wallet can cache nullifiers for Sapling received notes assert_equal(self.nodes[1].z_getbalance(myzaddr), zaddrremaining) # send node 2 zaddr on node 1 to taddr self.nodes[1].walletpassphrase("test", 600) mytaddr1 = self.nodes[1].getnewaddress() recipients = [] recipients.append({"address":mytaddr1, "amount":1.0}) wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(myzaddr, recipients), timeout=120) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check zaddr balance zsendmany3notevalue = Decimal('1.0') zaddrremaining2 = zaddrremaining - zsendmany3notevalue - zsendmanyfee assert_equal(self.nodes[1].z_getbalance(myzaddr), zaddrremaining2) assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining2) # Test viewing keys node3mined = Decimal('250.0') assert_equal({k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items()}, { 'transparent': node3mined, 'private': zsendmany2notevalue, 'total': node3mined + zsendmany2notevalue, }) # Add node 1 address and node 2 viewing key to node 3 myzvkey = self.nodes[2].z_exportviewingkey(myzaddr) self.nodes[3].importaddress(mytaddr1) importvk_result = self.nodes[3].z_importviewingkey(myzvkey, 'whenkeyisnew', 1) # Check results of z_importviewingkey assert_equal(importvk_result["type"], "sapling") assert_equal(importvk_result["address"], myzaddr) # Check the address has been imported assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False) assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True) # Node 3 should see the same received notes as node 2; however, there are 2 things: # - Some of the notes were change for node 2 but not for node 3. # - Each node wallet store transaction time as received. As # `wait_and_assert_operationid_status` is called node 2 and 3 are off by a few seconds. # Aside from that the received notes should be the same. So, # group by txid and then check that all properties aside from # change are equal. node2Received = dict([r['txid'], r] for r in self.nodes[2].z_listreceivedbyaddress(myzaddr)) node3Received = dict([r['txid'], r] for r in self.nodes[3].z_listreceivedbyaddress(myzaddr)) assert_equal(len(node2Received), len(node2Received)) for txid in node2Received: received2 = node2Received[txid] received3 = node3Received[txid] # the change field will be omitted for received3, but all other fields should be shared assert_true(len(received2) >= len(received3)) for key in received2: # check all the properties except for change and blocktime if key != 'change' and key != 'blocktime': assert_equal(received2[key], received3[key]) # Node 3's balances should be unchanged without explicitly requesting # to include watch-only balances assert_equal({k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items()}, { 'transparent': node3mined, 'private': zsendmany2notevalue, 'total': node3mined + zsendmany2notevalue, }) # Wallet can cache nullifiers for Sapling notes received by addresses it only has a # viewing key for. assert_equal({k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance(1, True).items()}, { 'transparent': node3mined + Decimal('1.0'), 'private': zsendmany2notevalue + zaddrremaining2, 'total': node3mined + Decimal('1.0') + zsendmany2notevalue + zaddrremaining2, }) # Check individual balances reflect the above assert_equal(self.nodes[3].z_getbalance(mytaddr1), Decimal('1.0')) assert_equal(self.nodes[3].z_getbalance(myzaddr), zaddrremaining2)
errorString = "" try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999) except JSONRPCException, e: errorString = e.error['message'] assert_equal("Insufficient funds" in errorString, True) # z_sendmany will fail because of insufficient funds recipients = [] recipients.append({ "address": self.nodes[1].getnewaddress(), "amount": Decimal('10000.0') }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status( self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001") myopid = self.nodes[0].z_sendmany(myzaddr, recipients) wait_and_assert_operationid_status( self.nodes[0], myopid, "failed", "Insufficient shielded funds, have 9.9998, need 10000.0001") # Send will fail because of insufficient funds unless sender uses coinbase utxos try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21) except JSONRPCException, e: errorString = e.error['message'] assert_equal( "Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr" in errorString, True)
def run_test(self): print "Mining blocks..." self.nodes[0].generate(102) self.sync_all() # Send some ZEL to Sprout/Sapling addresses coinbase_addr = get_coinbase_address(self.nodes[0]) sproutAddr = self.nodes[0].z_getnewaddress('sprout') saplingAddr = self.nodes[0].z_getnewaddress('sapling') t_addr = self.nodes[1].getnewaddress() opid = self.nodes[0].z_sendmany(coinbase_addr, [{ "address": sproutAddr, "amount": Decimal('10') }], 1, 0) wait_and_assert_operationid_status(self.nodes[0], opid) self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10')) assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('0')) # Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sprout Notes assert_mergetoaddress_exception( "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress", lambda: self.nodes[0].z_mergetoaddress( ["ANY_SPROUT", "ANY_SAPLING"], t_addr)) opid = self.nodes[0].z_sendmany(coinbase_addr, [{ "address": saplingAddr, "amount": Decimal('10') }], 1, 0) wait_and_assert_operationid_status(self.nodes[0], opid) self.nodes[0].generate(1) self.sync_all() assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('0')) # Merge Sprout -> taddr result = self.nodes[0].z_mergetoaddress(["ANY_SPROUT"], t_addr, 0) wait_and_assert_operationid_status(self.nodes[0], result['opid']) self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0')) assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('10')) assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('10')) # Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sapling Notes assert_mergetoaddress_exception( "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress", lambda: self.nodes[0].z_mergetoaddress( ["ANY_SPROUT", "ANY_SAPLING"], t_addr)) # Merge Sapling -> taddr result = self.nodes[0].z_mergetoaddress(["ANY_SAPLING"], t_addr, 0) wait_and_assert_operationid_status(self.nodes[0], result['opid']) self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0')) assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0')) assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('20'))
def run_test(self, test): print "Mining blocks..." test.nodes[0].generate(1) do_not_shield_taddr = test.nodes[0].getnewaddress() test.nodes[0].generate(4) walletinfo = test.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) test.sync_all() test.nodes[2].generate(1) test.nodes[2].getnewaddress() test.nodes[2].generate(1) test.nodes[2].getnewaddress() test.nodes[2].generate(1) test.sync_all() test.nodes[1].generate(101) test.sync_all() assert_equal(test.nodes[0].getbalance(), 50) assert_equal(test.nodes[1].getbalance(), 10) assert_equal(test.nodes[2].getbalance(), 30) # Shield the coinbase myzaddr = test.nodes[0].z_getnewaddress(self.addr_type) result = test.nodes[0].z_shieldcoinbase("*", myzaddr, 0) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Prepare some UTXOs and notes for merging mytaddr = test.nodes[0].getnewaddress() mytaddr2 = test.nodes[0].getnewaddress() mytaddr3 = test.nodes[0].getnewaddress() result = test.nodes[0].z_sendmany(myzaddr, [ {'address': do_not_shield_taddr, 'amount': 10}, {'address': mytaddr, 'amount': 10}, {'address': mytaddr2, 'amount': 10}, {'address': mytaddr3, 'amount': 10}, ], 1, 0) wait_and_assert_operationid_status(test.nodes[0], result) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Merging will fail because from arguments need to be in an array assert_mergetoaddress_exception( "JSON value is not an array as expected", lambda: test.nodes[0].z_mergetoaddress("notanarray", myzaddr)) # Merging will fail when trying to spend from watch-only address test.nodes[2].importaddress(mytaddr) assert_mergetoaddress_exception( "Could not find any funds to merge.", lambda: test.nodes[2].z_mergetoaddress([mytaddr], myzaddr)) # Merging will fail because fee is negative assert_mergetoaddress_exception( "Amount out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, -1)) # Merging will fail because fee is larger than MAX_MONEY assert_mergetoaddress_exception( "Amount out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('21000000.00000001'))) # Merging will fail because fee is larger than sum of UTXOs assert_mergetoaddress_exception( "Insufficient funds, have 50.00, which is less than miners fee 999.00", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 999)) # Merging will fail because transparent limit parameter must be at least 0 assert_mergetoaddress_exception( "Limit on maximum number of UTXOs cannot be negative", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), -1)) # Merging will fail because transparent limit parameter is absurdly large assert_mergetoaddress_exception( "JSON integer out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 99999999999999)) # Merging will fail because shielded limit parameter must be at least 0 assert_mergetoaddress_exception( "Limit on maximum number of notes cannot be negative", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, -1)) # Merging will fail because shielded limit parameter is absurdly large assert_mergetoaddress_exception( "JSON integer out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, 99999999999999)) # Merging will fail for this specific case where it would spend a fee and do nothing assert_mergetoaddress_exception( "Destination address is also the only source address, and all its funds are already merged.", lambda: test.nodes[0].z_mergetoaddress([mytaddr], mytaddr)) # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000 result = test.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone assert_equal(test.nodes[0].getbalance(), 10) assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0')) assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000')) assert_equal(test.nodes[1].getbalance(), 40) assert_equal(test.nodes[2].getbalance(), 30) # Shield all notes to another z-addr myzaddr2 = test.nodes[0].z_getnewaddress(self.addr_type) result = test.nodes[0].z_mergetoaddress(self.any_zaddr, myzaddr2, 0) assert_equal(result["mergingUTXOs"], Decimal('0')) assert_equal(result["remainingUTXOs"], Decimal('0')) assert_equal(result["mergingNotes"], Decimal('2')) assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() blockhash = test.nodes[1].generate(1) test.sync_all() assert_equal(len(test.nodes[0].getblock(blockhash[0])['tx']), 2) assert_equal(test.nodes[0].z_getbalance(myzaddr), 0) assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000')) # Shield coinbase UTXOs from any node 2 taddr, and set fee to 0 result = test.nodes[2].z_shieldcoinbase("*", myzaddr, 0) wait_and_assert_operationid_status(test.nodes[2], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() assert_equal(test.nodes[0].getbalance(), 10) assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('30')) assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000')) assert_equal(test.nodes[1].getbalance(), 60) assert_equal(test.nodes[2].getbalance(), 0) # Merge all notes from node 0 into a node 0 taddr, and set fee to 0 result = test.nodes[0].z_mergetoaddress(self.any_zaddr, mytaddr, 0) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() assert_equal(test.nodes[0].getbalance(), Decimal('79.99990000')) assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0')) assert_equal(test.nodes[0].z_getbalance(mytaddr), Decimal('69.99990000')) assert_equal(test.nodes[0].z_getbalance(myzaddr), 0) assert_equal(test.nodes[0].z_getbalance(myzaddr2), 0) assert_equal(test.nodes[1].getbalance(), 70) assert_equal(test.nodes[2].getbalance(), 0) # Merge all node 0 UTXOs together into a node 1 taddr, and set fee to 0 test.nodes[1].getnewaddress() # Ensure we have an empty address n1taddr = test.nodes[1].getnewaddress() result = test.nodes[0].z_mergetoaddress(["ANY_TADDR"], n1taddr, 0) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() assert_equal(test.nodes[0].getbalance(), 0) assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), 0) assert_equal(test.nodes[0].z_getbalance(mytaddr), 0) assert_equal(test.nodes[0].z_getbalance(myzaddr), 0) assert_equal(test.nodes[1].getbalance(), Decimal('159.99990000')) assert_equal(test.nodes[1].z_getbalance(n1taddr), Decimal('79.99990000')) assert_equal(test.nodes[2].getbalance(), 0) # Generate self.utxos_to_generate regular UTXOs on node 0, and 20 regular UTXOs on node 2 mytaddr = test.nodes[0].getnewaddress() n2taddr = test.nodes[2].getnewaddress() test.nodes[1].generate(1000) test.sync_all() for i in range(self.utxos_to_generate): test.nodes[1].sendtoaddress(mytaddr, 1) for i in range(20): test.nodes[1].sendtoaddress(n2taddr, 1) test.nodes[1].generate(1) test.sync_all() # Merging the UTXOs will conditionally occur over two transactions, since max tx size is 100,000 bytes before Sapling and 2,000,000 after. # We don't verify mergingTransparentValue as UTXOs are not selected in any specific order, so value can change on each test run. # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of UTXOs. result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 99999) assert_equal(result["mergingUTXOs"], self.utxos_in_tx1) assert_equal(result["remainingUTXOs"], self.utxos_in_tx2) assert_equal(result["mergingNotes"], Decimal('0')) assert_equal(result["mergingShieldedValue"], Decimal('0')) assert_equal(result["remainingNotes"], Decimal('0')) assert_equal(result["remainingShieldedValue"], Decimal('0')) remainingTransparentValue = result["remainingTransparentValue"] wait_and_assert_operationid_status(test.nodes[0], result['opid']) # For sapling we do not check that this occurs over two transactions because of the time that it would take if self.utxos_in_tx2 > 0: # Verify that UTXOs are locked (not available for selection) by queuing up another merging operation result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 0) assert_equal(result["mergingUTXOs"], self.utxos_in_tx2) assert_equal(result["mergingTransparentValue"], Decimal(remainingTransparentValue)) assert_equal(result["remainingUTXOs"], Decimal('0')) assert_equal(result["remainingTransparentValue"], Decimal('0')) assert_equal(result["mergingNotes"], Decimal('0')) assert_equal(result["mergingShieldedValue"], Decimal('0')) assert_equal(result["remainingNotes"], Decimal('0')) assert_equal(result["remainingShieldedValue"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected. # 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(test.nodes[:2]) sync_mempools(test.nodes[:2]) # Generate enough blocks to ensure all transactions are mined while test.nodes[1].getmempoolinfo()['size'] > 0: test.nodes[1].generate(1) test.sync_all() # Verify maximum number of UTXOs which node 2 can shield is limited by option -mempooltxinputlimit # This option is used when the limit parameter is set to 0. # -mempooltxinputlimit is not used after overwinter activation if self.test_mempooltxinputlimit: expected_to_merge = 7 expected_remaining = 13 else: expected_to_merge = 20 expected_remaining = 0 result = test.nodes[2].z_mergetoaddress([n2taddr], myzaddr, Decimal('0.0001'), 0) assert_equal(result["mergingUTXOs"], expected_to_merge) assert_equal(result["remainingUTXOs"], expected_remaining) assert_equal(result["mergingNotes"], Decimal('0')) assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[2], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Verify maximum number of UTXOs which node 0 can shield is set by default limit parameter of 50 mytaddr = test.nodes[0].getnewaddress() for i in range(100): test.nodes[1].sendtoaddress(mytaddr, 1) test.nodes[1].generate(1) test.sync_all() result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001')) assert_equal(result["mergingUTXOs"], Decimal('50')) assert_equal(result["remainingUTXOs"], Decimal('50')) assert_equal(result["mergingNotes"], Decimal('0')) # Remaining notes are only counted if we are trying to merge any notes assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # Verify maximum number of UTXOs which node 0 can shield can be set by the limit parameter result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001'), 33) assert_equal(result["mergingUTXOs"], Decimal('33')) assert_equal(result["remainingUTXOs"], Decimal('17')) assert_equal(result["mergingNotes"], Decimal('0')) # Remaining notes are only counted if we are trying to merge any notes assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit sync_blocks(test.nodes[:2]) sync_mempools(test.nodes[:2]) test.nodes[1].generate(1) test.sync_all() # Verify maximum number of notes which node 0 can shield can be set by the limit parameter # Also check that we can set off a second merge before the first one is complete # myzaddr will have 5 notes if testing before to Sapling activation and 4 otherwise num_notes = len(test.nodes[0].z_listunspent(0)) result1 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) result2 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) # First merge should select from all notes assert_equal(result1["mergingUTXOs"], Decimal('0')) # Remaining UTXOs are only counted if we are trying to merge any UTXOs assert_equal(result1["remainingUTXOs"], Decimal('0')) assert_equal(result1["mergingNotes"], Decimal('2')) assert_equal(result1["remainingNotes"], num_notes - 2) # Second merge should ignore locked notes assert_equal(result2["mergingUTXOs"], Decimal('0')) assert_equal(result2["remainingUTXOs"], Decimal('0')) assert_equal(result2["mergingNotes"], Decimal('2')) assert_equal(result2["remainingNotes"], num_notes - 4) wait_and_assert_operationid_status(test.nodes[0], result1['opid']) wait_and_assert_operationid_status(test.nodes[0], result2['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Shield both UTXOs and notes to a z-addr result = test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 0, 10, 2) assert_equal(result["mergingUTXOs"], Decimal('10')) assert_equal(result["remainingUTXOs"], Decimal('7')) assert_equal(result["mergingNotes"], Decimal('2')) assert_equal(result["remainingNotes"], num_notes - 4) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit sync_blocks(test.nodes[:2]) sync_mempools(test.nodes[:2]) test.nodes[1].generate(1) test.sync_all()
errorString = e.error['message'] assert_equal( "Limit on maximum number of utxos cannot be negative" in errorString, True) # Shielding will fail because limit parameter is absurdly large try: self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), 99999999999999) except JSONRPCException, e: errorString = e.error['message'] assert_equal("JSON integer out of range" in errorString, True) # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000 result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr) wait_and_assert_operationid_status(self.nodes[0], result['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Confirm balances and that do_not_shield_taddr containing funds of 12.5 was left alone assert_equal(self.nodes[0].getbalance(), 12.5) assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('12.5')) assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('49.99990000')) assert_equal(self.nodes[1].getbalance(), 25) assert_equal(self.nodes[2].getbalance(), 37.5) # Shield coinbase utxos from any node 2 taddr, and set fee to 0 result = self.nodes[2].z_shieldcoinbase("*", myzaddr, 0)
def run_test (self): print "Mining blocks..." self.nodes[0].generate(100) self.sync_all() self.nodes[1].generate(101) self.sync_all() mytaddr = self.nodes[0].getnewaddress() # where coins were mined myzaddr = self.nodes[0].z_getnewaddress() # Spend coinbase utxos to create three notes of 9.99990000 each recipients = [] recipients.append({"address":myzaddr, "amount":Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Check balance resp = self.nodes[0].z_getbalance(myzaddr) assert_equal(Decimal(resp), Decimal('9.9999') * 3 ) # 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 = [] recipients.append({"address":self.nodes[2].z_getnewaddress(), "amount":Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) # 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 = [] recipients.append({"address":self.nodes[2].z_getnewaddress(), "amount":Decimal('18')}) recipients.append({"address":self.nodes[2].z_getnewaddress(), "amount":Decimal('11.9997') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients) # Wait for Tx 2 to begin executing... for x in xrange(1, 60): results = self.nodes[0].z_getoperationstatus([myopid]) status = results[0]["status"] if status == "executing": break time.sleep(1) # 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 wait_and_assert_operationid_status(self.nodes[0], myopid) # 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'))
def run_test(self): # z_sendmany is expected to fail if tx size breaks limit myzaddr = self.nodes[0].z_getnewaddress() recipients = [] num_t_recipients = 1000 num_z_recipients = 2100 amount_per_recipient = Decimal('0.00000001') errorString = '' for i in range(0, num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({ "address": newtaddr, "amount": amount_per_recipient }) for i in range(0, num_z_recipients): newzaddr = self.nodes[2].z_getnewaddress() recipients.append({ "address": newzaddr, "amount": amount_per_recipient }) # Issue #2759 Workaround START # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process # loop above to create new addresses, that when z_sendmany is called with a large amount of # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP # connection into a good state to handle a large amount of data in recipients. self.nodes[0].getinfo() # Issue #2759 Workaround END try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException as e: errorString = e.error['message'] assert ("size of raw transaction would be larger than limit" in errorString) # add zaddr to node 2 myzaddr = self.nodes[2].z_getnewaddress() # add taddr to node 2 mytaddr = self.nodes[2].getnewaddress() # send from node 0 to node 2 taddr mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0) self.sync_all() self.nodes[0].generate(1) self.sync_all() # send node 2 taddr to zaddr recipients = [] recipients.append({"address": myzaddr, "amount": 7}) opid = self.nodes[2].z_sendmany(mytaddr, recipients) mytxid = wait_and_assert_operationid_status(self.nodes[2], opid) self.sync_all() # check balances zsendmanynotevalue = Decimal('7.0') zsendmanyfee = DEFAULT_FEE node2utxobalance = Decimal( '260.00000000') - zsendmanynotevalue - zsendmanyfee # check shielded balance status with getwalletinfo wallet_info = self.nodes[2].getwalletinfo() assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]), zsendmanynotevalue) assert_equal(Decimal(wallet_info["shielded_balance"]), Decimal('0.0')) self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), node2utxobalance) assert_equal(self.nodes[2].getbalance("*"), node2utxobalance) # check zaddr balance with z_getbalance zbalance = zsendmanynotevalue assert_equal(self.nodes[2].z_getbalance(myzaddr), zbalance) # check via z_gettotalbalance resp = self.nodes[2].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), node2utxobalance) assert_equal(Decimal(resp["private"]), zbalance) assert_equal(Decimal(resp["total"]), node2utxobalance + zbalance) # check confirmed shielded balance with getwalletinfo wallet_info = self.nodes[2].getwalletinfo() assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]), Decimal('0.0')) assert_equal(Decimal(wallet_info["shielded_balance"]), zsendmanynotevalue) # there should be at least one Sapling output mytxdetails = self.nodes[2].getrawtransaction(mytxid, 1) assert_greater_than(len(mytxdetails["vShieldedOutput"]), 0) # the Sapling output should take in all the public value assert_equal(mytxdetails["valueBalance"], -zsendmanynotevalue) # send from private note to node 0 and node 2 node0balance = self.nodes[0].getbalance() # The following assertion fails nondeterministically # assert_equal(node0balance, Decimal('25.99798873')) node2balance = self.nodes[2].getbalance() # The following assertion might fail nondeterministically # assert_equal(node2balance, Decimal('16.99799000')) recipients = [] recipients.append({ "address": self.nodes[0].getnewaddress(), "amount": 1 }) recipients.append({ "address": self.nodes[2].getnewaddress(), "amount": 1.0 }) opid = self.nodes[2].z_sendmany(myzaddr, recipients) wait_and_assert_operationid_status(self.nodes[2], opid) zbalance -= Decimal('2.0') + zsendmanyfee self.sync_all() self.nodes[2].generate(1) self.sync_all() node0balance += Decimal('11.0') node2balance += Decimal('1.0') assert_equal(Decimal(self.nodes[0].getbalance()), node0balance) assert_equal(Decimal(self.nodes[0].getbalance("*")), node0balance) assert_equal(Decimal(self.nodes[2].getbalance()), node2balance) assert_equal(Decimal(self.nodes[2].getbalance("*")), node2balance) # Get a new unified account on node 2 & generate a UA n0account0 = self.nodes[0].z_getnewaccount()['account'] n0ua0 = self.nodes[0].z_getaddressforaccount(n0account0)['address'] # Change went to a fresh address, so use `ANY_TADDR` which # should hold the rest of our transparent funds. source = 'ANY_TADDR' recipients = [] recipients.append({"address": n0ua0, "amount": 10}) # If we attempt to spend with the default privacy policy, z_sendmany # fails because it needs to spend transparent coins in a transaction # involving a Unified Address. revealed_senders_msg = 'This transaction requires selecting transparent coins, which is not enabled by default because it will publicly reveal transaction senders and amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedSenders` or weaker if you wish to allow this transaction to proceed anyway.' opid = self.nodes[2].z_sendmany(source, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[2], opid, 'failed', revealed_senders_msg) # We can't create a transaction with an unknown privacy policy. assert_raises_message( JSONRPCException, 'Unknown privacy policy name \'ZcashIsAwesome\'', self.nodes[2].z_sendmany, source, recipients, 1, 0, 'ZcashIsAwesome') # If we set any policy that does not include AllowRevealedSenders, # z_sendmany also fails. for policy in [ 'FullPrivacy', 'AllowRevealedAmounts', 'AllowRevealedRecipients', ]: opid = self.nodes[2].z_sendmany(source, recipients, 1, 0, policy) wait_and_assert_operationid_status(self.nodes[2], opid, 'failed', revealed_senders_msg) # By setting the correct policy, we can create the transaction. opid = self.nodes[2].z_sendmany(source, recipients, 1, 0, 'AllowRevealedSenders') wait_and_assert_operationid_status(self.nodes[2], opid) self.nodes[2].generate(1) self.sync_all() node2balance -= Decimal('10.0') node0balance += Decimal('10.0') assert_equal(Decimal(self.nodes[2].getbalance()), node2balance) assert_equal(Decimal(self.nodes[0].getbalance()), node0balance) self.check_balance(0, 0, n0ua0, {'sapling': 10}) # Send some funds to a specific legacy taddr that we can spend from recipients = [] recipients.append({"address": mytaddr, "amount": 5}) # If we attempt to spend with the default privacy policy, z_sendmany # returns an error because it needs to create a transparent recipient in # a transaction involving a Unified Address. revealed_recipients_msg = "This transaction would have transparent recipients, which is not enabled by default because it will publicly reveal transaction recipients and amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedRecipients` or weaker if you wish to allow this transaction to proceed anyway." opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], opid, 'failed', revealed_recipients_msg) # If we set any policy that does not include AllowRevealedRecipients, # z_sendmany also returns an error. for policy in [ 'FullPrivacy', 'AllowRevealedAmounts', 'AllowRevealedSenders', 'AllowLinkingAccountAddresses', ]: opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0, policy) wait_and_assert_operationid_status(self.nodes[0], opid, 'failed', revealed_recipients_msg) # By setting the correct policy, we can create the transaction. opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0, 'AllowRevealedRecipients') wait_and_assert_operationid_status(self.nodes[0], opid) self.nodes[0].generate(1) self.sync_all() node2balance += Decimal('5.0') self.check_balance(0, 0, n0ua0, {'sapling': 5}) assert_equal(Decimal(self.nodes[2].getbalance()), node2balance) # Send some funds to a legacy sapling address that we can spend from recipients = [] recipients.append({"address": myzaddr, "amount": 3}) opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], opid) self.nodes[0].generate(1) self.sync_all() zbalance += Decimal('3.0') self.check_balance(0, 0, n0ua0, {'sapling': 2}) assert_equal(Decimal(self.nodes[2].z_getbalance(myzaddr)), zbalance) # Send funds back from the legacy taddr to the UA. This requires # AllowRevealedSenders, but we can also use any weaker policy that # includes it. recipients = [] recipients.append({"address": n0ua0, "amount": 4}) opid = self.nodes[2].z_sendmany(mytaddr, recipients, 1, 0, 'AllowFullyTransparent') wait_and_assert_operationid_status(self.nodes[2], opid) self.nodes[2].generate(1) self.sync_all() node2balance -= Decimal('4.0') self.check_balance(0, 0, n0ua0, {'sapling': 6}) assert_equal(Decimal(self.nodes[2].getbalance()), node2balance) # Send funds back from the legacy zaddr to the UA recipients = [] recipients.append({"address": n0ua0, "amount": 2}) opid = self.nodes[2].z_sendmany(myzaddr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[2], opid) self.nodes[2].generate(1) self.sync_all() zbalance -= Decimal('2.0') self.check_balance(0, 0, n0ua0, {'sapling': 8}) assert_equal(Decimal(self.nodes[2].z_getbalance(myzaddr)), zbalance) # # Test that z_sendmany avoids UA linkability unless we allow it. # # Generate a new account with two new addresses. n1account = self.nodes[1].z_getnewaccount()['account'] n1ua0 = self.nodes[1].z_getaddressforaccount(n1account)['address'] n1ua1 = self.nodes[1].z_getaddressforaccount(n1account)['address'] # Send funds to the transparent receivers of both addresses. for ua in [n1ua0, n1ua1]: taddr = self.nodes[1].z_listunifiedreceivers(ua)['p2pkh'] self.nodes[0].sendtoaddress(taddr, 2) self.sync_all() self.nodes[2].generate(1) self.sync_all() # The account should see all funds. assert_equal( self.nodes[1].z_getbalanceforaccount(n1account)['pools'], {'transparent': { 'valueZat': 4 * COIN }}, ) # The addresses should see only the transparent funds sent to them. assert_equal(self.nodes[1].z_getbalance(n1ua0), 2) assert_equal(self.nodes[1].z_getbalance(n1ua1), 2) # If we try to send 3 ZEC from n1ua0, it will fail with too-few funds. recipients = [{"address": n0ua0, "amount": 3}] linked_addrs_msg = 'Insufficient funds: have 2.00, need 3.00 (This transaction may require selecting transparent coins that were sent to multiple Unified Addresses, which is not enabled by default because it would create a public link between the transparent receivers of these addresses. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowLinkingAccountAddresses` or weaker if you wish to allow this transaction to proceed anyway.)' opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', linked_addrs_msg) # If we try it again with any policy that is too strong, it also fails. for policy in [ 'FullPrivacy', 'AllowRevealedAmounts', 'AllowRevealedRecipients', 'AllowRevealedSenders', 'AllowFullyTransparent', ]: opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, policy) wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', linked_addrs_msg) # Once we provide a sufficiently-weak policy, the transaction succeeds. opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'AllowLinkingAccountAddresses') wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() self.nodes[2].generate(1) self.sync_all() # The account should see the remaining funds, and they should have been # sent to the Sapling change address (because NU5 is not active). assert_equal( self.nodes[1].z_getbalanceforaccount(n1account)['pools'], {'sapling': { 'valueZat': 1 * COIN }}, ) # The addresses should both show the same balance, as they both show the # Sapling balance. assert_equal(self.nodes[1].z_getbalance(n1ua0), 1) assert_equal(self.nodes[1].z_getbalance(n1ua1), 1) # # Test NoPrivacy policy # # Send some legacy transparent funds to n1ua0, creating Sapling outputs. recipients = [{"address": n1ua0, "amount": 10}] # This requires the AllowRevealedSenders policy... opid = self.nodes[2].z_sendmany('ANY_TADDR', recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[2], opid, 'failed', revealed_senders_msg) # ... which we can always override with the NoPrivacy policy. opid = self.nodes[2].z_sendmany('ANY_TADDR', recipients, 1, 0, 'NoPrivacy') wait_and_assert_operationid_status(self.nodes[2], opid) self.sync_all() self.nodes[2].generate(1) self.sync_all() # Send some funds from node 1's account to a transparent address. recipients = [{"address": mytaddr, "amount": 5}] # This requires the AllowRevealedRecipients policy... opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', revealed_recipients_msg) # ... which we can always override with the NoPrivacy policy. opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'NoPrivacy') wait_and_assert_operationid_status(self.nodes[1], opid) # Activate NU5 self.sync_all() self.nodes[1].generate(10) self.sync_all() # # Test AllowRevealedAmounts policy # assert_equal( { 'pools': { 'sapling': { 'valueZat': 600000000 } }, 'minimum_confirmations': 1 }, self.nodes[1].z_getbalanceforaccount(n1account)) # Sending some funds to the Orchard pool in n0account0 ... n0ua1 = self.nodes[0].z_getaddressforaccount(n0account0, ["orchard"])['address'] recipients = [{"address": n0ua1, "amount": 6}] # Should fail under default and 'FullPrivacy' policies ... revealed_amounts_msg = 'Sending from the Sapling shielded pool to the Orchard shielded pool is not enabled by default because it will publicly reveal the transaction amount. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedAmounts` or weaker if you wish to allow this transaction to proceed anyway.' opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', revealed_amounts_msg) opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'FullPrivacy') wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', revealed_amounts_msg) # Should succeed under 'AllowRevealedAmounts' opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'AllowRevealedAmounts') wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() self.nodes[1].generate(1) self.sync_all() assert_equal( { 'pools': { 'sapling': { 'valueZat': 1100000000 }, 'orchard': { 'valueZat': 600000000 } }, 'minimum_confirmations': 1 }, self.nodes[0].z_getbalanceforaccount(n0account0)) # A total that requires selecting from both pools should fail under default and # FullPrivacy policies... recipients = [{"address": n1ua0, "amount": 15}] opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], opid, 'failed', revealed_amounts_msg) opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0, 'FullPrivacy') wait_and_assert_operationid_status(self.nodes[0], opid, 'failed', revealed_amounts_msg) # Should succeed under 'AllowRevealedAmounts' opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0, 'AllowRevealedAmounts') wait_and_assert_operationid_status(self.nodes[0], opid) self.sync_all() self.nodes[1].generate(1) self.sync_all() # All funds should be received to the Orchard pool assert_equal( { 'pools': { 'orchard': { 'valueZat': 1500000000 } }, 'minimum_confirmations': 1 }, self.nodes[1].z_getbalanceforaccount(n1account)) # And all change should be optimistically shielded assert_equal( { 'pools': { 'orchard': { 'valueZat': 200000000 } }, 'minimum_confirmations': 1 }, self.nodes[0].z_getbalanceforaccount(n0account0))
def run_test(self, test): print "Mining blocks..." test.nodes[0].generate(1) do_not_shield_taddr = test.nodes[0].getnewaddress() test.nodes[0].generate(4) walletinfo = test.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) test.sync_all() test.nodes[2].generate(1) test.nodes[2].getnewaddress() test.nodes[2].generate(1) test.nodes[2].getnewaddress() test.nodes[2].generate(1) test.sync_all() test.nodes[1].generate(101) test.sync_all() assert_equal(test.nodes[0].getbalance(), 50) assert_equal(test.nodes[1].getbalance(), 10) assert_equal(test.nodes[2].getbalance(), 30) # Shield the coinbase myzaddr = test.nodes[0].z_getnewaddress(self.addr_type) result = test.nodes[0].z_shieldcoinbase("*", myzaddr, 0) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Prepare some UTXOs and notes for merging mytaddr = test.nodes[0].getnewaddress() mytaddr2 = test.nodes[0].getnewaddress() mytaddr3 = test.nodes[0].getnewaddress() result = test.nodes[0].z_sendmany(myzaddr, [ {'address': do_not_shield_taddr, 'amount': 10}, {'address': mytaddr, 'amount': 10}, {'address': mytaddr2, 'amount': 10}, {'address': mytaddr3, 'amount': 10}, ], 1, 0) wait_and_assert_operationid_status(test.nodes[0], result) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Merging will fail because from arguments need to be in an array assert_mergetoaddress_exception( "JSON value is not an array as expected", lambda: test.nodes[0].z_mergetoaddress("notanarray", myzaddr)) # Merging will fail when trying to spend from watch-only address test.nodes[2].importaddress(mytaddr) assert_mergetoaddress_exception( "Could not find any funds to merge.", lambda: test.nodes[2].z_mergetoaddress([mytaddr], myzaddr)) # Merging will fail because fee is negative assert_mergetoaddress_exception( "Amount out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, -1)) # Merging will fail because fee is larger than MAX_MONEY assert_mergetoaddress_exception( "Amount out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('21000000.00000001'))) # Merging will fail because fee is larger than sum of UTXOs assert_mergetoaddress_exception( "Insufficient funds, have 50.00, which is less than miners fee 999.00", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 999)) # Merging will fail because transparent limit parameter must be at least 0 assert_mergetoaddress_exception( "Limit on maximum number of UTXOs cannot be negative", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), -1)) # Merging will fail because transparent limit parameter is absurdly large assert_mergetoaddress_exception( "JSON integer out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 99999999999999)) # Merging will fail because shielded limit parameter must be at least 0 assert_mergetoaddress_exception( "Limit on maximum number of notes cannot be negative", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, -1)) # Merging will fail because shielded limit parameter is absurdly large assert_mergetoaddress_exception( "JSON integer out of range", lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, 99999999999999)) # Merging will fail for this specific case where it would spend a fee and do nothing assert_mergetoaddress_exception( "Destination address is also the only source address, and all its funds are already merged.", lambda: test.nodes[0].z_mergetoaddress([mytaddr], mytaddr)) # Merging will fail for this specific case where it would spend a fee and do nothing assert_mergetoaddress_exception( "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress", lambda: test.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], mytaddr)) # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000 result = test.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone assert_equal(test.nodes[0].getbalance(), 10) assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0')) assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000')) assert_equal(test.nodes[1].getbalance(), 40) assert_equal(test.nodes[2].getbalance(), 30) # Shield all notes to another z-addr myzaddr2 = test.nodes[0].z_getnewaddress(self.addr_type) result = test.nodes[0].z_mergetoaddress(self.any_zaddr, myzaddr2, 0) assert_equal(result["mergingUTXOs"], Decimal('0')) assert_equal(result["remainingUTXOs"], Decimal('0')) assert_equal(result["mergingNotes"], Decimal('2')) assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() blockhash = test.nodes[1].generate(1) test.sync_all() assert_equal(len(test.nodes[0].getblock(blockhash[0])['tx']), 2) assert_equal(test.nodes[0].z_getbalance(myzaddr), 0) assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000')) # Shield coinbase UTXOs from any node 2 taddr, and set fee to 0 result = test.nodes[2].z_shieldcoinbase("*", myzaddr, 0) wait_and_assert_operationid_status(test.nodes[2], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() assert_equal(test.nodes[0].getbalance(), 10) assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('30')) assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000')) assert_equal(test.nodes[1].getbalance(), 60) assert_equal(test.nodes[2].getbalance(), 0) # Merge all notes from node 0 into a node 0 taddr, and set fee to 0 result = test.nodes[0].z_mergetoaddress(self.any_zaddr, mytaddr, 0) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() assert_equal(test.nodes[0].getbalance(), Decimal('79.99990000')) assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0')) assert_equal(test.nodes[0].z_getbalance(mytaddr), Decimal('69.99990000')) assert_equal(test.nodes[0].z_getbalance(myzaddr), 0) assert_equal(test.nodes[0].z_getbalance(myzaddr2), 0) assert_equal(test.nodes[1].getbalance(), 70) assert_equal(test.nodes[2].getbalance(), 0) # Merge all node 0 UTXOs together into a node 1 taddr, and set fee to 0 test.nodes[1].getnewaddress() # Ensure we have an empty address n1taddr = test.nodes[1].getnewaddress() result = test.nodes[0].z_mergetoaddress(["ANY_TADDR"], n1taddr, 0) wait_and_assert_operationid_status(test.nodes[0], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() assert_equal(test.nodes[0].getbalance(), 0) assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), 0) assert_equal(test.nodes[0].z_getbalance(mytaddr), 0) assert_equal(test.nodes[0].z_getbalance(myzaddr), 0) assert_equal(test.nodes[1].getbalance(), Decimal('159.99990000')) assert_equal(test.nodes[1].z_getbalance(n1taddr), Decimal('79.99990000')) assert_equal(test.nodes[2].getbalance(), 0) # Generate self.utxos_to_generate regular UTXOs on node 0, and 20 regular UTXOs on node 2 mytaddr = test.nodes[0].getnewaddress() n2taddr = test.nodes[2].getnewaddress() test.nodes[1].generate(1000) test.sync_all() for i in range(self.utxos_to_generate): test.nodes[1].sendtoaddress(mytaddr, 1) for i in range(20): test.nodes[1].sendtoaddress(n2taddr, 1) test.nodes[1].generate(1) test.sync_all() # Merging the UTXOs will conditionally occur over two transactions, since max tx size is 100,000 bytes before Sapling and 2,000,000 after. # We don't verify mergingTransparentValue as UTXOs are not selected in any specific order, so value can change on each test run. # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of UTXOs. result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 99999) assert_equal(result["mergingUTXOs"], self.utxos_in_tx1) assert_equal(result["remainingUTXOs"], self.utxos_in_tx2) assert_equal(result["mergingNotes"], Decimal('0')) assert_equal(result["mergingShieldedValue"], Decimal('0')) assert_equal(result["remainingNotes"], Decimal('0')) assert_equal(result["remainingShieldedValue"], Decimal('0')) remainingTransparentValue = result["remainingTransparentValue"] wait_and_assert_operationid_status(test.nodes[0], result['opid']) # For sapling we do not check that this occurs over two transactions because of the time that it would take if self.utxos_in_tx2 > 0: # Verify that UTXOs are locked (not available for selection) by queuing up another merging operation result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 0) assert_equal(result["mergingUTXOs"], self.utxos_in_tx2) assert_equal(result["mergingTransparentValue"], Decimal(remainingTransparentValue)) assert_equal(result["remainingUTXOs"], Decimal('0')) assert_equal(result["remainingTransparentValue"], Decimal('0')) assert_equal(result["mergingNotes"], Decimal('0')) assert_equal(result["mergingShieldedValue"], Decimal('0')) assert_equal(result["remainingNotes"], Decimal('0')) assert_equal(result["remainingShieldedValue"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected. # 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(test.nodes[:2]) sync_mempools(test.nodes[:2]) # Generate enough blocks to ensure all transactions are mined while test.nodes[1].getmempoolinfo()['size'] > 0: test.nodes[1].generate(1) test.sync_all() # Verify maximum number of UTXOs which node 2 can shield is limited by option -mempooltxinputlimit # This option is used when the limit parameter is set to 0. # -mempooltxinputlimit is not used after overwinter activation if self.test_mempooltxinputlimit: expected_to_merge = 7 expected_remaining = 13 else: expected_to_merge = 20 expected_remaining = 0 result = test.nodes[2].z_mergetoaddress([n2taddr], myzaddr, Decimal('0.0001'), 0) assert_equal(result["mergingUTXOs"], expected_to_merge) assert_equal(result["remainingUTXOs"], expected_remaining) assert_equal(result["mergingNotes"], Decimal('0')) assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[2], result['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Verify maximum number of UTXOs which node 0 can shield is set by default limit parameter of 50 mytaddr = test.nodes[0].getnewaddress() for i in range(100): test.nodes[1].sendtoaddress(mytaddr, 1) test.nodes[1].generate(1) test.sync_all() result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001')) assert_equal(result["mergingUTXOs"], Decimal('50')) assert_equal(result["remainingUTXOs"], Decimal('50')) assert_equal(result["mergingNotes"], Decimal('0')) # Remaining notes are only counted if we are trying to merge any notes assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # Verify maximum number of UTXOs which node 0 can shield can be set by the limit parameter result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001'), 33) assert_equal(result["mergingUTXOs"], Decimal('33')) assert_equal(result["remainingUTXOs"], Decimal('17')) assert_equal(result["mergingNotes"], Decimal('0')) # Remaining notes are only counted if we are trying to merge any notes assert_equal(result["remainingNotes"], Decimal('0')) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit sync_blocks(test.nodes[:2]) sync_mempools(test.nodes[:2]) test.nodes[1].generate(1) test.sync_all() # Verify maximum number of notes which node 0 can shield can be set by the limit parameter # Also check that we can set off a second merge before the first one is complete # myzaddr will have 5 notes if testing before to Sapling activation and 4 otherwise num_notes = len(test.nodes[0].z_listunspent(0)) result1 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) result2 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) # First merge should select from all notes assert_equal(result1["mergingUTXOs"], Decimal('0')) # Remaining UTXOs are only counted if we are trying to merge any UTXOs assert_equal(result1["remainingUTXOs"], Decimal('0')) assert_equal(result1["mergingNotes"], Decimal('2')) assert_equal(result1["remainingNotes"], num_notes - 2) # Second merge should ignore locked notes assert_equal(result2["mergingUTXOs"], Decimal('0')) assert_equal(result2["remainingUTXOs"], Decimal('0')) assert_equal(result2["mergingNotes"], Decimal('2')) assert_equal(result2["remainingNotes"], num_notes - 4) wait_and_assert_operationid_status(test.nodes[0], result1['opid']) wait_and_assert_operationid_status(test.nodes[0], result2['opid']) test.sync_all() test.nodes[1].generate(1) test.sync_all() # Shield both UTXOs and notes to a z-addr result = test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 0, 10, 2) assert_equal(result["mergingUTXOs"], Decimal('10')) assert_equal(result["remainingUTXOs"], Decimal('7')) assert_equal(result["mergingNotes"], Decimal('2')) assert_equal(result["remainingNotes"], num_notes - 4) wait_and_assert_operationid_status(test.nodes[0], result['opid']) # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit sync_blocks(test.nodes[:2]) sync_mempools(test.nodes[:2]) test.nodes[1].generate(1) test.sync_all()
def run_test(self): alice = self.nodes[0].getnewaddress() z_alice = self.nodes[0].z_getnewaddress('sapling') bob = self.nodes[2].getnewaddress() z_bob = self.nodes[2].z_getnewaddress('sapling') print("Splitting network...") self.split_network() # Test dependent txs firstTx = self.nodes[0].sendtoaddress(alice, 0.1) firstTxInfo = self.nodes[0].getrawtransaction(firstTx, 1) assert_equal(firstTxInfo["version"], 4) assert_equal(firstTxInfo["overwintered"], True) assert ("expiryheight" in firstTxInfo) print("First tx expiry height:", firstTxInfo['expiryheight']) # Mine first transaction self.nodes[0].generate(1) for outpoint in firstTxInfo['vout']: if outpoint['value'] == Decimal('0.10000000'): vout = outpoint break inputs = [{ 'txid': firstTx, 'vout': vout['n'], 'scriptPubKey': vout['scriptPubKey']['hex'] }] outputs = {alice: 0.1} rawTx = self.nodes[0].createrawtransaction(inputs, outputs) rawTxSigned = self.nodes[0].signrawtransaction(rawTx) assert (rawTxSigned['complete']) secondTx = self.nodes[0].sendrawtransaction(rawTxSigned['hex']) secondTxInfo = self.nodes[0].getrawtransaction(secondTx, 1) print("Second tx expiry height:", secondTxInfo['expiryheight']) # Mine second, dependent transaction self.nodes[0].generate(1) print("Mine %d competing blocks on Node 2..." % (2 + TX_EXPIRY_DELTA)) blocks = self.nodes[2].generate(2 + TX_EXPIRY_DELTA) print("Connect nodes to force a reorg") connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False print("Syncing blocks") sync_blocks(self.nodes) print("Ensure that both txs are dropped from mempool of node 0") print("Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks']) print("Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks']) assert_equal(set(self.nodes[0].getrawmempool()), set()) assert_equal(set(self.nodes[2].getrawmempool()), set()) ## Shield one of Alice's coinbase funds to her zaddr res = self.nodes[0].z_shieldcoinbase("*", z_alice, DEFAULT_FEE, 1) wait_and_assert_operationid_status(self.nodes[0], res['opid']) self.nodes[0].generate(1) self.sync_all() # Get balance on node 0 bal = self.nodes[0].z_gettotalbalance() print("Balance before zsend, after shielding 10: ", bal) assert_equal(Decimal(bal["private"]), Decimal('97.0') - DEFAULT_FEE) print("Splitting network...") self.split_network() # Create transactions blockheight = self.nodes[0].getblockchaininfo()['blocks'] zsendamount = Decimal('1.0') - DEFAULT_FEE recipients = [] recipients.append({"address": z_bob, "amount": zsendamount}) myopid = self.nodes[0].z_sendmany(z_alice, recipients) persist_shielded = wait_and_assert_operationid_status( self.nodes[0], myopid) persist_transparent = self.nodes[0].sendtoaddress(bob, 0.01) # Verify transparent transaction is version 4 intended for Sapling branch rawtx = self.nodes[0].getrawtransaction(persist_transparent, 1) assert_equal(rawtx["version"], 4) assert_equal(rawtx["overwintered"], True) assert_equal(rawtx["expiryheight"], blockheight + 1 + TX_EXPIRY_DELTA) print( "Blockheight at persist_transparent & persist_shielded creation:", self.nodes[0].getblockchaininfo()['blocks']) print("Expiryheight of persist_transparent:", rawtx['expiryheight']) # Verify shielded transaction is version 4 intended for Sapling branch rawtx = self.nodes[0].getrawtransaction(persist_shielded, 1) print("Expiryheight of persist_shielded", rawtx['expiryheight']) assert_equal(rawtx["version"], 4) assert_equal(rawtx["overwintered"], True) assert_equal(rawtx["expiryheight"], blockheight + 1 + TX_EXPIRY_DELTA) print( "\nBlockheight advances to less than expiry block height. After reorg, txs should persist in mempool" ) assert (persist_transparent in self.nodes[0].getrawmempool()) assert (persist_shielded in self.nodes[0].getrawmempool()) assert_equal(set(self.nodes[2].getrawmempool()), set()) print("mempool node 0:", self.nodes[0].getrawmempool()) print("mempool node 2:", self.nodes[2].getrawmempool()) bal = self.nodes[0].z_gettotalbalance() print( "Printing balance before persist_shielded & persist_transparent are initially mined from mempool", bal) # Txs are mined on node 0; will later be rolled back self.nodes[0].generate(1) print("Node 0 generated 1 block") print("Node 0 height:", self.nodes[0].getblockchaininfo()['blocks']) print("Node 2 height:", self.nodes[2].getblockchaininfo()['blocks']) bal = self.nodes[0].z_gettotalbalance() print( "Printing balance after persist_shielded & persist_transparent are mined:", bal) assert_equal(set(self.nodes[0].getrawmempool()), set()) print("Mine 2 competing blocks on Node 2...") blocks = self.nodes[2].generate(2) for block in blocks: blk = self.nodes[2].getblock(block) print("Height: {0}, Mined block txs: {1}".format( blk["height"], blk["tx"])) print("Connect nodes to force a reorg") connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False print("Syncing blocks") sync_blocks(self.nodes) print("Ensure that txs are back in mempool of node 0") print("Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks']) print("Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks']) print("mempool node 0: ", self.nodes[0].getrawmempool()) print("mempool node 2: ", self.nodes[2].getrawmempool()) assert (persist_transparent in self.nodes[0].getrawmempool()) assert (persist_shielded in self.nodes[0].getrawmempool()) bal = self.nodes[0].z_gettotalbalance() # Mine txs to get them out of the way of mempool sync in split_network() print("Generating another block on node 0 to clear txs from mempool") self.nodes[0].generate(1) assert_equal(set(self.nodes[0].getrawmempool()), set()) sync_blocks(self.nodes) print("Splitting network...") self.split_network() print( "\nBlockheight advances to equal expiry block height. After reorg, txs should persist in mempool" ) myopid = self.nodes[0].z_sendmany(z_alice, recipients) persist_shielded_2 = wait_and_assert_operationid_status( self.nodes[0], myopid) persist_transparent_2 = self.nodes[0].sendtoaddress(bob, 0.01) rawtx_trans = self.nodes[0].getrawtransaction(persist_transparent_2, 1) rawtx_shield = self.nodes[0].getrawtransaction(persist_shielded_2, 1) print("Blockheight node 0 at persist_transparent_2 creation:", self.nodes[0].getblockchaininfo()['blocks']) print("Blockheight node 2 at persist_transparent_2 creation:", self.nodes[2].getblockchaininfo()['blocks']) print("Expiryheight of persist_transparent_2:", rawtx_trans['expiryheight']) print("Expiryheight of persist_shielded_2:", rawtx_shield['expiryheight']) blocks = self.nodes[2].generate(4) for block in blocks: blk = self.nodes[2].getblock(block) print("Height: {0}, Mined block txs: {1}".format( blk["height"], blk["tx"])) print("Connect nodes to force a reorg") connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False sync_blocks(self.nodes) print( "Ensure that persist_transparent_2 & persist_shielded_2 are in mempool at expiry block height" ) print("Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks']) print("Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks']) print("mempool node 0: ", self.nodes[0].getrawmempool()) print("mempool node 2: ", self.nodes[2].getrawmempool()) assert (persist_transparent_2 in self.nodes[0].getrawmempool()) assert (persist_shielded_2 in self.nodes[0].getrawmempool()) # Mine persist txs to get them out of the way of mempool sync in split_network() self.nodes[0].generate(1) assert_equal(set(self.nodes[0].getrawmempool()), set()) sync_blocks(self.nodes) print( "Balance after persist_shielded_2 is mined to remove from mempool: ", self.nodes[0].z_gettotalbalance()) print("Splitting network...") self.split_network() print( "\nBlockheight advances to greater than expiry block height. After reorg, txs should expire from mempool" ) print("Balance before expire_shielded is sent: ", self.nodes[0].z_gettotalbalance()) myopid = self.nodes[0].z_sendmany(z_alice, recipients) expire_shielded = wait_and_assert_operationid_status( self.nodes[0], myopid) expire_transparent = self.nodes[0].sendtoaddress(bob, 0.01) print("Blockheight node 0 at expire_transparent creation:", self.nodes[0].getblockchaininfo()['blocks']) print("Blockheight node 2 at expire_shielded creation:", self.nodes[2].getblockchaininfo()['blocks']) print( "Expiryheight of expire_transparent:", self.nodes[0].getrawtransaction(expire_transparent, 1)['expiryheight']) print( "Expiryheight of expire_shielded:", self.nodes[0].getrawtransaction(expire_shielded, 1)['expiryheight']) assert (expire_transparent in self.nodes[0].getrawmempool()) assert (expire_shielded in self.nodes[0].getrawmempool()) blocks = self.nodes[2].generate(1 + TX_EXPIRY_DELTA + 1) for block in blocks: blk = self.nodes[2].getblock(block) print("Height: {0}, Mined block txs: {1}".format( blk["height"], blk["tx"])) print("Connect nodes to force a reorg") connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False sync_blocks(self.nodes) print( "Ensure that expire_transparent & expire_shielded are not in mempool after expiry block height" ) print("mempool node 0: ", self.nodes[0].getrawmempool()) print("mempool node 2: ", self.nodes[2].getrawmempool()) assert_equal(set(self.nodes[0].getrawmempool()), set()) print("Ensure balance of node 0 is correct") bal = self.nodes[0].z_gettotalbalance() print("Balance after expire_shielded has expired: ", bal) assert_equal(Decimal(bal["private"]), Decimal('95.0') - DEFAULT_FEE) print("Splitting network...") self.split_network() print( "\nBlockheight advances to just before expiring soon threshold. Txs should be rejected from entering mempool." ) print("Balance before expire_shielded is sent: ", self.nodes[0].z_gettotalbalance()) myopid = self.nodes[0].z_sendmany(z_alice, recipients) expire_shielded = wait_and_assert_operationid_status( self.nodes[0], myopid) expire_transparent = self.nodes[0].sendtoaddress(bob, 0.01) print("Blockheight node 0 at expire_transparent creation:", self.nodes[0].getblockchaininfo()['blocks']) print("Blockheight node 2 at expire_shielded creation:", self.nodes[2].getblockchaininfo()['blocks']) print( "Expiryheight of expire_transparent:", self.nodes[0].getrawtransaction(expire_transparent, 1)['expiryheight']) print( "Expiryheight of expire_shielded:", self.nodes[0].getrawtransaction(expire_shielded, 1)['expiryheight']) assert (expire_transparent in self.nodes[0].getrawmempool()) assert (expire_shielded in self.nodes[0].getrawmempool()) blocks = self.nodes[2].generate(1 + TX_EXPIRY_DELTA - TX_EXPIRING_SOON_THRESHOLD - 1) for block in blocks: blk = self.nodes[2].getblock(block) print("Height: {0}, Mined block txs: {1}".format( blk["height"], blk["tx"])) print("Connect nodes to force a reorg") connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False sync_blocks(self.nodes) print( "Ensure that expire_transparent & expire_shielded are in node 0 mempool but not node 2 mempool" ) print("mempool node 0: ", self.nodes[0].getrawmempool()) print("mempool node 2: ", self.nodes[2].getrawmempool()) assert (expire_transparent in self.nodes[0].getrawmempool()) assert (expire_shielded in self.nodes[0].getrawmempool()) assert (expire_transparent not in self.nodes[2].getrawmempool()) assert (expire_shielded not in self.nodes[2].getrawmempool()) # Now try to add the transactions to Node 2 mempool. # Node 2 mempool will accept a transaction since block height has not reached the expiring soon threshold. rawtx = self.nodes[0].getrawtransaction(expire_transparent) self.nodes[2].sendrawtransaction(rawtx) # Generate a block and enter the expiring soon threshold. self.nodes[2].generate(1) # Node 2 mempool will reject a transaction which is expiring soon. try: rawtx = self.nodes[0].getrawtransaction(expire_shielded) self.nodes[2].sendrawtransaction(rawtx) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("tx-expiring-soon" in errorString)
def run_test(self): print "Mining blocks..." print "On REGTEST... \n\treward is {} per block\n\t100 blocks to maturity".format( self._reward) self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], self._reward * 4) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[2].generate(3) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), self._reward * 4) assert_equal(self.nodes[1].getbalance(), self._reward * 1) assert_equal(self.nodes[2].getbalance(), self._reward * 3) mytaddr = self.nodes[0].getnewaddress() myzaddr = self.nodes[0].z_getnewaddress() # Check that Node 2 has payment disclosure disabled. try: self.nodes[2].z_getpaymentdisclosure("invalidtxid", 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("payment disclosure is disabled" in errorString) # Check that Node 0 returns an error for an unknown txid try: self.nodes[0].z_getpaymentdisclosure("invalidtxid", 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("No information available about transaction" in errorString) # Shield coinbase utxos from node 0 of value 40, standard fee of 0.10000 recipients = [{ "address": myzaddr, "amount": Decimal(self._reward * 4) - self._fee }] myopid = self.nodes[0].z_sendmany(mytaddr, recipients) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) # Check the tx has joinsplits assert (len(self.nodes[0].getrawtransaction("" + txid, 1)["vjoinsplit"]) > 0) # Sync mempools self.sync_all() # Confirm that you can't create a payment disclosure for an unconfirmed tx try: self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Transaction has not been confirmed yet" in errorString) try: self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Transaction has not been confirmed yet" in errorString) # Mine tx self.nodes[0].generate(1) self.sync_all() # Confirm that Node 1 cannot create a payment disclosure for a transaction which does not impact its wallet try: self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Transaction does not belong to the wallet" in errorString) # Check that an invalid joinsplit index is rejected try: self.nodes[0].z_getpaymentdisclosure(txid, 1, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Invalid js_index" in errorString) try: self.nodes[0].z_getpaymentdisclosure(txid, -1, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Invalid js_index" in errorString) # Check that an invalid output index is rejected try: self.nodes[0].z_getpaymentdisclosure(txid, 0, 2) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Invalid output_index" in errorString) try: self.nodes[0].z_getpaymentdisclosure(txid, 0, -1) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Invalid output_index" in errorString) # Ask Node 0 to create and validate a payment disclosure for output 0 message = "Here is proof of my payment!" pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, message) result = self.nodes[0].z_validatepaymentdisclosure(pd) assert (result["valid"]) output_value_sum = Decimal(result["value"]) # Ask Node 1 to confirm the payment disclosure is valid result = self.nodes[1].z_validatepaymentdisclosure(pd) assert (result["valid"]) assert_equal(result["message"], message) assert_equal(result["value"], output_value_sum) # Confirm that payment disclosure begins with prefix zpd: assert (pd.startswith("zpd:")) # Confirm that payment disclosure without prefix zpd: fails validation try: self.nodes[1].z_validatepaymentdisclosure(pd[4:]) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("payment disclosure prefix not found" in errorString) # Check that total value of output index 0 and index 1 should equal shielding amount of 40 less standard fee. pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 1) result = self.nodes[0].z_validatepaymentdisclosure(pd) output_value_sum += Decimal(result["value"]) assert_equal(output_value_sum, Decimal(self._reward * 4) - self._fee) # Create a z->z transaction, sending shielded funds from node 0 to node 1 node1zaddr = self.nodes[1].z_getnewaddress() recipients = [{"address": node1zaddr, "amount": Decimal('1')}] myopid = self.nodes[0].z_sendmany(myzaddr, recipients) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Confirm that Node 0 can create a valid payment disclosure pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, "a message of your choice") result = self.nodes[0].z_validatepaymentdisclosure(pd) assert (result["valid"]) # Confirm that Node 1, even as recipient of shielded funds, cannot create a payment disclosure # as the transaction was created by Node 0 and Node 1's payment disclosure database does not # contain the necessary data to do so, where the data would only have been available on Node 0 # when executing z_shieldcoinbase. try: self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ( "Could not find payment disclosure info for the given joinsplit output" in errorString) # Payment disclosures cannot be created for transparent transactions. txid = self.nodes[2].sendtoaddress(mytaddr, 1.0) self.sync_all() # No matter the type of transaction, if it has not been confirmed, it is ignored. try: self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Transaction has not been confirmed yet" in errorString) self.nodes[0].generate(1) self.sync_all() # Confirm that a payment disclosure can only be generated for a shielded transaction. try: self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) assert (False) except JSONRPCException as e: errorString = e.error['message'] assert ("Transaction is not a shielded transaction" in errorString)
def nu_activation_checks(): # Mine block H - 2. After this, the mempool expects # block H - 1, which is the last X block. self.nodes[0].generate(1) self.sync_all() # Mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # Check node 0 shielded balance assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) # Fill the mempool with twice as many transactions as can fit into blocks node0_taddr = self.nodes[0].getnewaddress() x_txids = [] while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000: x_txids.append(self.nodes[1].sendtoaddress( node0_taddr, Decimal('0.001'))) self.sync_all() # Spends should be in the mempool x_mempool = set(self.nodes[0].getrawmempool()) assert_equal(x_mempool, set(x_txids)) # Mine block H - 1. After this, the mempool expects # block H, which is the first Y block. self.nodes[0].generate(1) self.sync_all() # mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # Block H - 1 should contain a subset of the original mempool # (with all other transactions having been dropped) block_txids = self.nodes[0].getblock( self.nodes[0].getbestblockhash())['tx'] assert (len(block_txids) < len(x_txids)) for txid in block_txids[1:]: # Exclude coinbase assert (txid in x_txids) # Create some transparent Y transactions y_txids = [ self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10) ] self.sync_all() # Create a shielded Y transaction recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0')) shielded = wait_and_assert_operationid_status( self.nodes[0], myopid) assert (shielded != None) y_txids.append(shielded) self.sync_all() # Spends should be in the mempool assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids)) # Node 0 note should be unspendable assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0')) # Invalidate block H - 1. block_hm1 = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(block_hm1) # BUG: Ideally, the mempool should now only contain the transactions # that were in block H - 1, the Y transactions having been dropped. # However, because chainActive is not updated until after the transactions # in the disconnected block have been re-added to the mempool, the height # seen by AcceptToMemoryPool is one greater than it should be. This causes # the block H - 1 transactions to be validated against the Y rules, # and rejected because they (obviously) fail. #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:])) assert_equal(set(self.nodes[0].getrawmempool()), set()) # Node 0 note should be spendable again assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) # Reconsider block H - 1. self.nodes[0].reconsiderblock(block_hm1) # Mine blocks on node 1, so that the Y transactions in its mempool # will be cleared. self.nodes[1].generate(6) self.sync_all()
def run_test(self): [alice, bob, charlie, david, miner] = self.nodes # the sender loses 'amount' plus fee; to_addr receives exactly 'amount' def z_send(from_node, from_addr, to_addr, amount): global fee opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}], 1, fee) wait_and_assert_operationid_status(from_node, opid) self.sync_all() miner.generate(1) self.sync_all() def verify_utxos(node, amts, zaddr): amts.sort(reverse=True) txs = node.z_listreceivedbyaddress(zaddr) def cmp_confirmations_high_to_low(a, b): return cmp(b["amount"], a["amount"]) txs.sort(cmp_confirmations_high_to_low) print("Sorted txs", txs) print("amts", amts) try: assert_equal(amts, [tx["amount"] for tx in txs]) for tx in txs: # make sure JoinSplit keys exist and have valid values assert_equal("jsindex" in tx, True) assert_equal("jsoutindex" in tx, True) assert_greater_than(tx["jsindex"], -1) assert_greater_than(tx["jsoutindex"], -1) except AssertionError: logging.error( 'Expected amounts: %r; txs: %r', amts, txs) raise def get_private_balance(node): balance = node.z_gettotalbalance() return balance['private'] def find_imported_key(node, import_zaddr): zaddrs = node.z_listaddresses() assert(import_zaddr in zaddrs) return import_zaddr # Seed Alice with some funds alice.generate(10) self.sync_all() miner.generate(100) self.sync_all() # Shield Alice's coinbase funds to her zaddr alice_zaddr = alice.z_getnewaddress('sprout') res = alice.z_shieldcoinbase("*", alice_zaddr) wait_and_assert_operationid_status(alice, res['opid']) self.sync_all() miner.generate(1) self.sync_all() # Now get a pristine z-address for receiving transfers: bob_zaddr = bob.z_getnewaddress('sprout') verify_utxos(bob, [], bob_zaddr) # TODO: Verify that charlie doesn't have funds in addr # verify_utxos(charlie, []) # the amounts of each txn embodied which generates a single UTXO: amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) # Internal test consistency assertion: assert_greater_than( get_private_balance(alice), reduce(Decimal.__add__, amounts)) logging.info("Sending pre-export txns...") for amount in amounts[0:2]: z_send(alice, alice_zaddr, bob_zaddr, amount) logging.info("Exporting privkey from bob...") bob_privkey = bob.z_exportkey(bob_zaddr) logging.info("Sending post-export txns...") for amount in amounts[2:4]: z_send(alice, alice_zaddr, bob_zaddr, amount) verify_utxos(bob, amounts[:4], bob_zaddr) # verify_utxos(charlie, []) logging.info("Importing bob_privkey into charlie...") # z_importkey rescan defaults to "whenkeyisnew", so should rescan here charlie.z_importkey(bob_privkey) ipk_zaddr = find_imported_key(charlie, bob_zaddr) # z_importkey should have rescanned for new key, so this should pass: verify_utxos(charlie, amounts[:4], ipk_zaddr) # Verify idempotent behavior: charlie.z_importkey(bob_privkey) ipk_zaddr2 = find_imported_key(charlie, bob_zaddr) assert_equal(ipk_zaddr, ipk_zaddr2) # amounts should be unchanged verify_utxos(charlie, amounts[:4], ipk_zaddr2) logging.info("Sending post-import txns...") for amount in amounts[4:]: z_send(alice, alice_zaddr, bob_zaddr, amount) verify_utxos(bob, amounts, bob_zaddr) verify_utxos(charlie, amounts, ipk_zaddr) verify_utxos(charlie, amounts, ipk_zaddr2) # keep track of the fees incurred by bob (his sends) bob_fee = Decimal(0) # Try to reproduce zombie balance reported in #1936 # At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice for amount in amounts[:2]: print("Sending amount from bob to alice: ", amount) z_send(bob, bob_zaddr, alice_zaddr, amount) bob_fee += fee bob_balance = sum(amounts[2:]) - bob_fee assert_equal(bob.z_getbalance(bob_zaddr), bob_balance) # z_import onto new node "david" (blockchain rescan, default or True?) david.z_importkey(bob_privkey) d_ipk_zaddr = find_imported_key(david, bob_zaddr) # Check if amt bob spent is deducted for charlie and david assert_equal(charlie.z_getbalance(ipk_zaddr), bob_balance) assert_equal(david.z_getbalance(d_ipk_zaddr), bob_balance)
def run_test(self): print("Mining blocks...") self.nodes[0].generate(4) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[3].getbalance(), 0) check_value_pool(self.nodes[0], 'sprout', 0) check_value_pool(self.nodes[1], 'sprout', 0) check_value_pool(self.nodes[2], 'sprout', 0) check_value_pool(self.nodes[3], 'sprout', 0) # Send will fail because we are enforcing the consensus rule that # coinbase utxos can only be sent to a zaddr. errorString = "" try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1) except JSONRPCException as e: errorString = e.error['message'] assert_equal( "Coinbase funds can only be sent to a zaddr" in errorString, True) # Prepare to send taddr->zaddr mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Node 3 will test that watch only address utxos are not selected self.nodes[3].importaddress(mytaddr) recipients = [{"address": myzaddr, "amount": Decimal('1')}] myopid = self.nodes[3].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status( self.nodes[3], myopid, "failed", "Insufficient transparent funds, no UTXOs found for taddr from address.", 10) # This send will fail because our wallet does not allow any change when shielding a coinbase utxo, # as it's currently not possible to specify a change address in z_sendmany. recipients = [] recipients.append({ "address": myzaddr, "amount": Decimal('1.23456789') }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) error_result = wait_and_assert_operationid_status_result( self.nodes[0], myopid, "failed", ("Change 8.76542211 not allowed. " "When shielding coinbase funds, the wallet does not allow any change " "as there is currently no way to specify a change address in z_sendmany." ), 10) # Test that the returned status object contains a params field with the operation's input parameters assert_equal(error_result["method"], "z_sendmany") params = error_result["params"] assert_equal(params["fee"], DEFAULT_FEE) # default assert_equal(params["minconf"], Decimal('1')) # default assert_equal(params["fromaddress"], mytaddr) assert_equal(params["amounts"][0]["address"], myzaddr) assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789')) # Add viewing key for myzaddr to Node 3 myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr) self.nodes[3].z_importviewingkey(myviewingkey, "no") # This send will succeed. We send two coinbase utxos totalling 20.0 less a default fee, with no change. shieldvalue = Decimal('20.0') - DEFAULT_FEE recipients = [] recipients.append({"address": myzaddr, "amount": shieldvalue}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # Verify that z_listunspent can return a note that has zero confirmations results = self.nodes[0].z_listunspent() assert (len(results) == 0) results = self.nodes[0].z_listunspent(0) # set minconf to zero assert (len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 0) # Mine the tx self.nodes[1].generate(1) self.sync_all() # Verify that z_listunspent returns one note which has been confirmed results = self.nodes[0].z_listunspent() assert (len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 1) assert_equal(results[0]["spendable"], True) # Verify that z_listunspent returns note for watchonly address on node 3. results = self.nodes[3].z_listunspent(1, 999, True) assert (len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 1) assert_equal(results[0]["spendable"], False) # Verify that z_listunspent returns error when address spending key from node 0 is not available in wallet of node 1. try: results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr]) except JSONRPCException as e: errorString = e.error['message'] assert_equal( "Invalid parameter, spending key for address does not belong to wallet" in errorString, True) # Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid initialized_line = check_node_log(self, 0, myopid + ": z_sendmany initialized", False) finished_line = check_node_log(self, 0, myopid + ": z_sendmany finished", False) assert (initialized_line < finished_line) # check balances (the z_sendmany consumes 3 coinbase utxos) resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('20.0')) assert_equal(Decimal(resp["private"]), Decimal('20.0') - DEFAULT_FEE) assert_equal(Decimal(resp["total"]), Decimal('40.0') - DEFAULT_FEE) # The Sprout value pool should reflect the send sproutvalue = shieldvalue check_value_pool(self.nodes[0], 'sprout', sproutvalue) # A custom fee of 0 is okay. Here the node will send the note value back to itself. recipients = [] recipients.append({ "address": myzaddr, "amount": Decimal('20.0') - DEFAULT_FEE }) myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('0.0')) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('20.0')) assert_equal(Decimal(resp["private"]), Decimal('20.0') - DEFAULT_FEE) assert_equal(Decimal(resp["total"]), Decimal('40.0') - DEFAULT_FEE) # The Sprout value pool should be unchanged check_value_pool(self.nodes[0], 'sprout', sproutvalue) # convert note to transparent funds unshieldvalue = Decimal('10.0') recipients = [] recipients.append({"address": mytaddr, "amount": unshieldvalue}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) assert (mytxid is not None) self.sync_all() # check that priority of the tx sending from a zaddr is not 0 mempool = self.nodes[0].getrawmempool(True) assert (Decimal(mempool[mytxid]['startingpriority']) >= Decimal('1000000000000')) self.nodes[1].generate(1) self.sync_all() # check balances sproutvalue -= unshieldvalue + DEFAULT_FEE resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('30.0')) assert_equal(Decimal(resp["private"]), Decimal('10.0') - 2 * DEFAULT_FEE) assert_equal(Decimal(resp["total"]), Decimal('40.0') - 2 * DEFAULT_FEE) check_value_pool(self.nodes[0], 'sprout', sproutvalue) # z_sendmany will return an error if there is transparent change output considered dust. # UTXO selection in z_sendmany sorts in ascending order, so smallest utxos are consumed first. # At this point in time, unspent notes all have a value of 10.0. recipients = [] amount = Decimal('10.0') - DEFAULT_FEE - Decimal( '0.00000001' ) # this leaves change at 1 zatoshi less than dust threshold recipients.append({ "address": self.nodes[0].getnewaddress(), "amount": amount }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status( self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)" ) # Send will fail because send amount is too big, even when including coinbase utxos errorString = "" try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Insufficient funds" in errorString, True) # z_sendmany will fail because of insufficient funds recipients = [] recipients.append({ "address": self.nodes[1].getnewaddress(), "amount": Decimal('10000.0') }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status( self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.00001") myopid = self.nodes[0].z_sendmany(myzaddr, recipients) wait_and_assert_operationid_status( self.nodes[0], myopid, "failed", "Insufficient shielded funds, have 9.99998, need 10000.00001") # Send will fail because of insufficient funds unless sender uses coinbase utxos try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21) except JSONRPCException as e: errorString = e.error['message'] assert_equal( "Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr" in errorString, True) # Verify that mempools accept tx with joinsplits which have at least the default z_sendmany fee. # If this test passes, it confirms that issue #1851 has been resolved, where sending from # a zaddr to 1385 taddr recipients fails because the default fee was considered too low # given the tx size, resulting in mempool rejection. errorString = '' recipients = [] num_t_recipients = 2500 amount_per_recipient = Decimal('0.00000546') # dust threshold # Note that regtest chainparams does not require standard tx, so setting the amount to be # less than the dust threshold, e.g. 0.00000001 will not result in mempool rejection. start_time = timeit.default_timer() for i in range(0, num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({ "address": newtaddr, "amount": amount_per_recipient }) elapsed = timeit.default_timer() - start_time print("...invoked getnewaddress() {} times in {} seconds".format( num_t_recipients, elapsed)) # Issue #2263 Workaround START # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process # loop above to create new addresses, that when z_sendmany is called with a large amount of # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP # connection into a good state to handle a large amount of data in recipients. self.nodes[0].getinfo() # Issue #2263 Workaround END myopid = self.nodes[0].z_sendmany(myzaddr, recipients) try: wait_and_assert_operationid_status(self.nodes[0], myopid) except JSONRPCException as e: print("JSONRPC error: " + e.error['message']) assert (False) except Exception as e: print("Unexpected exception caught during testing: ", e.error['message'], str(sys.exc_info()[0])) assert (False) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check balance node2balance = amount_per_recipient * num_t_recipients sproutvalue -= node2balance + DEFAULT_FEE assert_equal(self.nodes[2].getbalance(), node2balance) check_value_pool(self.nodes[0], 'sprout', sproutvalue) # Send will fail because fee is negative try: self.nodes[0].z_sendmany(myzaddr, recipients, 1, -1) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Amount out of range" in errorString, True) # Send will fail because fee is larger than MAX_MONEY try: self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('21000000.00000001')) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Amount out of range" in errorString, True) # Send will fail because fee is larger than sum of outputs try: self.nodes[0].z_sendmany( myzaddr, recipients, 1, (amount_per_recipient * num_t_recipients) + Decimal('0.00000001')) except JSONRPCException as e: errorString = e.error['message'] assert_equal("is greater than the sum of outputs" in errorString, True) # Send will succeed because the balance of non-coinbase utxos is 10.0 try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 9) except JSONRPCException: assert (False) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check balance node2balance = node2balance + 9 assert_equal(self.nodes[2].getbalance(), node2balance) # Check that chained joinsplits in a single tx are created successfully. recipients = [] num_recipients = 3 amount_per_recipient = Decimal('0.002') minconf = 1 send_amount = num_recipients * amount_per_recipient custom_fee = Decimal('0.00012345') zbalance = self.nodes[0].z_getbalance(myzaddr) for i in range(0, num_recipients): newzaddr = self.nodes[2].z_getnewaddress('sprout') recipients.append({ "address": newzaddr, "amount": amount_per_recipient }) myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, custom_fee) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check balances and unspent notes resp = self.nodes[2].z_gettotalbalance() assert_equal(Decimal(resp["private"]), send_amount) notes = self.nodes[2].z_listunspent() sum_of_notes = sum([note["amount"] for note in notes]) assert_equal(Decimal(resp["private"]), sum_of_notes) resp = self.nodes[0].z_getbalance(myzaddr) assert_equal(Decimal(resp), zbalance - custom_fee - send_amount) sproutvalue -= custom_fee check_value_pool(self.nodes[0], 'sprout', sproutvalue) notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr]) sum_of_notes = sum([note["amount"] for note in notes]) assert_equal(Decimal(resp), sum_of_notes)
def run_test(self): # Sanity-check the test harness self.nodes[0].generate(101) assert_equal(self.nodes[0].getblockcount(), 101) self.sync_all() # Node 0 shields some funds dest_addr = self.nodes[0].z_getnewaddress(POOL_NAME.lower()) taddr0 = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('10')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(dest_addr), Decimal('10')) # Verify size of shielded pool self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('10')) self.assert_pool_balance(self.nodes[1], POOL_NAME.lower(), Decimal('10')) self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('10')) # Relaunch node 0 with in-memory size of value pools set to zero. self.restart_and_sync_node(0, TURNSTILE_ARGS) # Verify size of shielded pool self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('0')) self.assert_pool_balance(self.nodes[1], POOL_NAME.lower(), Decimal('10')) self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('10')) # Node 0 creates an unshielding transaction recipients = [] recipients.append({"address": taddr0, "amount": Decimal('1')}) myopid = self.nodes[0].z_sendmany(dest_addr, recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) # Verify transaction appears in mempool of nodes self.sync_all() assert(mytxid in self.nodes[0].getrawmempool()) assert(mytxid in self.nodes[1].getrawmempool()) assert(mytxid in self.nodes[2].getrawmempool()) # Node 0 mines a block count = self.nodes[0].getblockcount() self.nodes[0].generate(1) self.sync_all() # Verify the mined block does not contain the unshielding transaction block = self.nodes[0].getblock(self.nodes[0].getbestblockhash()) assert_equal(len(block["tx"]), 1) assert_equal(block["height"], count + 1) # Stop node 0 and check logs to verify the miner excluded the transaction from the block self.nodes[0].stop() bitcoind_processes[0].wait() logpath = self.options.tmpdir + "/node0/regtest/debug.log" foundErrorMsg = False with open(logpath, "r") as myfile: logdata = myfile.readlines() for logline in logdata: if "CreateNewBlock(): tx " + mytxid + " appears to violate " + POOL_NAME.capitalize() + " turnstile" in logline: foundErrorMsg = True break assert(foundErrorMsg) # Launch node 0 with in-memory size of value pools set to zero. self.start_and_sync_node(0, TURNSTILE_ARGS) # Node 1 mines a block oldhash = self.nodes[0].getbestblockhash() self.nodes[1].generate(1) newhash = self.nodes[1].getbestblockhash() # Verify block contains the unshielding transaction assert(mytxid in self.nodes[1].getblock(newhash)["tx"]) # Verify nodes 1 and 2 have accepted the block as valid sync_blocks(self.nodes[1:3]) sync_mempools(self.nodes[1:3]) assert_equal(len(self.nodes[1].getrawmempool()), 0) assert_equal(len(self.nodes[2].getrawmempool()), 0) # Verify node 0 has not accepted the block assert_equal(oldhash, self.nodes[0].getbestblockhash()) assert(mytxid in self.nodes[0].getrawmempool()) self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('0')) # Verify size of shielded pool self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('0')) self.assert_pool_balance(self.nodes[1], POOL_NAME.lower(), Decimal('9')) self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('9')) # Stop node 0 and check logs to verify the block was rejected as a turnstile violation self.nodes[0].stop() bitcoind_processes[0].wait() logpath = self.options.tmpdir + "/node0/regtest/debug.log" foundConnectBlockErrorMsg = False foundInvalidBlockErrorMsg = False foundConnectTipErrorMsg = False with open(logpath, "r") as myfile: logdata = myfile.readlines() for logline in logdata: if "ConnectBlock(): turnstile violation in " + POOL_NAME.capitalize() + " shielded value pool" in logline: foundConnectBlockErrorMsg = True elif "InvalidChainFound: invalid block=" + newhash in logline: foundInvalidBlockErrorMsg = True elif "ConnectTip(): ConnectBlock " + newhash + " failed" in logline: foundConnectTipErrorMsg = True assert(foundConnectBlockErrorMsg and foundInvalidBlockErrorMsg and foundConnectTipErrorMsg) # Launch node 0 without overriding the pool size, so the node can sync with rest of network. self.start_and_sync_node(0) assert_equal(newhash, self.nodes[0].getbestblockhash())
newzaddr = self.nodes[2].z_getnewaddress() recipients.append({"address":newzaddr, "amount":amount_per_recipient}) try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException,e: errorString = e.error['message'] assert("Invalid parameter, too many zaddr outputs" in errorString) # add zaddr to node 2 myzaddr = self.nodes[2].z_getnewaddress() # send node 2 taddr to zaddr recipients = [] recipients.append({"address":myzaddr, "amount":7}) mytxid = wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(mytaddr, recipients)) self.sync_all() self.nodes[2].generate(1) self.sync_all() # check balances zsendmanynotevalue = Decimal('7.0') zsendmanyfee = Decimal('0.0001') node2utxobalance = Decimal('23.998') - zsendmanynotevalue - zsendmanyfee assert_equal(self.nodes[2].getbalance(), node2utxobalance) assert_equal(self.nodes[2].getbalance("*"), node2utxobalance) # check zaddr balance assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue)
assert(False) except JSONRPCException,e: errorString = e.error['message'] assert_equal("JSON integer out of range" in errorString, True) # Merging will fail for this specific case where it would spend a fee and do nothing try: self.nodes[0].z_mergetoaddress([mytaddr], mytaddr) assert(False) except JSONRPCException,e: errorString = e.error['message'] assert_equal("Destination address is also the only source address, and all its funds are already merged" in errorString, True) # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000 result = self.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr) wait_and_assert_operationid_status(self.nodes[0], result['opid']) 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')) assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000')) assert_equal(self.nodes[1].getbalance(), 40) assert_equal(self.nodes[2].getbalance(), 30) # Shield all notes to another z-addr myzaddr2 = self.nodes[0].z_getnewaddress() result = self.nodes[0].z_mergetoaddress(["ANY_ZADDR"], myzaddr2, 0) assert_equal(result["mergingUTXOs"], Decimal('0'))
def run_test(self): [alice, bob, charlie, miner] = self.nodes # the sender loses 'amount' plus fee; to_addr receives exactly 'amount' def z_send(from_node, from_addr, to_addr, amount): global fee opid = from_node.z_sendmany(from_addr, [{ "address": to_addr, "amount": Decimal(amount) }], 1, fee) wait_and_assert_operationid_status(from_node, opid) self.sync_all() miner.generate(1) self.sync_all() def verify_utxos(node, amts, zaddr): amts.sort(reverse=True) txs = node.z_listreceivedbyaddress(zaddr) def cmp_confirmations_high_to_low(a, b): return cmp(b["amount"], a["amount"]) txs.sort(cmp_confirmations_high_to_low) try: assert_equal(amts, [tx["amount"] for tx in txs]) except AssertionError: logging.error('Expected amounts: %r; txs: %r', amts, txs) raise def get_private_balance(node): balance = node.z_gettotalbalance() return balance['private'] def find_imported_zaddr(node, import_zaddr): zaddrs = node.z_listaddresses() assert (import_zaddr in zaddrs) return import_zaddr # activate sapling alice.generate(102) self.sync_all() # sanity-check the test harness assert_equal(self.nodes[0].getblockcount(), 102) # shield alice's coinbase funds to her zaddr alice_zaddr = alice.z_getnewaddress('sapling') res = alice.z_shieldcoinbase("*", alice_zaddr) wait_and_assert_operationid_status(alice, res['opid']) self.sync_all() miner.generate(1) self.sync_all() amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) # internal test consistency assertion: assert_greater_than(get_private_balance(alice), reduce(Decimal.__add__, amounts)) # now get a pristine z-address for receiving transfers: bob_zaddr = bob.z_getnewaddress('sapling') verify_utxos(bob, [], bob_zaddr) logging.info("sending pre-export txns...") for amount in amounts[0:2]: z_send(alice, alice_zaddr, bob_zaddr, amount) logging.info("exporting ivk from bob...") bob_ivk = bob.z_exportviewingkey(bob_zaddr) logging.info("sending post-export txns...") for amount in amounts[2:4]: z_send(alice, alice_zaddr, bob_zaddr, amount) verify_utxos(bob, amounts[:4], bob_zaddr) logging.info("importing bob_ivk into charlie...") # we need to pass bob_zaddr since it's a sapling address charlie.z_importviewingkey(bob_ivk, 'yes', 0, bob_zaddr) # z_importkey should have rescanned for new key, so this should pass: verify_utxos(charlie, amounts[:4], bob_zaddr) # verify idempotent behavior: charlie.z_importviewingkey(bob_ivk, 'yes', 0, bob_zaddr) verify_utxos(charlie, amounts[:4], bob_zaddr) logging.info("Sending post-import txns...") for amount in amounts[4:]: z_send(alice, alice_zaddr, bob_zaddr, amount) verify_utxos(bob, amounts, bob_zaddr) verify_utxos(charlie, amounts, bob_zaddr)
def run_test(self): self.nodes[0].generate(100) self.sync_all() # Mine three blocks. After this, nodes[0] blocks # 1, 2, and 3 are spend-able. self.nodes[1].generate(3) self.sync_all() # Check 1: z_sendmany is limited by -mempooltxinputlimit # Add zaddr to node 0 node0_zaddr = self.nodes[0].z_getnewaddress('sprout') # Send three inputs from node 0 taddr to zaddr to get out of coinbase node0_taddr = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({"address":node0_zaddr, "amount":Decimal('30.0')-Decimal('0.0001')}) # utxo amount less fee myopid = self.nodes[0].z_sendmany(node0_taddr, recipients) # Spend should fail due to -mempooltxinputlimit wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Too many transparent inputs 3 > limit 2", 120) # Mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # Reduce amount to only use two inputs spend_zaddr_amount = Decimal('20.0') - Decimal('0.0001') spend_zaddr_id = self.call_z_sendmany(node0_taddr, node0_zaddr, spend_zaddr_amount) # utxo amount less fee self.sync_all() # Spend should be in the mempool assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_zaddr_id ])) self.nodes[0].generate(1) self.sync_all() # mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # Check 2: sendfrom is limited by -mempooltxinputlimit recipients = [] spend_taddr_amount = spend_zaddr_amount - Decimal('0.0001') spend_taddr_output = Decimal('8') # Create three outputs recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_output}) recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_output}) recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_amount - spend_taddr_output - spend_taddr_output}) myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Should use three UTXOs and fail try: self.nodes[1].sendfrom("", node0_taddr, spend_taddr_amount - Decimal('1')) assert(False) except JSONRPCException,e: msg = e.error['message'] assert_equal("Too many transparent inputs 3 > limit 2", msg)
def test_received_sapling(self, height): self.generate_and_sync(height + 1) taddr = self.nodes[1].getnewaddress() zaddr1 = self.nodes[1].z_getnewaddress('sapling') zaddrExt = self.nodes[2].z_getnewaddress('sapling') txid_taddr = self.nodes[0].sendtoaddress(taddr, 4.0) self.generate_and_sync(height + 2) # Send 1 ZEC to zaddr1 opid = self.nodes[1].z_sendmany(taddr, [ { 'address': zaddr1, 'amount': 1, 'memo': my_memo }, { 'address': zaddrExt, 'amount': 2 }, ]) txid = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() # Decrypted transaction details should be correct pt = self.nodes[1].z_viewtransaction(txid) assert_equal(pt['txid'], txid) assert_equal(len(pt['spends']), 0) assert_equal(len(pt['outputs']), 2) # Outputs are not returned in a defined order but the amounts are deterministic outputs = sorted(pt['outputs'], key=lambda x: x['valueZat']) assert_equal(outputs[0]['type'], 'sapling') assert_equal(outputs[0]['address'], zaddr1) assert_equal(outputs[0]['value'], Decimal('1')) assert_equal(outputs[0]['valueZat'], 100000000) assert_equal(outputs[0]['output'], 0) assert_equal(outputs[0]['outgoing'], False) assert_equal(outputs[0]['memo'], my_memo) assert_equal(outputs[0]['memoStr'], my_memo_str) assert_equal(outputs[1]['type'], 'sapling') assert_equal(outputs[1]['address'], zaddrExt) assert_equal(outputs[1]['value'], Decimal('2')) assert_equal(outputs[1]['valueZat'], 200000000) assert_equal(outputs[1]['output'], 1) assert_equal(outputs[1]['outgoing'], True) assert_equal(outputs[1]['memo'], no_memo) assert 'memoStr' not in outputs[1] r = self.nodes[1].z_listreceivedbyaddress(zaddr1) assert_equal(0, len(r), "Should have received no confirmed note") c = self.nodes[1].z_getnotescount() assert_equal(0, c['sapling'], "Count of confirmed notes should be 0") # No confirmation required, one note should be present r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) assert_equal(1, len(r), "Should have received one (unconfirmed) note") assert_equal(txid, r[0]['txid']) assert_equal(1, r[0]['amount']) assert_equal(100000000, r[0]['amountZat']) assert_false(r[0]['change'], "Note should not be change") assert_equal(my_memo, r[0]['memo']) assert_equal(0, r[0]['confirmations']) assert_equal(-1, r[0]['blockindex']) assert_equal(0, r[0]['blockheight']) c = self.nodes[1].z_getnotescount(0) assert_equal(1, c['sapling'], "Count of unconfirmed notes should be 1") # Confirm transaction (1 ZEC from taddr to zaddr1) self.generate_and_sync(height + 3) # adjust confirmations r[0]['confirmations'] = 1 # adjust blockindex r[0]['blockindex'] = 1 # adjust height r[0]['blockheight'] = height + 3 # Require one confirmation, note should be present assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1)) # Generate some change by sending part of zaddr1 to zaddr2 txidPrev = txid zaddr2 = self.nodes[1].z_getnewaddress('sapling') opid = self.nodes[1].z_sendmany(zaddr1, [{ 'address': zaddr2, 'amount': 0.6 }]) txid = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() self.generate_and_sync(height + 4) # Decrypted transaction details should be correct pt = self.nodes[1].z_viewtransaction(txid) assert_equal(pt['txid'], txid) assert_equal(len(pt['spends']), 1) assert_equal(len(pt['outputs']), 2) assert_equal(pt['spends'][0]['type'], 'sapling') assert_equal(pt['spends'][0]['txidPrev'], txidPrev) assert_equal(pt['spends'][0]['spend'], 0) assert_equal(pt['spends'][0]['outputPrev'], 0) assert_equal(pt['spends'][0]['address'], zaddr1) assert_equal(pt['spends'][0]['value'], Decimal('1.0')) assert_equal(pt['spends'][0]['valueZat'], 100000000) # Outputs are not returned in a defined order but the amounts are deterministic outputs = sorted(pt['outputs'], key=lambda x: x['valueZat']) assert_equal(outputs[0]['type'], 'sapling') assert_equal(outputs[0]['address'], zaddr1) assert_equal(outputs[0]['value'], Decimal('0.4') - DEFAULT_FEE) assert_equal(outputs[0]['valueZat'], 40000000 - DEFAULT_FEE_ZATS) assert_equal(outputs[0]['output'], 1) assert_equal(outputs[0]['outgoing'], False) assert_equal(outputs[0]['memo'], no_memo) assert 'memoStr' not in outputs[0] assert_equal(outputs[1]['type'], 'sapling') assert_equal(outputs[1]['address'], zaddr2) assert_equal(outputs[1]['value'], Decimal('0.6')) assert_equal(outputs[1]['valueZat'], 60000000) assert_equal(outputs[1]['output'], 0) assert_equal(outputs[1]['outgoing'], False) assert_equal(outputs[1]['memo'], no_memo) assert 'memoStr' not in outputs[1] # zaddr1 should have a note with change r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) assert_equal(2, len(r), "zaddr1 Should have received 2 notes") r = sorted(r, key=lambda received: received['amount']) assert_equal(txid, r[0]['txid']) assert_equal(Decimal('0.4') - DEFAULT_FEE, r[0]['amount']) assert_equal(40000000 - DEFAULT_FEE_ZATS, r[0]['amountZat']) assert_equal( r[0]['change'], True, "Note valued at (0.4-" + str(DEFAULT_FEE) + ") should be change") assert_equal(no_memo, r[0]['memo']) # The old note still exists (it's immutable), even though it is spent assert_equal(Decimal('1.0'), r[1]['amount']) assert_equal(100000000, r[1]['amountZat']) assert_equal(r[1]['change'], False, "Note valued at 1.0 should not be change") assert_equal(my_memo, r[1]['memo']) # zaddr2 should not have change r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0) assert_equal(len(r), 1, "zaddr2 Should have received 1 notes") r = sorted(r, key=lambda received: received['amount']) assert_equal(r[0]['txid'], txid) assert_equal(r[0]['amount'], Decimal('0.6')) assert_equal(r[0]['amountZat'], 60000000) assert_equal(r[0]['change'], False, "Note valued at 0.6 should not be change") assert_equal(r[0]['memo'], no_memo) assert 0 <= r[0]['outindex'] < 2 c = self.nodes[1].z_getnotescount(0) assert_equal( c['sapling'], 3, "Count of unconfirmed notes should be 3(2 in zaddr1 + 1 in zaddr2)" ) # As part of UA support, a transparent address is now accepted r = self.nodes[1].z_listreceivedbyaddress(taddr, 0) assert_equal(len(r), 1) assert_equal(r[0]['pool'], 'transparent') assert_equal(r[0]['txid'], txid_taddr) assert_equal(r[0]['amount'], Decimal('4')) assert_equal(r[0]['amountZat'], 400000000) assert_equal(r[0]['confirmations'], 3) assert 0 <= r[0]['outindex'] < 2 # Test unified address node = self.nodes[1] # Create a unified address on one node, try z_listreceivedbyaddress on another node account = self.nodes[0].z_getnewaccount()['account'] r = self.nodes[0].z_getaddressforaccount(account) unified_addr = r['address'] # this address isn't in node1's wallet assert_raises_message(JSONRPCException, "From address does not belong to this node", node.z_listreceivedbyaddress, unified_addr, 0) # create a UA on node1 r = node.z_getnewaccount() account = r['account'] r = node.z_getaddressforaccount(account) unified_addr = r['address'] receivers = node.z_listunifiedreceivers(unified_addr) assert_equal(len(receivers), 3) assert 'p2pkh' in receivers assert 'sapling' in receivers assert 'orchard' in receivers assert_raises_message( JSONRPCException, "The provided address is a bare receiver from a Unified Address in this wallet.", node.z_listreceivedbyaddress, receivers['p2pkh'], 0) assert_raises_message( JSONRPCException, "The provided address is a bare receiver from a Unified Address in this wallet.", node.z_listreceivedbyaddress, receivers['sapling'], 0) # Wallet contains no notes r = node.z_listreceivedbyaddress(unified_addr, 0) assert_equal(len(r), 0, "unified_addr should have received zero notes") # Create a note in this UA on node1 opid = node.z_sendmany(zaddr1, [{ 'address': unified_addr, 'amount': 0.1 }]) txid_sapling = wait_and_assert_operationid_status(node, opid) self.generate_and_sync(height + 5) # Create a UTXO that unified_address's transparent component references, on node1 outputs = {receivers['p2pkh']: 0.2} txid_taddr = node.sendmany("", outputs) r = node.z_listreceivedbyaddress(unified_addr, 0) assert_equal(len(r), 2, "unified_addr should have received 2 payments") # The return list order isn't defined, so sort by pool name r = sorted(r, key=lambda x: x['pool']) assert_equal(r[0]['pool'], 'sapling') assert_equal(r[0]['txid'], txid_sapling) assert_equal(r[0]['amount'], Decimal('0.1')) assert_equal(r[0]['amountZat'], 10000000) assert_equal(r[0]['memo'], no_memo) assert 0 <= r[0]['outindex'] < 2 assert_equal(r[0]['confirmations'], 1) assert_equal(r[0]['change'], False) assert_equal(r[0]['blockheight'], height + 5) assert_equal(r[0]['blockindex'], 1) assert 'blocktime' in r[0] assert_equal(r[1]['pool'], 'transparent') assert_equal(r[1]['txid'], txid_taddr) assert_equal(r[1]['amount'], Decimal('0.2')) assert_equal(r[1]['amountZat'], 20000000) assert 0 <= r[1]['outindex'] < 2 assert_equal(r[1]['confirmations'], 0) assert_equal(r[1]['change'], False) assert 'memo' not in r[1] assert_equal(r[1]['blockheight'], 0) # not yet mined assert_equal(r[1]['blockindex'], -1) # not yet mined assert 'blocktime' in r[1]
myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)") # Send will fail because send amount is too big, even when including coinbase utxos errorString = "" try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999) except JSONRPCException,e: errorString = e.error['message'] assert_equal("Insufficient funds" in errorString, True) # z_sendmany will fail because of insufficient funds recipients = [] recipients.append({"address":self.nodes[1].getnewaddress(), "amount":Decimal('10000.0')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001") myopid = self.nodes[0].z_sendmany(myzaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient shielded funds, have 9.9998, need 10000.0001") # Send will fail because of insufficient funds unless sender uses coinbase utxos try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21) except JSONRPCException,e: errorString = e.error['message'] assert_equal("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr" in errorString, True) # Verify that mempools accept tx with joinsplits which have at least the default z_sendmany fee. # If this test passes, it confirms that issue #1851 has been resolved, where sending from # a zaddr to 1385 taddr recipients fails because the default fee was considered too low # given the tx size, resulting in mempool rejection. errorString = ''
def test_received_orchard(self, height): self.generate_and_sync(height + 1) taddr = self.nodes[1].getnewaddress() acct1 = self.nodes[1].z_getnewaccount()['account'] acct2 = self.nodes[1].z_getnewaccount()['account'] addrResO = self.nodes[1].z_getaddressforaccount(acct1, ['orchard']) assert_equal(addrResO['receiver_types'], ['orchard']) uao = addrResO['address'] addrResSO = self.nodes[1].z_getaddressforaccount( acct2, ['sapling', 'orchard']) assert_equal(addrResSO['receiver_types'], ['sapling', 'orchard']) uaso = addrResSO['address'] self.nodes[0].sendtoaddress(taddr, 4.0) self.generate_and_sync(height + 2) acct_node0 = self.nodes[0].z_getnewaccount()['account'] ua_node0 = self.nodes[0].z_getaddressforaccount( acct_node0, ['sapling', 'orchard'])['address'] opid = self.nodes[1].z_sendmany(taddr, [ { 'address': uao, 'amount': 1, 'memo': my_memo }, { 'address': uaso, 'amount': 2 }, ], 1, 0, 'AllowRevealedSenders') txid0 = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() # Decrypted transaction details should be correct, even though # the transaction is still just in the mempool pt = self.nodes[1].z_viewtransaction(txid0) assert_equal(pt['txid'], txid0) assert_equal(len(pt['spends']), 0) assert_equal(len(pt['outputs']), 2) # Outputs are not returned in a defined order but the amounts are deterministic outputs = sorted(pt['outputs'], key=lambda x: x['valueZat']) assert_equal(outputs[0]['type'], 'orchard') assert_equal(outputs[0]['address'], uao) assert_equal(outputs[0]['value'], Decimal('1')) assert_equal(outputs[0]['valueZat'], 100000000) assert_equal(outputs[0]['outgoing'], False) assert_equal(outputs[0]['memo'], my_memo) assert_equal(outputs[0]['memoStr'], my_memo_str) actionToSpend = outputs[0]['action'] assert_equal(outputs[1]['type'], 'orchard') assert_equal(outputs[1]['address'], uaso) assert_equal(outputs[1]['value'], Decimal('2')) assert_equal(outputs[1]['valueZat'], 200000000) assert_equal(outputs[1]['outgoing'], False) assert_equal(outputs[1]['memo'], no_memo) assert 'memoStr' not in outputs[1] self.generate_and_sync(height + 3) opid = self.nodes[1].z_sendmany(uao, [{ 'address': uaso, 'amount': Decimal('0.3') }, { 'address': ua_node0, 'amount': Decimal('0.2') }]) txid1 = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() pt = self.nodes[1].z_viewtransaction(txid1) assert_equal(pt['txid'], txid1) assert_equal(len(pt['spends']), 1) # one spend we can see assert_equal(len(pt['outputs']), 3) # one output + one change output we can see spends = pt['spends'] assert_equal(spends[0]['type'], 'orchard') assert_equal(spends[0]['txidPrev'], txid0) assert_equal(spends[0]['actionPrev'], actionToSpend) assert_equal(spends[0]['address'], uao) assert_equal(spends[0]['value'], Decimal('1.0')) assert_equal(spends[0]['valueZat'], 100000000) outputs = sorted(pt['outputs'], key=lambda x: x['valueZat']) assert_equal(outputs[0]['type'], 'orchard') assert_equal(outputs[0]['address'], ua_node0) assert_equal(outputs[0]['value'], Decimal('0.2')) assert_equal(outputs[0]['valueZat'], 20000000) assert_equal(outputs[0]['outgoing'], True) assert_equal(outputs[0]['walletInternal'], False) assert_equal(outputs[0]['memo'], no_memo) assert_equal(outputs[1]['type'], 'orchard') assert_equal(outputs[1]['address'], uaso) assert_equal(outputs[1]['value'], Decimal('0.3')) assert_equal(outputs[1]['valueZat'], 30000000) assert_equal(outputs[1]['outgoing'], False) assert_equal(outputs[1]['walletInternal'], False) assert_equal(outputs[1]['memo'], no_memo) # Verify that we observe the change output assert_equal(outputs[2]['type'], 'orchard') assert_equal(outputs[2]['value'], Decimal('0.49999')) assert_equal(outputs[2]['valueZat'], 49999000) assert_equal(outputs[2]['outgoing'], False) assert_equal(outputs[2]['walletInternal'], True) assert_equal(outputs[2]['memo'], no_memo) # The change address should have been erased assert_true('address' not in outputs[2])
def run_test(self): self.nodes[0].generate(1) self.sync_all() taddr = self.nodes[1].getnewaddress() zaddr1 = self.nodes[1].z_getnewaddress('sprout') zaddr2 = self.nodes[1].z_getnewaddress('sprout') self.nodes[0].sendtoaddress(taddr, Decimal('1.0')) self.generate_and_sync() # Send 1 ZEC to a zaddr wait_and_assert_operationid_status( self.nodes[1], self.nodes[1].z_sendmany(taddr, [{ 'address': zaddr1, 'amount': 1.0, 'memo': 'c0ffee01' }], 1, 0)) self.generate_and_sync() # Check that we have received 1 note which is not change receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) listunspent = self.nodes[1].z_listunspent() assert_equal(1, len(receivedbyaddress), "Should have received 1 note") assert_false(receivedbyaddress[0]['change'], "Note should not be change") assert_equal(1, len(listunspent), "Should have 1 unspent note") assert_false(listunspent[0]['change'], "Unspent note should not be change") # Generate some change wait_and_assert_operationid_status( self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{ 'address': zaddr2, 'amount': 0.6, 'memo': 'c0ffee02' }], 1, 0)) self.generate_and_sync() # Check zaddr1 received sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress( zaddr1, 0), key=lambda received: received['amount']) assert_equal(2, len(sortedreceived1), "zaddr1 Should have received 2 notes") assert_equal(Decimal('0.4'), sortedreceived1[0]['amount']) assert_true(sortedreceived1[0]['change'], "Note valued at 0.4 should be change") assert_equal(Decimal('1.0'), sortedreceived1[1]['amount']) assert_false(sortedreceived1[1]['change'], "Note valued at 1.0 should not be change") # Check zaddr2 received sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress( zaddr2, 0), key=lambda received: received['amount']) assert_equal(1, len(sortedreceived2), "zaddr2 Should have received 1 notes") assert_equal(Decimal('0.6'), sortedreceived2[0]['amount']) assert_false(sortedreceived2[0]['change'], "Note valued at 0.6 should not be change") # Check unspent sortedunspent = sorted(self.nodes[1].z_listunspent(), key=lambda received: received['amount']) assert_equal(2, len(sortedunspent), "Should have 2 unspent notes") assert_equal(Decimal('0.4'), sortedunspent[0]['amount']) assert_true(sortedunspent[0]['change'], "Unspent note valued at 0.4 should be change") assert_equal(Decimal('0.6'), sortedunspent[1]['amount']) assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change") # Give node 0 a viewing key viewing_key = self.nodes[1].z_exportviewingkey(zaddr1) self.nodes[0].z_importviewingkey(viewing_key) received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0) assert_equal(2, len(received_node0)) unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True) assert_equal(2, len(unspent_node0)) # node 0 only has a viewing key so does not see the change field assert_false('change' in received_node0[0]) assert_false('change' in received_node0[1]) assert_false('change' in unspent_node0[0]) assert_false('change' in unspent_node0[1])
def test_received_sprout(self, height): self.generate_and_sync(height + 2) zaddr1 = self.nodes[1].z_getnewaddress('sprout') # Send 10 ZEC each zaddr1 and zaddrExt via z_shieldcoinbase result = self.nodes[0].z_shieldcoinbase( get_coinbase_address(self.nodes[0]), zaddr1, 0, 1) txid_shielding1 = wait_and_assert_operationid_status( self.nodes[0], result['opid']) zaddrExt = self.nodes[2].z_getnewaddress('sprout') result = self.nodes[0].z_shieldcoinbase( get_coinbase_address(self.nodes[0]), zaddrExt, 0, 1) txid_shieldingExt = wait_and_assert_operationid_status( self.nodes[0], result['opid']) self.sync_all() # Decrypted transaction details should not be visible on node 0 pt = self.nodes[0].z_viewtransaction(txid_shielding1) assert_equal(pt['txid'], txid_shielding1) assert_equal(len(pt['spends']), 0) assert_equal(len(pt['outputs']), 0) # Decrypted transaction details should be correct on node 1 pt = self.nodes[1].z_viewtransaction(txid_shielding1) assert_equal(pt['txid'], txid_shielding1) assert_equal(len(pt['spends']), 0) assert_equal(len(pt['outputs']), 1) assert_equal(pt['outputs'][0]['type'], 'sprout') assert_equal(pt['outputs'][0]['js'], 0) assert_equal(pt['outputs'][0]['address'], zaddr1) assert_equal(pt['outputs'][0]['value'], Decimal('10')) assert_equal(pt['outputs'][0]['valueZat'], 1000000000) assert_equal(pt['outputs'][0]['memo'], no_memo) jsOutputPrev = pt['outputs'][0]['jsOutput'] # Second transaction should not be known to node 1 assert_raises_message(JSONRPCException, "Invalid or non-wallet transaction id", self.nodes[1].z_viewtransaction, txid_shieldingExt) # Second transaction should be visible on node0 pt = self.nodes[2].z_viewtransaction(txid_shieldingExt) assert_equal(pt['txid'], txid_shieldingExt) assert_equal(len(pt['spends']), 0) assert_equal(len(pt['outputs']), 1) assert_equal(pt['outputs'][0]['type'], 'sprout') assert_equal(pt['outputs'][0]['js'], 0) assert_equal(pt['outputs'][0]['address'], zaddrExt) assert_equal(pt['outputs'][0]['value'], Decimal('10')) assert_equal(pt['outputs'][0]['valueZat'], 1000000000) assert_equal(pt['outputs'][0]['memo'], no_memo) r = self.nodes[1].z_listreceivedbyaddress(zaddr1) assert_equal(0, len(r), "Should have received no confirmed note") c = self.nodes[1].z_getnotescount() assert_equal(0, c['sprout'], "Count of confirmed notes should be 0") # No confirmation required, one note should be present r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) assert_equal(1, len(r), "Should have received one (unconfirmed) note") assert_equal(txid_shielding1, r[0]['txid']) assert_equal(10, r[0]['amount']) assert_equal(1000000000, r[0]['amountZat']) assert_false(r[0]['change'], "Note should not be change") assert_equal(no_memo, r[0]['memo']) assert_equal(0, r[0]['confirmations']) assert_equal(-1, r[0]['blockindex']) assert_equal(0, r[0]['blockheight']) c = self.nodes[1].z_getnotescount(0) assert_equal(1, c['sprout'], "Count of unconfirmed notes should be 1") # Confirm transaction (10 ZEC shielded) self.generate_and_sync(height + 3) # Require one confirmation, note should be present r0 = self.nodes[1].z_listreceivedbyaddress(zaddr1) assert_equal(1, len(r0), "Should have received one (unconfirmed) note") assert_equal(txid_shielding1, r0[0]['txid']) assert_equal(10, r0[0]['amount']) assert_equal(1000000000, r0[0]['amountZat']) assert_false(r0[0]['change'], "Note should not be change") assert_equal(no_memo, r0[0]['memo']) assert_equal(1, r0[0]['confirmations']) assert_equal(height + 3, r0[0]['blockheight']) taddr = self.nodes[1].getnewaddress() # Generate some change by sending part of zaddr1 back to taddr opid = self.nodes[1].z_sendmany(zaddr1, [{ 'address': taddr, 'amount': 0.6 }]) txid = wait_and_assert_operationid_status(self.nodes[1], opid) self.generate_and_sync(height + 4) # Decrypted transaction details should be correct pt = self.nodes[1].z_viewtransaction(txid) assert_equal(pt['txid'], txid) assert_equal(len(pt['spends']), 1) # TODO: enable once z_viewtransaction displays transparent elements # assert_equal(len(pt['outputs']), 2) assert_equal(len(pt['outputs']), 1) assert_equal(pt['spends'][0]['type'], 'sprout') assert_equal(pt['spends'][0]['txidPrev'], txid_shielding1) assert_equal(pt['spends'][0]['js'], 0) assert_equal(pt['spends'][0]['jsPrev'], 0) assert_equal(pt['spends'][0]['jsOutputPrev'], jsOutputPrev) assert_equal(pt['spends'][0]['address'], zaddr1) assert_equal(pt['spends'][0]['value'], Decimal('10.0')) assert_equal(pt['spends'][0]['valueZat'], 1000000000) # We expect a transparent output and a Sprout output, but the RPC does # not define any particular ordering of these within the returned JSON. outputs = [{ 'type': output['type'], 'address': output['address'], 'value': output['value'], 'valueZat': output['valueZat'], } for output in pt['outputs']] for (i, output) in enumerate(pt['outputs']): if 'memo' in output: outputs[i]['memo'] = output['memo'] # TODO: enable once z_viewtransaction displays transparent elements # assert({ # 'type': 'transparent', # 'address': taddr, # 'value': Decimal('0.6'), # 'valueZat': 60000000, # } in outputs) assert ({ 'type': 'sprout', 'address': zaddr1, 'value': Decimal('9.4') - DEFAULT_FEE, 'valueZat': 940000000 - DEFAULT_FEE_ZATS, 'memo': no_memo, } in outputs) # zaddr1 should have a note with change r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) assert_equal(2, len(r), "zaddr1 Should have received 2 notes") r = sorted(r, key=lambda received: received['amount']) assert_equal(txid, r[0]['txid']) assert_equal(Decimal('9.4') - DEFAULT_FEE, r[0]['amount']) assert_equal(940000000 - DEFAULT_FEE_ZATS, r[0]['amountZat']) assert_true( r[0]['change'], "Note valued at (9.4-" + str(DEFAULT_FEE) + ") should be change") assert_equal(no_memo, r[0]['memo']) # The old note still exists (it's immutable), even though it is spent assert_equal(Decimal('10.0'), r[1]['amount']) assert_equal(1000000000, r[1]['amountZat']) assert_false(r[1]['change'], "Note valued at 10.0 should not be change") assert_equal(no_memo, r[1]['memo'])
class WalletShieldingCoinbaseTest(BitcoinTestFramework): def setup_chain(self): print("Initializing test directory " + self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, 4) # Start nodes with -regtestshieldcoinbase to set fCoinbaseMustBeShielded to true. def setup_network(self, split=False): self.nodes = start_nodes( 4, self.options.tmpdir, extra_args=[['-regtestshieldcoinbase', '-debug=zrpcunsafe']] * 4) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) connect_nodes_bi(self.nodes, 0, 3) self.is_network_split = False self.sync_all() def run_test(self): print "Mining blocks..." self.nodes[0].generate(4) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[3].getbalance(), 0) check_value_pool(self.nodes[0], 'sprout', 0) check_value_pool(self.nodes[1], 'sprout', 0) check_value_pool(self.nodes[2], 'sprout', 0) check_value_pool(self.nodes[3], 'sprout', 0) # Send will fail because we are enforcing the consensus rule that # coinbase utxos can only be sent to a zaddr. errorString = "" try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1) except JSONRPCException, e: errorString = e.error['message'] assert_equal( "Coinbase funds can only be sent to a zaddr" in errorString, True) # Prepare to send taddr->zaddr mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Node 3 will test that watch only address utxos are not selected self.nodes[3].importaddress(mytaddr) recipients = [{"address": myzaddr, "amount": Decimal('1')}] myopid = self.nodes[3].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status( self.nodes[3], myopid, "failed", "Insufficient funds, no UTXOs found for taddr from address.", 10) # This send will fail because our wallet does not allow any change when shielding a coinbase utxo, # as it's currently not possible to specify a change address in z_sendmany. recipients = [] recipients.append({ "address": myzaddr, "amount": Decimal('1.23456789') }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) error_result = wait_and_assert_operationid_status_result( self.nodes[0], myopid, "failed", ("Change 8.76533211 not allowed. " "When shielding coinbase funds, the wallet does not allow any change " "as there is currently no way to specify a change address in z_sendmany." ), 10) # Test that the returned status object contains a params field with the operation's input parameters assert_equal(error_result["method"], "z_sendmany") params = error_result["params"] assert_equal(params["fee"], Decimal('0.0001')) # default assert_equal(params["minconf"], Decimal('1')) # default assert_equal(params["fromaddress"], mytaddr) assert_equal(params["amounts"][0]["address"], myzaddr) assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789')) # Add viewing key for myzaddr to Node 3 myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr) self.nodes[3].z_importviewingkey(myviewingkey, "no") # This send will succeed. We send two coinbase utxos totalling 20.0 less a fee of 0.00010000, with no change. shieldvalue = Decimal('20.0') - Decimal('0.0001') recipients = [] recipients.append({"address": myzaddr, "amount": shieldvalue}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # Verify that z_listunspent can return a note that has zero confirmations results = self.nodes[0].z_listunspent() assert (len(results) == 0) results = self.nodes[0].z_listunspent(0) # set minconf to zero assert (len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 0) # Mine the tx self.nodes[1].generate(1) self.sync_all() # Verify that z_listunspent returns one note which has been confirmed results = self.nodes[0].z_listunspent() assert (len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 1) assert_equal(results[0]["spendable"], True) # Verify that z_listunspent returns note for watchonly address on node 3. results = self.nodes[3].z_listunspent(1, 999, True) assert (len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 1) assert_equal(results[0]["spendable"], False) # Verify that z_listunspent returns error when address spending key from node 0 is not available in wallet of node 1. try: results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr]) except JSONRPCException as e: errorString = e.error['message'] assert_equal( "Invalid parameter, spending key for address does not belong to wallet" in errorString, True) # Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid logpath = self.options.tmpdir + "/node0/regtest/debug.log" logcounter = 0 with open(logpath, "r") as myfile: logdata = myfile.readlines() for logline in logdata: if myopid + ": z_sendmany initialized" in logline and mytaddr in logline and myzaddr in logline: assert_equal(logcounter, 0) # verify order of log messages logcounter = logcounter + 1 if myopid + ": z_sendmany finished" in logline and mytxid in logline: assert_equal(logcounter, 1) logcounter = logcounter + 1 assert_equal(logcounter, 2) # check balances (the z_sendmany consumes 3 coinbase utxos) resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('20.0')) assert_equal(Decimal(resp["private"]), Decimal('19.9999')) assert_equal(Decimal(resp["total"]), Decimal('39.9999')) # The Sprout value pool should reflect the send sproutvalue = shieldvalue check_value_pool(self.nodes[0], 'sprout', sproutvalue) # A custom fee of 0 is okay. Here the node will send the note value back to itself. recipients = [] recipients.append({"address": myzaddr, "amount": Decimal('19.9999')}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('0.0')) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('20.0')) assert_equal(Decimal(resp["private"]), Decimal('19.9999')) assert_equal(Decimal(resp["total"]), Decimal('39.9999')) # The Sprout value pool should be unchanged check_value_pool(self.nodes[0], 'sprout', sproutvalue) # convert note to transparent funds unshieldvalue = Decimal('10.0') recipients = [] recipients.append({"address": mytaddr, "amount": unshieldvalue}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) assert (mytxid is not None) self.sync_all() # check that priority of the tx sending from a zaddr is not 0 mempool = self.nodes[0].getrawmempool(True) assert (Decimal(mempool[mytxid]['startingpriority']) >= Decimal('1000000000000')) self.nodes[1].generate(1) self.sync_all() # check balances sproutvalue -= unshieldvalue + Decimal('0.0001') resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('30.0')) assert_equal(Decimal(resp["private"]), Decimal('9.9998')) assert_equal(Decimal(resp["total"]), Decimal('39.9998')) check_value_pool(self.nodes[0], 'sprout', sproutvalue) # z_sendmany will return an error if there is transparent change output considered dust. # UTXO selection in z_sendmany sorts in ascending order, so smallest utxos are consumed first. # At this point in time, unspent notes all have a value of 10.0 and standard z_sendmany fee is 0.0001. recipients = [] amount = Decimal('10.0') - Decimal('0.00010000') - Decimal( '0.00000001' ) # this leaves change at 1 zatoshi less than dust threshold recipients.append({ "address": self.nodes[0].getnewaddress(), "amount": amount }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status( self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)" ) # Send will fail because send amount is too big, even when including coinbase utxos errorString = "" try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999) except JSONRPCException, e: errorString = e.error['message']
def send_to_sprout_zaddr(self, tAddr, sproutAddr): # Send some ZEC to a Sprout address opid = self.nodes[0].z_sendmany(tAddr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0) wait_and_assert_operationid_status(self.nodes[0], opid) self.nodes[0].generate(1) self.sync_all()
def run_test(self): print "Mining blocks..." self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], self._reward * 4) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(102) self.sync_all() assert_equal(self.nodes[0].getbalance(), self._reward * 4) assert_equal(self.nodes[1].getbalance(), self._reward * 2) assert_equal(self.nodes[2].getbalance(), 0) # At this point in time, commitment tree is the empty root # Node 0 creates a joinsplit transaction mytaddr0 = self.nodes[0].getnewaddress() myzaddr0 = self.nodes[0].z_getnewaddress('sprout') recipients = [] recipients.append({ "address": myzaddr0, "amount": self._reward - self._fee }) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) # Sync up mempools and mine the transaction. All nodes have the same anchor. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Stop nodes. stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and partition network into two: # A: node 0 # B: node 1, 2 self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-debug=zrpc']] * 3) connect_nodes_bi(self.nodes, 1, 2) # Partition B, node 1 mines an empty block self.nodes[1].generate(1) # Partition A, node 0 creates a joinsplit transaction recipients = [] recipients.append({ "address": myzaddr0, "amount": self._reward - self._fee }) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) rawhex = self.nodes[0].getrawtransaction(txid) # Partition A, node 0 mines a block with the transaction self.nodes[0].generate(1) # Partition B, node 1 mines the same joinsplit transaction txid2 = self.nodes[1].sendrawtransaction(rawhex) assert_equal(txid, txid2) self.nodes[1].generate(1) # Check that Partition B is one block ahead and that they have different tips assert_equal(self.nodes[0].getblockcount() + 1, self.nodes[1].getblockcount()) assert (self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()) # Shut down all nodes so any in-memory state is saved to disk stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and reconnect the entire network self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-debug=zrpc']] * 3) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) # Mine a new block and let it propagate self.nodes[1].generate(1) # Due to a bug in v1.0.0-1.0.3, node 0 will die with a tree root assertion, so sync_all() will throw an exception. self.sync_all() # v1.0.4 will reach here safely assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash())
def run_test(self): print "Mining blocks..." self.nodes[0].generate(100) self.sync_all() self.nodes[1].generate(101) self.sync_all() mytaddr = self.nodes[0].getnewaddress() # where coins were mined myzaddr = self.nodes[0].z_getnewaddress() # Spend coinbase utxos to create three notes of 9.99990000 each recipients = [] recipients.append({ "address": myzaddr, "amount": Decimal(self._coin) - Decimal('0.0001') }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Check balance resp = self.nodes[0].z_getbalance(myzaddr) assert_equal(Decimal(resp), (Decimal(self._coin) - Decimal('0.0001')) * 3) # 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 = [] recipients.append({ "address": self.nodes[2].z_getnewaddress(), "amount": Decimal(self._coin) - Decimal('0.0001') }) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) # 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 = [] recipients.append({ "address": self.nodes[2].z_getnewaddress(), "amount": Decimal('18') }) recipients.append({ "address": self.nodes[2].z_getnewaddress(), "amount": (Decimal(self._coin) - Decimal('0.0001')) * 3 - Decimal('18') - Decimal('0.0001') }) myopid = self.nodes[0].z_sendmany(myzaddr, recipients) # Wait for Tx 2 to begin executing... for x in xrange(1, 60): results = self.nodes[0].z_getoperationstatus([myopid]) status = results[0]["status"] if status == "executing": break time.sleep(1) # 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 wait_and_assert_operationid_status(self.nodes[0], myopid) # 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'))
def run_test_release(self, release, height): self.generate_and_sync(height+1) taddr = self.nodes[1].getnewaddress() zaddr1 = self.nodes[1].z_getnewaddress(release) self.nodes[0].sendtoaddress(taddr, 2.0) self.generate_and_sync(height+2) # Send 1 ZEC to zaddr1 opid = self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1, 'memo': my_memo}]) txid = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() r = self.nodes[1].z_listreceivedbyaddress(zaddr1) assert_equal(0, len(r), "Should have received no confirmed note") # No confirmation required, one note should be present r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) assert_equal(1, len(r), "Should have received one (unconfirmed) note") assert_equal(txid, r[0]['txid']) assert_equal(1, r[0]['amount']) assert_false(r[0]['change'], "Note should not be change") assert_equal(my_memo, r[0]['memo']) # Confirm transaction (1 ZEC from taddr to zaddr1) self.generate_and_sync(height+3) # Require one confirmation, note should be present assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1)) # Generate some change by sending part of zaddr1 to zaddr2 zaddr2 = self.nodes[1].z_getnewaddress(release) opid = self.nodes[1].z_sendmany(zaddr1, [{'address': zaddr2, 'amount': 0.6}]) txid = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() self.generate_and_sync(height+4) # zaddr1 should have a note with change r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) r = sorted(r, key = lambda received: received['amount']) assert_equal(2, len(r), "zaddr1 Should have received 2 notes") assert_equal(txid, r[0]['txid']) assert_equal(Decimal('0.4')-fee, r[0]['amount']) assert_true(r[0]['change'], "Note valued at (0.4-fee) should be change") assert_equal(no_memo, r[0]['memo']) # The old note still exists (it's immutable), even though it is spent assert_equal(Decimal('1.0'), r[1]['amount']) assert_false(r[1]['change'], "Note valued at 1.0 should not be change") assert_equal(my_memo, r[1]['memo']) # zaddr2 should not have change r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0) r = sorted(r, key = lambda received: received['amount']) assert_equal(1, len(r), "zaddr2 Should have received 1 notes") assert_equal(txid, r[0]['txid']) assert_equal(Decimal('0.6'), r[0]['amount']) assert_false(r[0]['change'], "Note valued at 0.6 should not be change") assert_equal(no_memo, r[0]['memo'])
def run_test(self): # Current height = 200 -> Sprout assert_equal(200, self.nodes[0].getblockcount()) sproutzaddr = self.nodes[0].z_getnewaddress('sprout') # test that we can create a sapling zaddr before sapling activates saplingzaddr = self.nodes[0].z_getnewaddress('sapling') # we've got lots of coinbase (taddr) but no shielded funds yet assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) # Set current height to 201 -> Sprout self.nodes[0].generate(1) self.sync_all() assert_equal(201, self.nodes[0].getblockcount()) # Shield coinbase funds (must be a multiple of 10, no change allowed pre-sapling) receive_amount_10 = Decimal('10.0') - Decimal('0.0001') recipients = [{"address":sproutzaddr, "amount":receive_amount_10}] myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients) txid_1 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # No funds (with (default) one or more confirmations) in sproutzaddr yet assert_equal(0, len(self.nodes[0].z_listunspent())) assert_equal(0, len(self.nodes[0].z_listunspent(1))) # no private balance because no confirmations yet assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) # list private unspent, this time allowing 0 confirmations unspent_cb = self.nodes[0].z_listunspent(0) assert_equal(1, len(unspent_cb)) assert_equal(False, unspent_cb[0]['change']) assert_equal(txid_1, unspent_cb[0]['txid']) assert_equal(True, unspent_cb[0]['spendable']) assert_equal(sproutzaddr, unspent_cb[0]['address']) assert_equal(receive_amount_10, unspent_cb[0]['amount']) # list unspent, filtering by address, should produce same result unspent_cb_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) assert_equal(unspent_cb, unspent_cb_filter) # Generate a block to confirm shield coinbase tx self.nodes[0].generate(1) self.sync_all() # Current height = 202 -> Overwinter. Default address type remains Sprout assert_equal(202, self.nodes[0].getblockcount()) # Send 1.0 (actually 0.9999) from sproutzaddr to a new zaddr sproutzaddr2 = self.nodes[0].z_getnewaddress('sprout') receive_amount_1 = Decimal('1.0') - Decimal('0.0001') change_amount_9 = receive_amount_10 - Decimal('1.0') assert_equal('sprout', self.nodes[0].z_validateaddress(sproutzaddr2)['type']) recipients = [{"address": sproutzaddr2, "amount":receive_amount_1}] myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients) txid_2 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # list unspent, allowing 0conf txs unspent_tx = self.nodes[0].z_listunspent(0) assert_equal(len(unspent_tx), 2) # sort low-to-high by amount (order of returned entries is not guaranteed) unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) assert_equal(False, unspent_tx[0]['change']) assert_equal(txid_2, unspent_tx[0]['txid']) assert_equal(True, unspent_tx[0]['spendable']) assert_equal(sproutzaddr2, unspent_tx[0]['address']) assert_equal(receive_amount_1, unspent_tx[0]['amount']) assert_equal(True, unspent_tx[1]['change']) assert_equal(txid_2, unspent_tx[1]['txid']) assert_equal(True, unspent_tx[1]['spendable']) assert_equal(sproutzaddr, unspent_tx[1]['address']) assert_equal(change_amount_9, unspent_tx[1]['amount']) unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr2]) assert_equal(1, len(unspent_tx_filter)) assert_equal(unspent_tx[0], unspent_tx_filter[0]) unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) assert_equal(1, len(unspent_tx_filter)) assert_equal(unspent_tx[1], unspent_tx_filter[0]) # Set current height to 204 -> Sapling self.nodes[0].generate(12) self.sync_all() assert_equal(214, self.nodes[0].getblockcount()) # No funds in saplingzaddr yet assert_equal(0, len(self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr]))) # Send 0.9999 to our sapling zaddr # (sending from a sprout zaddr to a sapling zaddr is disallowed, # so send from coin base) receive_amount_2 = Decimal('2.0') - Decimal('0.0001') recipients = [{"address": saplingzaddr, "amount":receive_amount_2}] myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients) txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() unspent_tx = self.nodes[0].z_listunspent(0) assert_equal(3, len(unspent_tx)) # low-to-high in amount unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) assert_equal(False, unspent_tx[0]['change']) assert_equal(txid_2, unspent_tx[0]['txid']) assert_equal(True, unspent_tx[0]['spendable']) assert_equal(sproutzaddr2, unspent_tx[0]['address']) assert_equal(receive_amount_1, unspent_tx[0]['amount']) assert_equal(False, unspent_tx[1]['change']) assert_equal(txid_3, unspent_tx[1]['txid']) assert_equal(True, unspent_tx[1]['spendable']) assert_equal(saplingzaddr, unspent_tx[1]['address']) assert_equal(receive_amount_2, unspent_tx[1]['amount']) assert_equal(True, unspent_tx[2]['change']) assert_equal(txid_2, unspent_tx[2]['txid']) assert_equal(True, unspent_tx[2]['spendable']) assert_equal(sproutzaddr, unspent_tx[2]['address']) assert_equal(change_amount_9, unspent_tx[2]['amount']) unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr]) assert_equal(1, len(unspent_tx_filter)) assert_equal(unspent_tx[1], unspent_tx_filter[0]) # test that pre- and post-sapling can be filtered in a single call unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr, saplingzaddr]) assert_equal(2, len(unspent_tx_filter)) unspent_tx_filter = sorted(unspent_tx_filter, key=lambda k: k['amount']) assert_equal(unspent_tx[1], unspent_tx_filter[0]) assert_equal(unspent_tx[2], unspent_tx_filter[1]) # so far, this node has no watchonly addresses, so results are the same unspent_tx_watchonly = self.nodes[0].z_listunspent(0, 9999, True) unspent_tx_watchonly = sorted(unspent_tx_watchonly, key=lambda k: k['amount']) assert_equal(unspent_tx, unspent_tx_watchonly)
def run_test(self): # Sanity-check the test harness self.nodes[0].generate(200) assert_equal(self.nodes[0].getblockcount(), 200) self.sync_all() # Verify Sapling address is persisted in wallet (even when Sapling is not yet active) sapling_addr = self.nodes[0].z_getnewaddress('sapling') # Make sure the node has the addresss addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address before restart") # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Make sure we still have the address after restarting addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address after restart") # Activate Sapling self.nodes[0].generate(1) self.sync_all() # Node 0 shields funds to Sapling address taddr0 = self.nodes[0].getnewaddress() recipients = [] recipients.append({"address": sapling_addr, "amount": Decimal('20')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify shielded balance assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20')) # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Node 0 sends some shielded funds to Node 1 dest_addr = self.nodes[1].z_getnewaddress('sapling') recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('15')}) myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Verify importing a spending key will update and persist the nullifiers and witnesses correctly sk0 = self.nodes[0].z_exportkey(sapling_addr) self.nodes[2].z_importkey(sk0, "yes") assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify nullifiers persisted correctly by checking balance # Prior to PR #3590, there will be an error as spent notes are considered unspent: # Assertion failed: expected: <25.00000000> but was: <5> assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) # Verity witnesses persisted correctly by sending shielded funds recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('1')}) myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[2], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
try: self.nodes[0].createrawtransaction([], {}, 0, 200) except JSONRPCException,e: errorString = e.error['message'] assert_equal("Invalid parameter, expiryheight should be at least 203 to avoid transaction expiring soon" in errorString, True) # Node 0 sends transparent funds to Node 3 tsendamount = Decimal('1.0') txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount) self.sync_all() # Node 3 sends the zero-confirmation transparent funds to Node 1 using z_sendmany recipients = [] recipients.append({"address":taddr1, "amount": Decimal('0.5')}) myopid = self.nodes[3].z_sendmany(taddr3, recipients, 0) txid_zsendmany = wait_and_assert_operationid_status(self.nodes[3], myopid) # Node 0 shields to Node 3, a coinbase utxo of value 10.0 less fee 0.00010000 zsendamount = Decimal('10.0') - Decimal('0.0001') recipients = [] recipients.append({"address":zaddr3, "amount": zsendamount}) myopid = self.nodes[0].z_sendmany(taddr0, recipients) txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) # Mine the first Overwinter block self.sync_all() self.nodes[0].generate(1) self.sync_all() bci = self.nodes[0].getblockchaininfo() # size_on_disk should be > 0
def run_test(self): # Sanity-check the test harness assert_equal(self.nodes[0].getblockcount(), 200) # Activate Overwinter self.nodes[2].generate(1) self.sync_all() # Verify RPCs disallow Sapling value transfer if Sapling is not active tmp_taddr = get_coinbase_address(self.nodes[3]) tmp_zaddr = self.nodes[3].z_getnewaddress('sapling') try: recipients = [] recipients.append({"address": tmp_zaddr, "amount": Decimal('10')}) self.nodes[3].z_sendmany(tmp_taddr, recipients, 1, 0) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) try: recipients = [] recipients.append({"address": tmp_taddr, "amount": Decimal('10')}) self.nodes[3].z_sendmany(tmp_zaddr, recipients, 1, 0) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) try: self.nodes[3].z_shieldcoinbase(tmp_taddr, tmp_zaddr) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) # Verify z_mergetoaddress RPC does not support Sapling yet try: self.nodes[3].z_mergetoaddress([tmp_taddr], tmp_zaddr) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) try: self.nodes[3].z_mergetoaddress([tmp_zaddr], tmp_taddr) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: # When sending from a zaddr we check for sapling activation only if # we find notes belonging to that address. Since sapling is not active # none can be generated and none will be found. assert_equal("Could not find any funds to merge.", e.error['message']) # Activate Sapling self.nodes[2].generate(2) self.sync_all() taddr1 = self.nodes[1].getnewaddress() saplingAddr0 = self.nodes[0].z_getnewaddress('sapling') saplingAddr1 = self.nodes[1].z_getnewaddress('sapling') # Verify addresses assert(saplingAddr0 in self.nodes[0].z_listaddresses()) assert(saplingAddr1 in self.nodes[1].z_listaddresses()) assert_equal(self.nodes[0].z_validateaddress(saplingAddr0)['type'], 'sapling') assert_equal(self.nodes[0].z_validateaddress(saplingAddr1)['type'], 'sapling') # Verify balance assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('0')) assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0')) # Node 0 shields some funds # taddr -> Sapling recipients = [] recipients.append({"address": saplingAddr0, "amount": Decimal('10')}) myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000) mempool = self.nodes[0].getrawmempool(True) assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16')) # Shield another coinbase UTXO myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('20')) assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0')) # Node 0 sends some shielded funds to node 1 # Sapling -> Sapling # -> Sapling (change) recipients = [] recipients.append({"address": saplingAddr1, "amount": Decimal('15')}) myopid = self.nodes[0].z_sendmany(saplingAddr0, recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000) mempool = self.nodes[0].getrawmempool(True) assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16')) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('15')) assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0')) # Node 1 sends some shielded funds to node 0, as well as unshielding # Sapling -> Sapling # -> taddr # -> Sapling (change) recipients = [] recipients.append({"address": saplingAddr0, "amount": Decimal('5')}) recipients.append({"address": taddr1, "amount": Decimal('5')}) myopid = self.nodes[1].z_sendmany(saplingAddr1, recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000) mempool = self.nodes[1].getrawmempool(True) assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16')) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('10')) assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('5')) # Verify existence of Sapling related JSON fields resp = self.nodes[0].getrawtransaction(mytxid, 1) assert_equal(resp['valueBalance'], Decimal('5')) assert(len(resp['vShieldedSpend']) == 1) assert(len(resp['vShieldedOutput']) == 2) assert('bindingSig' in resp) shieldedSpend = resp['vShieldedSpend'][0] assert('cv' in shieldedSpend) assert('anchor' in shieldedSpend) assert('nullifier' in shieldedSpend) assert('rk' in shieldedSpend) assert('proof' in shieldedSpend) assert('spendAuthSig' in shieldedSpend) shieldedOutput = resp['vShieldedOutput'][0] assert('cv' in shieldedOutput) assert('cmu' in shieldedOutput) assert('ephemeralKey' in shieldedOutput) assert('encCiphertext' in shieldedOutput) assert('outCiphertext' in shieldedOutput) assert('proof' in shieldedOutput) # Verify importing a spending key will update the nullifiers and witnesses correctly sk0 = self.nodes[0].z_exportkey(saplingAddr0) self.nodes[2].z_importkey(sk0, "yes") assert_equal(self.nodes[2].z_getbalance(saplingAddr0), Decimal('10')) sk1 = self.nodes[1].z_exportkey(saplingAddr1) self.nodes[2].z_importkey(sk1, "yes") assert_equal(self.nodes[2].z_getbalance(saplingAddr1), Decimal('5')) # Make sure we get a useful error when trying to send to both sprout and sapling node4_sproutaddr = self.nodes[3].z_getnewaddress('sprout') node4_saplingaddr = self.nodes[3].z_getnewaddress('sapling') try: self.nodes[1].z_sendmany( taddr1, [{'address': node4_sproutaddr, 'amount': 2.5}, {'address': node4_saplingaddr, 'amount': 2.4999}], 1, 0.0001 ) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: assert_equal("Cannot send to both Sprout and Sapling addresses using z_sendmany", e.error['message'])
def run_test(self): # Current height = 200 -> Sprout assert_equal(200, self.nodes[0].getblockcount()) # test that we can create a sapling zaddr before sapling activates saplingzaddr = self.nodes[0].z_getnewaddress('sapling') # Set current height to 204 -> Sapling self.nodes[0].generate(2) self.sync_all() assert_equal(204, self.nodes[0].getblockcount()) # No funds in saplingzaddr yet assert_equal( 0, len(self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr]))) # Send 0.9999 to our sapling zaddr # (sending from a sprout zaddr to a sapling zaddr is disallowed, # so send from coin base) receive_amount_2 = Decimal('2.0') - Decimal('0.0001') recipients = [{"address": saplingzaddr, "amount": receive_amount_2}] myopid = self.nodes[0].z_sendmany(mining_addr, recipients) txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() unspent_tx = self.nodes[0].z_listunspent(0) assert_equal(3, len(unspent_tx)) # low-to-high in amount unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) assert_equal(False, unspent_tx[0]['change']) assert_equal(txid_2, unspent_tx[0]['txid']) assert_equal(True, unspent_tx[0]['spendable']) assert_equal(sproutzaddr2, unspent_tx[0]['address']) assert_equal(receive_amount_1, unspent_tx[0]['amount']) assert_equal(False, unspent_tx[1]['change']) assert_equal(txid_3, unspent_tx[1]['txid']) assert_equal(True, unspent_tx[1]['spendable']) assert_equal(saplingzaddr, unspent_tx[1]['address']) assert_equal(receive_amount_2, unspent_tx[1]['amount']) assert_equal(True, unspent_tx[2]['change']) assert_equal(txid_2, unspent_tx[2]['txid']) assert_equal(True, unspent_tx[2]['spendable']) assert_equal(sproutzaddr, unspent_tx[2]['address']) assert_equal(change_amount_9, unspent_tx[2]['amount']) unspent_tx_filter = self.nodes[0].z_listunspent( 0, 9999, False, [saplingzaddr]) assert_equal(1, len(unspent_tx_filter)) assert_equal(unspent_tx[1], unspent_tx_filter[0]) # test that pre- and post-sapling can be filtered in a single call unspent_tx_filter = self.nodes[0].z_listunspent( 0, 9999, False, [sproutzaddr, saplingzaddr]) assert_equal(2, len(unspent_tx_filter)) unspent_tx_filter = sorted(unspent_tx_filter, key=lambda k: k['amount']) assert_equal(unspent_tx[1], unspent_tx_filter[0]) assert_equal(unspent_tx[2], unspent_tx_filter[1]) # so far, this node has no watchonly addresses, so results are the same unspent_tx_watchonly = self.nodes[0].z_listunspent(0, 9999, True) unspent_tx_watchonly = sorted(unspent_tx_watchonly, key=lambda k: k['amount']) assert_equal(unspent_tx, unspent_tx_watchonly)
def run_test (self): print "Mining blocks..." self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(102) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 20) assert_equal(self.nodes[2].getbalance(), 0) # At this point in time, commitment tree is the empty root # Node 0 creates a joinsplit transaction mytaddr0 = get_coinbase_address(self.nodes[0]) myzaddr0 = self.nodes[0].z_getnewaddress('sprout') recipients = [] recipients.append({"address":myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) # Sync up mempools and mine the transaction. All nodes have the same anchor. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Stop nodes. stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and partition network into two: # A: node 0 # B: node 1, 2 self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3 ) connect_nodes_bi(self.nodes,1,2) # Partition B, node 1 mines an empty block self.nodes[1].generate(1) # Partition A, node 0 creates a joinsplit transaction recipients = [] recipients.append({"address":myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) rawhex = self.nodes[0].getrawtransaction(txid) # Partition A, node 0 mines a block with the transaction self.nodes[0].generate(1) # Partition B, node 1 mines the same joinsplit transaction txid2 = self.nodes[1].sendrawtransaction(rawhex) assert_equal(txid, txid2) self.nodes[1].generate(1) # Check that Partition B is one block ahead and that they have different tips assert_equal(self.nodes[0].getblockcount() + 1, self.nodes[1].getblockcount()) assert( self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()) # Shut down all nodes so any in-memory state is saved to disk stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and reconnect the entire network self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3 ) connect_nodes_bi(self.nodes,0, 1) connect_nodes_bi(self.nodes,1, 2) connect_nodes_bi(self.nodes,0, 2) # Mine a new block and let it propagate self.nodes[1].generate(1) # Due to a bug in v1.0.0-1.0.3, node 0 will die with a tree root assertion, so sync_all() will throw an exception. self.sync_all() # v1.0.4 will reach here safely assert_equal( self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) assert_equal( self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash())
def run_test(self): # Sanity-check the test harness self.nodes[0].generate(200) assert_equal(self.nodes[0].getblockcount(), 200) self.sync_all() # Verify Sapling address is persisted in wallet (even when Sapling is not yet active) sapling_addr = self.nodes[0].z_getnewaddress('sapling') # Make sure the node has the addresss addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address before restart") # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Make sure we still have the address after restarting addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address after restart") # Activate Sapling self.nodes[0].generate(1) self.sync_all() # Node 0 shields funds to Sapling address taddr0 = self.nodes[0].getnewaddress() recipients = [] recipients.append({"address": sapling_addr, "amount": Decimal('20')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify shielded balance assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20')) # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Node 0 sends some shielded funds to Node 1 dest_addr = self.nodes[1].z_getnewaddress('sapling') recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('15')}) myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Verify importing a spending key will update and persist the nullifiers and witnesses correctly sk0 = self.nodes[0].z_exportkey(sapling_addr) self.nodes[2].z_importkey(sk0, "yes") assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify nullifiers persisted correctly by checking balance # Prior to PR #3590, there will be an error as spent notes are considered unspent: # Assertion failed: expected: <25.00000000> but was: <5> assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) # Verity witnesses persisted correctly by sending shielded funds recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('1')}) myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[2], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
def run_test(self): # add zaddr to node 0 myzaddr0 = self.nodes[0].z_getnewaddress('sprout') # send node 0 taddr to zaddr to get out of coinbase # Tests using the default cached chain have one address per coinbase output mytaddr = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({ "address": myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001') }) # utxo amount less fee wait_and_assert_operationid_status(self.nodes[0], self.nodes[0].z_sendmany( mytaddr, recipients), timeout=120) self.sync_all() self.nodes[0].generate(1) self.sync_all() # add zaddr to node 2 myzaddr = self.nodes[2].z_getnewaddress('sprout') # import node 2 zaddr into node 1 myzkey = self.nodes[2].z_exportkey(myzaddr) self.nodes[1].z_importkey(myzkey) # encrypt node 1 wallet and wait to terminate self.nodes[1].encryptwallet("test") bitcoind_processes[1].wait() # restart node 1 self.nodes[1] = start_node(1, self.options.tmpdir) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) self.sync_all() # send node 0 zaddr to note 2 zaddr recipients = [] recipients.append({"address": myzaddr, "amount": 7.0}) wait_and_assert_operationid_status(self.nodes[0], self.nodes[0].z_sendmany( myzaddr0, recipients), timeout=120) self.sync_all() self.nodes[0].generate(1) self.sync_all() # check zaddr balance zsendmanynotevalue = Decimal('8750.0') assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue) assert_equal(self.nodes[1].z_getbalance(myzaddr), zsendmanynotevalue) # add zaddr to node 3 myzaddr3 = self.nodes[3].z_getnewaddress('sprout') # send node 2 zaddr to note 3 zaddr recipients = [] recipients.append({"address": myzaddr3, "amount": 2500.0}) wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany( myzaddr, recipients), timeout=120) self.sync_all() self.nodes[2].generate(1) self.sync_all() # check zaddr balance zsendmany2notevalue = Decimal('2500.0') zsendmanyfee = Decimal('0.0001') zaddrremaining = zsendmanynotevalue - zsendmany2notevalue - zsendmanyfee assert_equal(self.nodes[3].z_getbalance(myzaddr3), zsendmany2notevalue) assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining) # Parallel encrypted wallet can't cache nullifiers for received notes, # and therefore can't detect spends. So it sees a balance corresponding # to the sum of both notes it received (one as change). # TODO: Devise a way to avoid this issue (#1528) assert_equal(self.nodes[1].z_getbalance(myzaddr), zsendmanynotevalue + zaddrremaining) # send node 2 zaddr on node 1 to taddr # This requires that node 1 be unlocked, which triggers caching of # uncached nullifiers. self.nodes[1].walletpassphrase("test", 600) mytaddr1 = self.nodes[1].getnewaddress() recipients = [] recipients.append({"address": mytaddr1, "amount": 1250.0}) wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany( myzaddr, recipients), timeout=120) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check zaddr balance # Now that the encrypted wallet has been unlocked, the note nullifiers # have been cached and spent notes can be detected. Thus the two wallets # are in agreement once more. zsendmany3notevalue = Decimal('1250.0') zaddrremaining2 = zaddrremaining - zsendmany3notevalue - zsendmanyfee assert_equal(self.nodes[1].z_getbalance(myzaddr), zaddrremaining2) assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining2) # Test viewing keys node3mined = Decimal('312500.0') assert_equal( { k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items() }, { 'transparent': node3mined, 'private': zsendmany2notevalue, 'total': node3mined + zsendmany2notevalue, }) # add node 1 address and node 2 viewing key to node 3 myzvkey = self.nodes[2].z_exportviewingkey(myzaddr) self.nodes[3].importaddress(mytaddr1) self.nodes[3].z_importviewingkey(myzvkey, 'whenkeyisnew', 1) # Check the address has been imported assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False) assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True) # Node 3 should see the same received notes as node 2; however, # some of the notes were change for node 2 but not for node 3. # Aside from that the recieved notes should be the same. So, # group by txid and then check that all properties aside from # change are equal. node2Received = dict( [r['txid'], r] for r in self.nodes[2].z_listreceivedbyaddress(myzaddr)) node3Received = dict( [r['txid'], r] for r in self.nodes[3].z_listreceivedbyaddress(myzaddr)) assert_equal(len(node2Received), len(node2Received)) for txid in node2Received: received2 = node2Received[txid] received3 = node3Received[txid] # the change field will be omitted for received3, but all other fields should be shared assert_true(len(received2) >= len(received3)) for key in received2: # check all the properties except for change if key != 'change': assert_equal(received2[key], received3[key]) # Node 3's balances should be unchanged without explicitly requesting # to include watch-only balances assert_equal( { k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items() }, { 'transparent': node3mined, 'private': zsendmany2notevalue, 'total': node3mined + zsendmany2notevalue, }) # Wallet can't cache nullifiers for notes received by addresses it only has a # viewing key for, and therefore can't detect spends. So it sees a balance # corresponding to the sum of all notes the address received. # TODO: Fix this during the Sapling upgrade (via #2277) assert_equal( { k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance(1, True).items() }, { 'transparent': node3mined + Decimal('1250.0'), 'private': zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, 'total': node3mined + Decimal('1250.0') + zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, }) # Check individual balances reflect the above assert_equal(self.nodes[3].z_getbalance(mytaddr1), Decimal('1250.0')) assert_equal(self.nodes[3].z_getbalance(myzaddr), zsendmanynotevalue + zaddrremaining + zaddrremaining2)
newzaddr = self.nodes[2].z_getnewaddress('sprout') recipients.append({"address":newzaddr, "amount":amount_per_recipient}) try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException,e: errorString = e.error['message'] assert("Invalid parameter, too many zaddr outputs" in errorString) # add zaddr to node 2 myzaddr = self.nodes[2].z_getnewaddress('sprout') # send node 2 taddr to zaddr recipients = [] recipients.append({"address":myzaddr, "amount":7}) mytxid = wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(mytaddr, recipients)) self.sync_all() self.nodes[2].generate(1) self.sync_all() # check balances zsendmanynotevalue = Decimal('7.0') zsendmanyfee = Decimal('0.0001') node2utxobalance = Decimal('23.998') - zsendmanynotevalue - zsendmanyfee assert_equal(self.nodes[2].getbalance(), node2utxobalance) assert_equal(self.nodes[2].getbalance("*"), node2utxobalance) # check zaddr balance assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue)
def nu_activation_checks(): # Mine block H - 2. After this, the mempool expects # block H - 1, which is the last X block. self.nodes[0].generate(1) self.sync_all() # Mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # Check node 0 shielded balance assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) # Fill the mempool with twice as many transactions as can fit into blocks node0_taddr = self.nodes[0].getnewaddress() x_txids = [] while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000: x_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001'))) self.sync_all() # Spends should be in the mempool x_mempool = set(self.nodes[0].getrawmempool()) assert_equal(x_mempool, set(x_txids)) # Mine block H - 1. After this, the mempool expects # block H, which is the first Y block. self.nodes[0].generate(1) self.sync_all() # mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) # Block H - 1 should contain a subset of the original mempool # (with all other transactions having been dropped) block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx'] assert(len(block_txids) < len(x_txids)) for txid in block_txids[1:]: # Exclude coinbase assert(txid in x_txids) # Create some transparent Y transactions y_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)] self.sync_all() # Create a shielded Y transaction recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0')) shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) assert(shielded != None) y_txids.append(shielded) self.sync_all() # Spends should be in the mempool assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids)) # Node 0 note should be unspendable assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0')) # Invalidate block H - 1. block_hm1 = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(block_hm1) # BUG: Ideally, the mempool should now only contain the transactions # that were in block H - 1, the Y transactions having been dropped. # However, because chainActive is not updated until after the transactions # in the disconnected block have been re-added to the mempool, the height # seen by AcceptToMemoryPool is one greater than it should be. This causes # the block H - 1 transactions to be validated against the Y rules, # and rejected because they (obviously) fail. #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:])) assert_equal(set(self.nodes[0].getrawmempool()), set()) # Node 0 note should be spendable again assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) # Reconsider block H - 1. self.nodes[0].reconsiderblock(block_hm1) # Mine blocks on node 1, so that the Y transactions in its mempool # will be cleared. self.nodes[1].generate(6) self.sync_all()
def run_test(self): [alice, bob, charlie, david, miner] = self.nodes # the sender loses 'amount' plus fee; to_addr receives exactly 'amount' def z_send(from_node, from_addr, to_addr, amount): global fee opid = from_node.z_sendmany(from_addr, [{ "address": to_addr, "amount": Decimal(amount) }], 1, fee) wait_and_assert_operationid_status(from_node, opid) self.sync_all() miner.generate(1) self.sync_all() def verify_utxos(node, amts, zaddr): amts.sort(reverse=True) txs = node.z_listreceivedbyaddress(zaddr) def cmp_confirmations_high_to_low(a, b): return cmp(b["amount"], a["amount"]) txs.sort(cmp_confirmations_high_to_low) #print("Sorted txs", txs) #print("amts", amts) try: assert_equal(amts, [tx["amount"] for tx in txs]) for tx in txs: # make sure JoinSplit keys exist and have valid values assert_equal("jsindex" in tx, True) assert_equal("jsoutindex" in tx, True) assert_greater_than(tx["jsindex"], -1) assert_greater_than(tx["jsoutindex"], -1) except AssertionError: logging.error('Expected amounts: %r; txs: %r', amts, txs) raise def get_private_balance(node): balance = node.z_gettotalbalance() return balance['private'] def find_imported_key(node, import_zaddr): zaddrs = node.z_listaddresses() assert (import_zaddr in zaddrs) return import_zaddr # Seed Alice with some funds alice.generate(10) self.sync_all() miner.generate(100) self.sync_all() # Shield Alice's coinbase funds to her zaddr alice_zaddr = alice.z_getnewaddress('sprout') res = alice.z_shieldcoinbase("*", alice_zaddr) wait_and_assert_operationid_status(alice, res['opid']) self.sync_all() miner.generate(1) self.sync_all() # Now get a pristine z-address for receiving transfers: bob_zaddr = bob.z_getnewaddress('sprout') verify_utxos(bob, [], bob_zaddr) # TODO: Verify that charlie doesn't have funds in addr # verify_utxos(charlie, []) # the amounts of each txn embodied which generates a single UTXO: amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) # Internal test consistency assertion: assert_greater_than(get_private_balance(alice), reduce(Decimal.__add__, amounts)) logging.info("Sending pre-export txns...") for amount in amounts[0:2]: z_send(alice, alice_zaddr, bob_zaddr, amount) logging.info("Exporting privkey from bob...") bob_privkey = bob.z_exportkey(bob_zaddr) logging.info("Sending post-export txns...") for amount in amounts[2:4]: z_send(alice, alice_zaddr, bob_zaddr, amount) verify_utxos(bob, amounts[:4], bob_zaddr) # verify_utxos(charlie, []) logging.info("Importing bob_privkey into charlie...") # z_importkey rescan defaults to "whenkeyisnew", so should rescan here charlie.z_importkey(bob_privkey) ipk_zaddr = find_imported_key(charlie, bob_zaddr) # z_importkey should have rescanned for new key, so this should pass: verify_utxos(charlie, amounts[:4], ipk_zaddr) # Verify idempotent behavior: charlie.z_importkey(bob_privkey) ipk_zaddr2 = find_imported_key(charlie, bob_zaddr) assert_equal(ipk_zaddr, ipk_zaddr2) # amounts should be unchanged verify_utxos(charlie, amounts[:4], ipk_zaddr2) logging.info("Sending post-import txns...") for amount in amounts[4:]: z_send(alice, alice_zaddr, bob_zaddr, amount) verify_utxos(bob, amounts, bob_zaddr) verify_utxos(charlie, amounts, ipk_zaddr) verify_utxos(charlie, amounts, ipk_zaddr2) # keep track of the fees incurred by bob (his sends) bob_fee = Decimal(0) # Try to reproduce zombie balance reported in #1936 # At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice for amount in amounts[:2]: print("Sending amount from bob to alice: ", amount) z_send(bob, bob_zaddr, alice_zaddr, amount) bob_fee += fee bob_balance = sum(amounts[2:]) - bob_fee assert_equal(bob.z_getbalance(bob_zaddr), bob_balance) # z_import onto new node "david" (blockchain rescan, default or True?) david.z_importkey(bob_privkey) d_ipk_zaddr = find_imported_key(david, bob_zaddr) # Check if amt bob spent is deducted for charlie and david assert_equal(charlie.z_getbalance(ipk_zaddr), bob_balance) assert_equal(david.z_getbalance(d_ipk_zaddr), bob_balance)
def call_z_sendmany(self, from_addr, to_addr, amount): recipients = [] recipients.append({"address": to_addr, "amount": amount}) myopid = self.nodes[0].z_sendmany(from_addr, recipients) return wait_and_assert_operationid_status(self.nodes[0], myopid)
def run_test_release(self, release, height): self.generate_and_sync(height + 1) taddr = self.nodes[1].getnewaddress() zaddr1 = self.nodes[1].z_getnewaddress(release) self.nodes[0].sendtoaddress(taddr, 2.0) self.generate_and_sync(height + 2) # Send 1 ZEC to zaddr1 opid = self.nodes[1].z_sendmany(taddr, [{ 'address': zaddr2, 'amount': 0.6 }]) txid = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() r = self.nodes[1].z_listreceivedbyaddress(zaddr1) assert_equal(0, len(r), "Should have received no confirmed note") # No confirmation required, one note should be present r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) assert_equal(1, len(r), "Should have received one (unconfirmed) note") assert_equal(txid, r[0]['txid']) assert_equal(1, r[0]['amount']) assert_false(r[0]['change'], "Note should not be change") assert_equal(my_memo, r[0]['memo']) # Confirm transaction (1 ZEC from taddr to zaddr1) self.generate_and_sync(height + 3) # Require one confirmation, note should be present assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1)) # Generate some change by sending part of zaddr1 to zaddr2 zaddr2 = self.nodes[1].z_getnewaddress(release) opid = self.nodes[1].z_sendmany(zaddr1, [{ 'address': zaddr2, 'amount': 0.6, 'memo': my_memo }]) txid = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() self.generate_and_sync(height + 4) # zaddr1 should have a note with change r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) r = sorted(r, key=lambda received: received['amount']) assert_equal(2, len(r), "zaddr1 Should have received 2 notes") assert_equal(txid, r[0]['txid']) assert_equal(Decimal('0.4') - fee, r[0]['amount']) assert_true(r[0]['change'], "Note valued at (0.4-fee) should be change") assert_equal(no_memo, r[0]['memo']) # The old note still exists (it's immutable), even though it is spent assert_equal(Decimal('1.0'), r[1]['amount']) assert_false(r[1]['change'], "Note valued at 1.0 should not be change") assert_equal(my_memo, r[0]['memo']) # zaddr2 should not have change r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0) r = sorted(r, key=lambda received: received['amount']) assert_equal(1, len(r), "zaddr2 Should have received 1 notes") assert_equal(txid, r[0]['txid']) assert_equal(Decimal('0.6'), r[0]['amount']) assert_false(r[0]['change'], "Note valued at 0.6 should not be change") assert_equal(no_memo, r[0]['memo'])
def run_test(self): alice = self.nodes[0].getnewaddress() z_alice = self.nodes[0].z_getnewaddress() bob = self.nodes[2].getnewaddress() z_bob = self.nodes[2].z_getnewaddress() # When Overwinter not yet activated, no expiryheight in tx sapling_tx = self.nodes[0].sendtoaddress(bob, 0.01) rawtx = self.nodes[0].getrawtransaction(sapling_tx, 1) assert_equal(rawtx["overwintered"], False) assert("expiryheight" not in rawtx) self.nodes[0].generate(6) self.sync_all() print "Splitting network..." self.split_network() # When Overwinter is activated, test dependent txs firstTx = self.nodes[0].sendtoaddress(alice, 0.1) firstTxInfo = self.nodes[0].getrawtransaction(firstTx, 1) print "First tx expiry height:", firstTxInfo['expiryheight'] # Mine first transaction self.nodes[0].generate(1) for outpoint in firstTxInfo['vout']: if outpoint['value'] == Decimal('0.10000000'): vout = outpoint break inputs = [{'txid': firstTx, 'vout': vout['n'], 'scriptPubKey': vout['scriptPubKey']['hex']}] outputs = {alice: 0.1} rawTx = self.nodes[0].createrawtransaction(inputs, outputs) rawTxSigned = self.nodes[0].signrawtransaction(rawTx) assert(rawTxSigned['complete']) secondTx = self.nodes[0].sendrawtransaction(rawTxSigned['hex']) secondTxInfo = self.nodes[0].getrawtransaction(secondTx, 1) print "Second tx expiry height:", secondTxInfo['expiryheight'] # Mine second, dependent transaction self.nodes[0].generate(1) print "Mine 6 competing blocks on Node 2..." blocks = self.nodes[2].generate(6) print "Connect nodes to force a reorg" connect_nodes_bi(self.nodes,0,2) self.is_network_split = False print "Syncing blocks" sync_blocks(self.nodes) print "Ensure that both txs are dropped from mempool of node 0" print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks'] print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks'] assert_equal(set(self.nodes[0].getrawmempool()), set()) assert_equal(set(self.nodes[2].getrawmempool()), set()) ## Shield one of Alice's coinbase funds to her zaddr res = self.nodes[0].z_shieldcoinbase("*", z_alice, 0.0001, 1) wait_and_assert_operationid_status(self.nodes[0], res['opid']) self.nodes[0].generate(1) self.sync_all() # Get balance on node 0 bal = self.nodes[0].z_gettotalbalance() print "Balance before zsend, after shielding 10: ", bal assert_equal(Decimal(bal["private"]), Decimal("9.9999")) print "Splitting network..." self.split_network() # Create transactions blockheight = self.nodes[0].getblockchaininfo()['blocks'] zsendamount = Decimal('1.0') - Decimal('0.0001') recipients = [] recipients.append({"address": z_bob, "amount": zsendamount}) myopid = self.nodes[0].z_sendmany(z_alice, recipients) persist_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) persist_transparent = self.nodes[0].sendtoaddress(bob, 0.01) # Verify transparent transaction is version 3 intended for Overwinter branch rawtx = self.nodes[0].getrawtransaction(persist_transparent, 1) assert_equal(rawtx["version"], 3) assert_equal(rawtx["overwintered"], True) assert_equal(rawtx["expiryheight"], blockheight + 5) print "Blockheight at persist_transparent & persist_shielded creation:", self.nodes[0].getblockchaininfo()['blocks'] print "Expiryheight of persist_transparent:", rawtx['expiryheight'] # Verify shielded transaction is version 3 intended for Overwinter branch rawtx = self.nodes[0].getrawtransaction(persist_shielded, 1) print "Expiryheight of persist_shielded", rawtx['expiryheight'] assert_equal(rawtx["version"], 3) assert_equal(rawtx["overwintered"], True) assert_equal(rawtx["expiryheight"], blockheight + 5) print "\n Blockheight advances to less than expiry block height. After reorg, txs should persist in mempool" assert(persist_transparent in self.nodes[0].getrawmempool()) assert(persist_shielded in self.nodes[0].getrawmempool()) assert_equal(set(self.nodes[2].getrawmempool()), set()) print "mempool node 0:", self.nodes[0].getrawmempool() print "mempool node 2:", self.nodes[2].getrawmempool() bal = self.nodes[0].z_gettotalbalance() print "Printing balance before persist_shielded & persist_transparent are initially mined from mempool", bal # Txs are mined on node 0; will later be rolled back self.nodes[0].generate(1) print "Node 0 generated 1 block" print "Node 0 height:", self.nodes[0].getblockchaininfo()['blocks'] print "Node 2 height:", self.nodes[2].getblockchaininfo()['blocks'] bal = self.nodes[0].z_gettotalbalance() print "Printing balance after persist_shielded & persist_transparent are mined:", bal assert_equal(set(self.nodes[0].getrawmempool()), set()) print "Mine 2 competing blocks on Node 2..." blocks = self.nodes[2].generate(2) for block in blocks: blk = self.nodes[2].getblock(block) print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"]) print "Connect nodes to force a reorg" connect_nodes_bi(self.nodes,0,2) self.is_network_split = False print "Syncing blocks" sync_blocks(self.nodes) print "Ensure that txs are back in mempool of node 0" print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks'] print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks'] print "mempool node 0: ", self.nodes[0].getrawmempool() print "mempool node 2: ", self.nodes[2].getrawmempool() assert(persist_transparent in self.nodes[0].getrawmempool()) assert(persist_shielded in self.nodes[0].getrawmempool()) bal = self.nodes[0].z_gettotalbalance() # Mine txs to get them out of the way of mempool sync in split_network() print "Generating another block on node 0 to clear txs from mempool" self.nodes[0].generate(1) assert_equal(set(self.nodes[0].getrawmempool()), set()) sync_blocks(self.nodes) print "Splitting network..." self.split_network() print "\n Blockheight advances to equal expiry block height. After reorg, txs should persist in mempool" myopid = self.nodes[0].z_sendmany(z_alice, recipients) persist_shielded_2 = wait_and_assert_operationid_status(self.nodes[0], myopid) persist_transparent_2 = self.nodes[0].sendtoaddress(bob, 0.01) rawtx_trans = self.nodes[0].getrawtransaction(persist_transparent_2, 1) rawtx_shield = self.nodes[0].getrawtransaction(persist_shielded_2, 1) print "Blockheight node 0 at persist_transparent_2 creation:", self.nodes[0].getblockchaininfo()['blocks'] print "Blockheight node 2 at persist_transparent_2 creation:", self.nodes[2].getblockchaininfo()['blocks'] print "Expiryheight of persist_transparent_2:", rawtx_trans['expiryheight'] print "Expiryheight of persist_shielded_2:", rawtx_shield['expiryheight'] blocks = self.nodes[2].generate(4) for block in blocks: blk = self.nodes[2].getblock(block) print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"]) print "Connect nodes to force a reorg" connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False sync_blocks(self.nodes) print "Ensure that persist_transparent_2 & persist_shielded_2 are in mempool at expiry block height" print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks'] print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks'] print "mempool node 0: ", self.nodes[0].getrawmempool() print "mempool node 2: ", self.nodes[2].getrawmempool() assert(persist_transparent_2 in self.nodes[0].getrawmempool()) assert(persist_shielded_2 in self.nodes[0].getrawmempool()) # Mine persist txs to get them out of the way of mempool sync in split_network() self.nodes[0].generate(1) assert_equal(set(self.nodes[0].getrawmempool()), set()) sync_blocks(self.nodes) print "Balance after persist_shielded_2 is mined to remove from mempool: ", self.nodes[0].z_gettotalbalance() print "Splitting network..." self.split_network() print "\n Blockheight advances to greater than expiry block height. After reorg, txs should expire from mempool" print "Balance before expire_shielded is sent: ", self.nodes[0].z_gettotalbalance() myopid = self.nodes[0].z_sendmany(z_alice, recipients) expire_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) expire_transparent = self.nodes[0].sendtoaddress(bob, 0.01) print "Blockheight node 0 at expire_transparent creation:", self.nodes[0].getblockchaininfo()['blocks'] print "Blockheight node 2 at expire_shielded creation:", self.nodes[2].getblockchaininfo()['blocks'] print "Expiryheight of expire_transparent:", self.nodes[0].getrawtransaction(expire_transparent, 1)['expiryheight'] print "Expiryheight of expire_shielded:", self.nodes[0].getrawtransaction(expire_shielded, 1)['expiryheight'] assert(expire_transparent in self.nodes[0].getrawmempool()) assert(expire_shielded in self.nodes[0].getrawmempool()) blocks = self.nodes[2].generate(6) for block in blocks: blk = self.nodes[2].getblock(block) print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"]) print "Connect nodes to force a reorg" connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False sync_blocks(self.nodes) print "Ensure that expire_transparent & expire_shielded are in mempool at expiry block height" print "mempool node 0: ", self.nodes[0].getrawmempool() print "mempool node 2: ", self.nodes[2].getrawmempool() assert_equal(set(self.nodes[0].getrawmempool()), set()) print "Ensure balance of node 0 is correct" bal = self.nodes[0].z_gettotalbalance() print "Balance after expire_shielded has expired: ", bal assert_equal(Decimal(bal["private"]), Decimal("7.9999"))
def run_test(self): # Current height = 200 -> Sprout assert_equal(200, self.nodes[0].getblockcount()) sproutzaddr = self.nodes[0].z_getnewaddress('sprout') # test that we can create a sapling zaddr before sapling activates saplingzaddr = self.nodes[0].z_getnewaddress('sapling') # we've got lots of coinbase (taddr) but no shielded funds yet assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) # Set current height to 201 -> Sprout self.nodes[0].generate(1) self.sync_all() assert_equal(201, self.nodes[0].getblockcount()) mining_addr = self.nodes[0].listunspent()[0]['address'] # Shield coinbase funds (must be a multiple of 10, no change allowed pre-sapling) receive_amount_10 = Decimal('10.0') - Decimal('0.0001') recipients = [{"address":sproutzaddr, "amount":receive_amount_10}] myopid = self.nodes[0].z_sendmany(mining_addr, recipients) txid_1 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # No funds (with (default) one or more confirmations) in sproutzaddr yet assert_equal(0, len(self.nodes[0].z_listunspent())) assert_equal(0, len(self.nodes[0].z_listunspent(1))) # no private balance because no confirmations yet assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) # list private unspent, this time allowing 0 confirmations unspent_cb = self.nodes[0].z_listunspent(0) assert_equal(1, len(unspent_cb)) assert_equal(False, unspent_cb[0]['change']) assert_equal(txid_1, unspent_cb[0]['txid']) assert_equal(True, unspent_cb[0]['spendable']) assert_equal(sproutzaddr, unspent_cb[0]['address']) assert_equal(receive_amount_10, unspent_cb[0]['amount']) # list unspent, filtering by address, should produce same result unspent_cb_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) assert_equal(unspent_cb, unspent_cb_filter) # Generate a block to confirm shield coinbase tx self.nodes[0].generate(1) self.sync_all() # Current height = 202 -> Overwinter. Default address type remains Sprout assert_equal(202, self.nodes[0].getblockcount()) # Send 1.0 (actually 0.9999) from sproutzaddr to a new zaddr sproutzaddr2 = self.nodes[0].z_getnewaddress() receive_amount_1 = Decimal('1.0') - Decimal('0.0001') change_amount_9 = receive_amount_10 - Decimal('1.0') assert_equal('sprout', self.nodes[0].z_validateaddress(sproutzaddr2)['type']) recipients = [{"address": sproutzaddr2, "amount":receive_amount_1}] myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients) txid_2 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # list unspent, allowing 0conf txs unspent_tx = self.nodes[0].z_listunspent(0) assert_equal(len(unspent_tx), 2) # sort low-to-high by amount (order of returned entries is not guaranteed) unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) assert_equal(False, unspent_tx[0]['change']) assert_equal(txid_2, unspent_tx[0]['txid']) assert_equal(True, unspent_tx[0]['spendable']) assert_equal(sproutzaddr2, unspent_tx[0]['address']) assert_equal(receive_amount_1, unspent_tx[0]['amount']) assert_equal(True, unspent_tx[1]['change']) assert_equal(txid_2, unspent_tx[1]['txid']) assert_equal(True, unspent_tx[1]['spendable']) assert_equal(sproutzaddr, unspent_tx[1]['address']) assert_equal(change_amount_9, unspent_tx[1]['amount']) unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr2]) assert_equal(1, len(unspent_tx_filter)) assert_equal(unspent_tx[0], unspent_tx_filter[0]) unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) assert_equal(1, len(unspent_tx_filter)) assert_equal(unspent_tx[1], unspent_tx_filter[0]) # Set current height to 204 -> Sapling self.nodes[0].generate(2) self.sync_all() assert_equal(204, self.nodes[0].getblockcount()) # No funds in saplingzaddr yet assert_equal(0, len(self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr]))) # Send 0.9999 to our sapling zaddr # (sending from a sprout zaddr to a sapling zaddr is disallowed, # so send from coin base) receive_amount_2 = Decimal('2.0') - Decimal('0.0001') recipients = [{"address": saplingzaddr, "amount":receive_amount_2}] myopid = self.nodes[0].z_sendmany(mining_addr, recipients) txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() unspent_tx = self.nodes[0].z_listunspent(0) assert_equal(3, len(unspent_tx)) # low-to-high in amount unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) assert_equal(False, unspent_tx[0]['change']) assert_equal(txid_2, unspent_tx[0]['txid']) assert_equal(True, unspent_tx[0]['spendable']) assert_equal(sproutzaddr2, unspent_tx[0]['address']) assert_equal(receive_amount_1, unspent_tx[0]['amount']) assert_equal(False, unspent_tx[1]['change']) assert_equal(txid_3, unspent_tx[1]['txid']) assert_equal(True, unspent_tx[1]['spendable']) assert_equal(saplingzaddr, unspent_tx[1]['address']) assert_equal(receive_amount_2, unspent_tx[1]['amount']) assert_equal(True, unspent_tx[2]['change']) assert_equal(txid_2, unspent_tx[2]['txid']) assert_equal(True, unspent_tx[2]['spendable']) assert_equal(sproutzaddr, unspent_tx[2]['address']) assert_equal(change_amount_9, unspent_tx[2]['amount']) unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr]) assert_equal(1, len(unspent_tx_filter)) assert_equal(unspent_tx[1], unspent_tx_filter[0]) # test that pre- and post-sapling can be filtered in a single call unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr, saplingzaddr]) assert_equal(2, len(unspent_tx_filter)) unspent_tx_filter = sorted(unspent_tx_filter, key=lambda k: k['amount']) assert_equal(unspent_tx[1], unspent_tx_filter[0]) assert_equal(unspent_tx[2], unspent_tx_filter[1]) # so far, this node has no watchonly addresses, so results are the same unspent_tx_watchonly = self.nodes[0].z_listunspent(0, 9999, True) unspent_tx_watchonly = sorted(unspent_tx_watchonly, key=lambda k: k['amount']) assert_equal(unspent_tx, unspent_tx_watchonly)
class WalletOverwinterTxTest (BitcoinTestFramework): def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, 4) def setup_network(self, split=False): self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[["-nuparams=5ba81b19:200", "-debug=zrpcunsafe", "-txindex"]] * 4 ) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) connect_nodes_bi(self.nodes,0,3) self.is_network_split=False self.sync_all() def run_test (self): self.nodes[0].generate(100) self.sync_all() self.nodes[1].generate(98) self.sync_all() # Node 0 has reward from blocks 1 to 98 which are spendable. taddr0 = self.nodes[0].getnewaddress() taddr1 = self.nodes[1].getnewaddress() taddr2 = self.nodes[2].getnewaddress() zaddr2 = self.nodes[2].z_getnewaddress('sprout') taddr3 = self.nodes[3].getnewaddress() zaddr3 = self.nodes[3].z_getnewaddress('sprout') # # Currently at block 198. The next block to be mined 199 is a Sprout block # bci = self.nodes[0].getblockchaininfo() assert_equal(bci['consensus']['chaintip'], '00000000') assert_equal(bci['consensus']['nextblock'], '00000000') assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') # Cannot use the expiryheight parameter of createrawtransaction if Overwinter is not active in the next block try: self.nodes[0].createrawtransaction([], {}, 0, 99) except JSONRPCException,e: errorString = e.error['message'] assert_equal("Invalid parameter, expiryheight can only be used if Overwinter is active when the transaction is mined" in errorString, True) # Node 0 sends transparent funds to Node 2 tsendamount = Decimal('1.0') txid_transparent = self.nodes[0].sendtoaddress(taddr2, tsendamount) self.sync_all() # Node 2 sends the zero-confirmation transparent funds to Node 1 using z_sendmany recipients = [] recipients.append({"address":taddr1, "amount": Decimal('0.5')}) myopid = self.nodes[2].z_sendmany(taddr2, recipients, 0) txid_zsendmany = wait_and_assert_operationid_status(self.nodes[2], myopid) # Node 0 shields to Node 2, a coinbase utxo of value 10.0 less fee 0.00010000 zsendamount = Decimal('10.0') - Decimal('0.0001') recipients = [] recipients.append({"address":zaddr2, "amount": zsendamount}) myopid = self.nodes[0].z_sendmany(taddr0, recipients) txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0.5')) assert_equal(self.nodes[2].getbalance(), Decimal('0.4999')) assert_equal(self.nodes[2].z_getbalance(zaddr2), zsendamount) # Verify transaction versions are 1 or 2 (intended for Sprout) result = self.nodes[0].getrawtransaction(txid_transparent, 1) assert_equal(result["version"], 1) assert_equal(result["overwintered"], False) result = self.nodes[0].getrawtransaction(txid_zsendmany, 1) assert_equal(result["version"], 1) assert_equal(result["overwintered"], False) result = self.nodes[0].getrawtransaction(txid_shielded, 1) assert_equal(result["version"], 2) assert_equal(result["overwintered"], False) # # Currently at block 199. The next block to be mined 200 is an Overwinter block # bci = self.nodes[0].getblockchaininfo() assert_equal(bci['consensus']['chaintip'], '00000000') assert_equal(bci['consensus']['nextblock'], '5ba81b19') assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') # Test using expiryheight parameter of createrawtransaction when Overwinter is active in the next block errorString = "" try: self.nodes[0].createrawtransaction([], {}, 0, 499999999) except JSONRPCException,e: errorString = e.error['message']
def run_test(self): # Activate Overwinter and Sapling self.nodes[0].generate(200) self.sync_all() # Verfify genesis block contains null field for what is now called the final sapling root field. blk = self.nodes[0].getblock("0") assert_equal(blk["finalsaplingroot"], NULL_FIELD) # Verify all generated blocks contain the empty root of the Sapling tree. blockcount = self.nodes[0].getblockcount() for height in xrange(1, blockcount + 1): blk = self.nodes[0].getblock(str(height)) assert_equal(blk["finalsaplingroot"], SAPLING_TREE_EMPTY_ROOT) # Node 0 shields some funds taddr0 = get_coinbase_address(self.nodes[0]) saplingAddr0 = self.nodes[0].z_getnewaddress('sapling') recipients = [] recipients.append({"address": saplingAddr0, "amount": Decimal('20')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify the final Sapling root has changed blk = self.nodes[0].getblock("201") root = blk["finalsaplingroot"] assert(root is not SAPLING_TREE_EMPTY_ROOT) assert(root is not NULL_FIELD) # Verify there is a Sapling output description (its commitment was added to tree) result = self.nodes[0].getrawtransaction(mytxid, 1) assert_equal(len(result["vShieldedOutput"]), 1) # Mine an empty block and verify the final Sapling root does not change self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(root, self.nodes[0].getblock("202")["finalsaplingroot"]) # Mine a block with a transparent tx and verify the final Sapling root does not change taddr1 = self.nodes[1].getnewaddress() self.nodes[0].sendtoaddress(taddr1, Decimal("1.23")) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(len(self.nodes[0].getblock("203")["tx"]), 2) assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal("1.23")) assert_equal(root, self.nodes[0].getblock("203")["finalsaplingroot"]) # Mine a block with a Sprout shielded tx and verify the final Sapling root does not change zaddr1 = self.nodes[1].z_getnewaddress('sprout') recipients = [] recipients.append({"address": zaddr1, "amount": Decimal('10')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(len(self.nodes[0].getblock("204")["tx"]), 2) assert_equal(self.nodes[1].z_getbalance(zaddr1), Decimal("10")) assert_equal(root, self.nodes[0].getblock("204")["finalsaplingroot"]) # Mine a block with a Sapling shielded recipient and verify the final Sapling root changes saplingAddr1 = self.nodes[1].z_getnewaddress("sapling") recipients = [] recipients.append({"address": saplingAddr1, "amount": Decimal('12.34')}) myopid = self.nodes[0].z_sendmany(saplingAddr0, recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(len(self.nodes[0].getblock("205")["tx"]), 2) assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal("12.34")) assert(root is not self.nodes[0].getblock("205")["finalsaplingroot"]) # Verify there is a Sapling output description (its commitment was added to tree) result = self.nodes[0].getrawtransaction(mytxid, 1) assert_equal(len(result["vShieldedOutput"]), 2) # there is Sapling shielded change # Mine a block with a Sapling shielded sender and transparent recipient and verify the final Sapling root doesn't change taddr2 = self.nodes[0].getnewaddress() recipients = [] recipients.append({"address": taddr2, "amount": Decimal('12.34')}) myopid = self.nodes[1].z_sendmany(saplingAddr1, recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(len(self.nodes[0].getblock("206")["tx"]), 2) assert_equal(self.nodes[0].z_getbalance(taddr2), Decimal("12.34")) blk = self.nodes[0].getblock("206") root = blk["finalsaplingroot"] assert_equal(root, self.nodes[0].getblock("205")["finalsaplingroot"])
def run_test (self): self.nodes[0].generate(100) self.sync_all() self.nodes[1].generate(98) self.sync_all() # Node 0 has reward from blocks 1 to 98 which are spendable. taddr0 = self.nodes[0].getnewaddress() taddr1 = self.nodes[1].getnewaddress() taddr2 = self.nodes[2].getnewaddress() zaddr2 = self.nodes[2].z_getnewaddress() taddr3 = self.nodes[3].getnewaddress() zaddr3 = self.nodes[3].z_getnewaddress() # # Currently at block 198. The next block to be mined 199 is a Sprout block # bci = self.nodes[0].getblockchaininfo() assert_equal(bci['consensus']['chaintip'], '00000000') assert_equal(bci['consensus']['nextblock'], '00000000') assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') # Node 0 sends transparent funds to Node 2 tsendamount = Decimal('1.0') txid_transparent = self.nodes[0].sendtoaddress(taddr2, tsendamount) self.sync_all() # Node 2 sends the zero-confirmation transparent funds to Node 1 using z_sendmany recipients = [] recipients.append({"address":taddr1, "amount": Decimal('0.5')}) myopid = self.nodes[2].z_sendmany(taddr2, recipients, 0) txid_zsendmany = wait_and_assert_operationid_status(self.nodes[2], myopid) # Node 0 shields to Node 2, a coinbase utxo of value 10.0 less fee 0.00010000 zsendamount = Decimal('10.0') - Decimal('0.0001') recipients = [] recipients.append({"address":zaddr2, "amount": zsendamount}) myopid = self.nodes[0].z_sendmany(taddr0, recipients) txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0.5')) assert_equal(self.nodes[2].getbalance(), Decimal('0.4999')) assert_equal(self.nodes[2].z_getbalance(zaddr2), zsendamount) # Verify transaction versions are 1 or 2 (intended for Sprout) result = self.nodes[0].getrawtransaction(txid_transparent, 1) assert_equal(result["version"], 1) assert_equal(result["overwintered"], False) result = self.nodes[0].getrawtransaction(txid_zsendmany, 1) assert_equal(result["version"], 1) assert_equal(result["overwintered"], False) result = self.nodes[0].getrawtransaction(txid_shielded, 1) assert_equal(result["version"], 2) assert_equal(result["overwintered"], False) # # Currently at block 199. The next block to be mined 200 is an Overwinter block # bci = self.nodes[0].getblockchaininfo() assert_equal(bci['consensus']['chaintip'], '00000000') assert_equal(bci['consensus']['nextblock'], '5ba81b19') assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') # Node 0 sends transparent funds to Node 3 tsendamount = Decimal('1.0') txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount) self.sync_all() # Node 3 sends the zero-confirmation transparent funds to Node 1 using z_sendmany recipients = [] recipients.append({"address":taddr1, "amount": Decimal('0.5')}) myopid = self.nodes[3].z_sendmany(taddr3, recipients, 0) txid_zsendmany = wait_and_assert_operationid_status(self.nodes[3], myopid) # Node 0 shields to Node 3, a coinbase utxo of value 10.0 less fee 0.00010000 zsendamount = Decimal('10.0') - Decimal('0.0001') recipients = [] recipients.append({"address":zaddr3, "amount": zsendamount}) myopid = self.nodes[0].z_sendmany(taddr0, recipients) txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) # Mine the first Overwinter block self.sync_all() self.nodes[0].generate(1) self.sync_all() bci = self.nodes[0].getblockchaininfo() assert_equal(bci['consensus']['chaintip'], '5ba81b19') assert_equal(bci['consensus']['nextblock'], '5ba81b19') assert_equal(bci['upgrades']['5ba81b19']['status'], 'active') # Verify balance assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('1.0')) assert_equal(self.nodes[3].getbalance(), Decimal('0.4999')) assert_equal(self.nodes[3].z_getbalance(zaddr3), zsendamount) # Verify transaction version is 3 (intended for Overwinter) result = self.nodes[0].getrawtransaction(txid_transparent, 1) assert_equal(result["version"], 3) assert_equal(result["overwintered"], True) assert_equal(result["versiongroupid"], "03c48270") result = self.nodes[0].getrawtransaction(txid_zsendmany, 1) assert_equal(result["version"], 3) assert_equal(result["overwintered"], True) assert_equal(result["versiongroupid"], "03c48270") result = self.nodes[0].getrawtransaction(txid_shielded, 1) assert_equal(result["version"], 3) assert_equal(result["overwintered"], True) assert_equal(result["versiongroupid"], "03c48270")