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 = get_coinbase_address(self.nodes[0]) 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']
def run_test(self): # Check enabling via '-migration' and disabling via rpc check_migration_status(self.nodes[0], True, SAPLING_ADDR, False, False, False, 0, 0) self.nodes[0].z_setmigration(False) check_migration_status(self.nodes[0], False, SAPLING_ADDR, False, False, False, 0, 0) # 1. Test using self.nodes[0] which has the parameter print("Running test using '-migrationdestaddress'...") print("Mining blocks...") self.nodes[0].generate(101) self.sync_all() tAddr = get_coinbase_address(self.nodes[0]) # Import a previously generated key to test '-migrationdestaddress' self.nodes[0].z_importkey(SAPLING_KEY) sproutAddr0 = self.nodes[0].z_getnewaddress('sprout') self.send_to_sprout_zaddr(tAddr, sproutAddr0) self.run_migration_test(self.nodes[0], sproutAddr0, SAPLING_ADDR, 500) # Disable migration so only self.nodes[1] has a transaction in the mempool at block 999 self.nodes[0].z_setmigration(False) # 2. Test using self.nodes[1] which will use the default Sapling address print("Running test using default Sapling address...") # Mine more blocks so we start at 102 % 500 print("Mining blocks...") self.nodes[1].generate(91) # 511 -> 602 self.sync_all() sproutAddr1 = self.nodes[1].z_getnewaddress('sprout') saplingAddr1 = self.nodes[1].z_getnewaddress('sapling') self.send_to_sprout_zaddr(tAddr, sproutAddr1) self.run_migration_test(self.nodes[1], sproutAddr1, saplingAddr1, 1000)
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): 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)
class WalletProtectCoinbaseTest(BitcoinTestFramework): def setup_chain(self): print("Initializing test directory " + self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, 4) # Start nodes with -regtestprotectcoinbase to set fCoinbaseMustBeProtected to true. def setup_network(self, split=False): self.nodes = start_nodes( 4, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-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) 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", "no UTXOs found for taddr from address", 10) # This send will fail because our wallet does not allow any change when protecting 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( self.nodes[0], myopid, "failed", "wallet does not allow any change", 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 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('12.5')}) 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): 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): print "Mining blocks..." self.nodes[0].generate(100) self.sync_all() self.nodes[1].generate(101) self.sync_all() mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # 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('sprout'), "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('sprout'), "amount":Decimal('18')}) recipients.append({"address":self.nodes[2].z_getnewaddress('sprout'), "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): # 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 = get_coinbase_address(self.nodes[0]) 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'))
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): self.nodes[0].generate(200) self.sync_all() # Verify 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) treestate = self.nodes[0].z_gettreestate("0") assert_equal(treestate["height"], 0) assert_equal(treestate["hash"], self.nodes[0].getblockhash(0)) assert_equal(treestate["sprout"]["commitments"]["finalRoot"], SPROUT_TREE_EMPTY_ROOT) assert_equal(treestate["sprout"]["commitments"]["finalState"], "000000") assert("skipHash" not in treestate["sprout"]) assert_equal(treestate["sapling"]["commitments"]["finalRoot"], NULL_FIELD) # There is no sapling state tree yet, and trying to find it in an earlier # block won't succeed (we're at genesis block), so skipHash is absent. assert("finalState" not in treestate["sapling"]) assert("skipHash" not in treestate["sapling"]) # Verify all generated blocks contain the empty root of the Sapling tree. blockcount = self.nodes[0].getblockcount() for height in range(1, blockcount + 1): blk = self.nodes[0].getblock(str(height)) assert_equal(blk["finalsaplingroot"], SAPLING_TREE_EMPTY_ROOT) treestate = self.nodes[0].z_gettreestate(str(height)) assert_equal(treestate["height"], height) assert_equal(treestate["hash"], self.nodes[0].getblockhash(height)) assert("skipHash" not in treestate["sprout"]) assert_equal(treestate["sprout"]["commitments"]["finalRoot"], SPROUT_TREE_EMPTY_ROOT) assert_equal(treestate["sprout"]["commitments"]["finalState"], "000000") assert("skipHash" not in treestate["sapling"]) assert_equal(treestate["sapling"]["commitments"]["finalRoot"], SAPLING_TREE_EMPTY_ROOT) assert_equal(treestate["sapling"]["commitments"]["finalState"], "000000") # 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) # Since there is a now sapling shielded input in the blockchain, # the sapling values should have changed new_treestate = self.nodes[0].z_gettreestate(str(-1)) assert_equal(new_treestate["sapling"]["commitments"]["finalRoot"], root) assert_equal(new_treestate["sprout"], treestate["sprout"]) assert(new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"]) assert(new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"]) assert_equal(len(new_treestate["sapling"]["commitments"]["finalRoot"]), 64) assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 70) treestate = new_treestate # 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"]) new_treestate = self.nodes[0].z_gettreestate(str(-1)) assert_equal(new_treestate["sapling"]["commitments"]["finalRoot"], root) assert_equal(new_treestate["sapling"], treestate["sapling"]) assert(new_treestate["sprout"]["commitments"]["finalRoot"] != treestate["sprout"]["commitments"]["finalRoot"]) assert(new_treestate["sprout"]["commitments"]["finalState"] != treestate["sprout"]["commitments"]["finalState"]) assert_equal(len(new_treestate["sprout"]["commitments"]["finalRoot"]), 64) assert_equal(len(new_treestate["sprout"]["commitments"]["finalState"]), 134) treestate = new_treestate # 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 new_treestate = self.nodes[0].z_gettreestate(str(-1)) assert_equal(new_treestate["sprout"], treestate["sprout"]) assert(new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"]) assert(new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"]) assert_equal(len(new_treestate["sapling"]["commitments"]["finalRoot"]), 64) assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 136) treestate = new_treestate # 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"]) new_treestate = self.nodes[0].z_gettreestate(str(-1)) assert_equal(new_treestate["sprout"], treestate["sprout"]) assert_equal(new_treestate["sapling"], treestate["sapling"])
def run_test(self): print "Mining blocks..." self.nodes[0].setmocktime(starttime) self.nodes[0].generate(101) self.sync_all() 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) self.sync_all() # 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): # 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('700.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":200.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('200.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":1000.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('1000.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('25000.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('100.0'), 'private': zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, 'total': node3mined + Decimal('100.0') + zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, }) # Check individual balances reflect the above assert_equal(self.nodes[3].z_getbalance(mytaddr1), Decimal('100.0')) assert_equal(self.nodes[3].z_getbalance(myzaddr), zsendmanynotevalue + zaddrremaining + zaddrremaining2)
def run_test(self): print("Mining blocks...") self.nodes[0].generate(1) self.nodes[0].generate(4) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[2].generate(1) self.nodes[2].generate(1) self.nodes[2].generate(1) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 30) # create one zaddr that is the target of all shielding myzaddr = self.test_init_zaddr(self.nodes[0]) do_not_shield_taddr = get_coinbase_address(self.nodes[0], 1) # Prepare to send taddr->zaddr mytaddr = get_coinbase_address(self.nodes[0], 4) # Shielding will fail when trying to spend from watch-only address self.nodes[2].importaddress(mytaddr) try: self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr) except JSONRPCException as e: errorString = e.error['message'] assert_equal( "Could not find any coinbase funds to shield" in errorString, True) # Shielding will fail because fee is negative try: self.nodes[0].z_shieldcoinbase("*", myzaddr, -1) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Amount out of range" in errorString, True) # Shielding will fail because fee is larger than MAX_MONEY try: self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('21000000.00000001')) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Amount out of range" in errorString, True) # Shielding will fail because fee is larger than sum of utxos try: self.nodes[0].z_shieldcoinbase("*", myzaddr, 999) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Insufficient coinbase funds" in errorString, True) # Shielding will fail because limit parameter must be at least 0 try: self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), -1) except JSONRPCException as e: 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 as 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 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 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')) self.test_check_balance_zaddr(self.nodes[0], Decimal('40.0') - DEFAULT_FEE) assert_equal(self.nodes[1].getbalance(), 20) assert_equal(self.nodes[2].getbalance(), 30) # Shield coinbase utxos from any node 2 taddr, and set fee to 0 result = self.nodes[2].z_shieldcoinbase("*", myzaddr, 0) wait_and_assert_operationid_status(self.nodes[2], result['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), 10) self.test_check_balance_zaddr(self.nodes[0], Decimal('70.0') - DEFAULT_FEE) assert_equal(self.nodes[1].getbalance(), 30) assert_equal(self.nodes[2].getbalance(), 0) # Generate 800 coinbase utxos on node 0, and 20 coinbase utxos on node 2 self.nodes[0].generate(800) self.sync_all() self.nodes[2].generate(20) self.sync_all() self.nodes[1].generate(100) self.sync_all() mytaddr = get_coinbase_address(self.nodes[0], 800) def verify_locking(first, second, limit): result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, limit) assert_equal(result["shieldingUTXOs"], Decimal(first)) assert_equal(result["remainingUTXOs"], Decimal(second)) remainingValue = result["remainingValue"] opid1 = result['opid'] # Verify that utxos are locked (not available for selection) by queuing up another shielding operation result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 0) assert_equal(result["shieldingValue"], Decimal(remainingValue)) assert_equal(result["shieldingUTXOs"], Decimal(second)) assert_equal(result["remainingValue"], Decimal('0')) assert_equal(result["remainingUTXOs"], Decimal('0')) opid2 = result['opid'] # wait for both async operations to complete wait_and_assert_operationid_status(self.nodes[0], opid1) wait_and_assert_operationid_status(self.nodes[0], opid2) # Shield the 800 utxos over two transactions verify_locking('500', '300', 500) # 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(self.nodes[:2]) sync_mempools(self.nodes[:2]) self.nodes[1].generate(1) self.sync_all() # Verify maximum number of utxos which node 0 can shield is set by default limit parameter of 50 self.nodes[0].generate(200) self.sync_all() mytaddr = get_coinbase_address(self.nodes[0], 100) result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, DEFAULT_FEE) assert_equal(result["shieldingUTXOs"], Decimal('50')) assert_equal(result["remainingUTXOs"], Decimal('50')) wait_and_assert_operationid_status(self.nodes[0], result['opid']) # Verify maximum number of utxos which node 0 can shield can be set by the limit parameter result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, DEFAULT_FEE, 33) assert_equal(result["shieldingUTXOs"], Decimal('33')) assert_equal(result["remainingUTXOs"], Decimal('17')) wait_and_assert_operationid_status(self.nodes[0], result['opid']) # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit sync_blocks(self.nodes[:2]) sync_mempools(self.nodes[:2]) self.nodes[1].generate(1) self.sync_all() # Note, no "if __name__ == '__main__" and call the test here; it's called from # pool-specific derived classes in wallet_shieldcoinbase_*.py
def run_test (self): print "Mining blocks..." 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[1].generate(102) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 25) 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('12.5') - 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('12.5') - 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(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('3920000')}) 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('3920000')) # Verify size of shielded pool self.assert_pool_balance(self.nodes[0], POOL_NAME.lower(), Decimal('3920000')) self.assert_pool_balance(self.nodes[1], POOL_NAME.lower(), Decimal('3920000')) self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('3920000')) # 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('3920000')) self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('3920000')) # 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('3919999')) self.assert_pool_balance(self.nodes[2], POOL_NAME.lower(), Decimal('3919999')) # 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())
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 ZCL 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()
self.sync_all() assert_equal(self.nodes[0].getbalance(), 10) assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('69.99990000')) assert_equal(self.nodes[1].getbalance(), 30) assert_equal(self.nodes[2].getbalance(), 0) # Generate 800 coinbase utxos on node 0, and 20 coinbase utxos on node 2 self.nodes[0].generate(800) self.sync_all() self.nodes[2].generate(20) self.sync_all() self.nodes[1].generate(100) self.sync_all() mytaddr = get_coinbase_address(self.nodes[0], 800) def verify_locking(first, second, limit): result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, limit) assert_equal(result["shieldingUTXOs"], Decimal(first)) assert_equal(result["remainingUTXOs"], Decimal(second)) remainingValue = result["remainingValue"] opid1 = result['opid'] # Verify that utxos are locked (not available for selection) by queuing up another shielding operation result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 0) assert_equal(result["shieldingValue"], Decimal(remainingValue)) assert_equal(result["shieldingUTXOs"], Decimal(second)) assert_equal(result["remainingValue"], Decimal('0')) assert_equal(result["remainingUTXOs"], Decimal('0')) opid2 = result['opid']
def run_test(self): print("Mining blocks...") self.sync_all() self.nodes[1].generate(1) self.sync_all() self.nodes[2].generate(1) self.sync_all() self.nodes[3].generate(1) self.sync_all() self.nodes[0].generate(100) self.sync_all() assert_equal(Decimal("10.00"), Decimal(self.nodes[1].z_gettotalbalance()['transparent'])) assert_equal(Decimal("10.00"), Decimal(self.nodes[2].z_gettotalbalance()['transparent'])) assert_equal(Decimal("10.00"), Decimal(self.nodes[3].z_gettotalbalance()['transparent'])) zaddr1 = self.nodes[0].z_getnewaddress('sapling') zaddr2 = self.nodes[0].z_getnewaddress('sapling') zaddr3 = self.nodes[0].z_getnewaddress('sapling') print("Filling mempool...") opid1 = self.nodes[1].z_sendmany(get_coinbase_address(self.nodes[1]), [{ "address": zaddr1, "amount": Decimal('9.999') }]) wait_and_assert_operationid_status(self.nodes[1], opid1) opid2 = self.nodes[2].z_sendmany(get_coinbase_address(self.nodes[2]), [{ "address": zaddr2, "amount": Decimal('9.999') }]) wait_and_assert_operationid_status(self.nodes[2], opid2) self.sync_all() self.check_mempool_sizes(2) print("Adding one more transaction...") opid3 = self.nodes[3].z_sendmany(get_coinbase_address(self.nodes[3]), [{ "address": zaddr3, "amount": Decimal('9.999') }]) wait_and_assert_operationid_status(self.nodes[3], opid3) # The mempools are no longer guaranteed to be in a consistent state, so we cannot sync sleep(5) mempool_node3 = self.nodes[3].getrawmempool() assert_equal(3, len(mempool_node3), "node {}".format(3)) print("Checking mempool size...") # Due to the size limit, there should only be 2 transactions in the mempool self.check_mempool_sizes(2, False) self.nodes[3].generate(1) self.sync_all() # The mempool sizes should be reset print("Checking mempool size reset after block mined...") self.check_mempool_sizes(0) zaddr4 = self.nodes[0].z_getnewaddress('sapling') opid4 = self.nodes[0].z_sendmany(zaddr1, [{ "address": zaddr4, "amount": Decimal('9.998') }]) wait_and_assert_operationid_status(self.nodes[0], opid4) opid5 = self.nodes[0].z_sendmany(zaddr2, [{ "address": zaddr4, "amount": Decimal('9.998') }]) wait_and_assert_operationid_status(self.nodes[0], opid5) self.sync_all() self.check_mempool_sizes(2) # Make sure the transactions are mined without error self.nodes[3].generate(1) self.sync_all()
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): print "Mining blocks..." self.nodes[0].generate(100) self.sync_all() self.nodes[1].generate(101) self.sync_all() mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # 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('sprout'), "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('sprout'), "amount": Decimal('18') }) recipients.append({ "address": self.nodes[2].z_getnewaddress('sprout'), "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): # 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())
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'])
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): 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 run_test(self): # Current height = 200 assert_equal(200, self.nodes[0].getblockcount()) sproutzaddr = self.nodes[0].z_getnewaddress('sprout') 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 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) receive_amount_10 = Decimal('97.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 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]) # 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): # Generate blocks up to Heartwood activation logging.info( "Generating initial blocks. Current height is 200, advance to 210 (activate Heartwood but not Canopy)" ) self.nodes[0].generate(10) self.sync_all() # Shield coinbase to Sprout on node 0. Should pass sprout_addr = self.nodes[0].z_getnewaddress('sprout') myopid = self.nodes[0].z_shieldcoinbase( get_coinbase_address(self.nodes[0]), sprout_addr, 0)['opid'] wait_and_assert_operationid_status(self.nodes[0], myopid) print( "taddr -> Sprout z_shieldcoinbase tx accepted before Canopy on node 0" ) self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(sprout_addr), Decimal('10')) # Fund taddr_0 from shielded coinbase on node 0 taddr_0 = self.nodes[0].getnewaddress() for _ in range(3): recipients = [{"address": taddr_0, "amount": Decimal('1')}] myopid = self.nodes[0].z_sendmany(sprout_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Create taddr -> Sprout transaction and mine on node 0 before it is Canopy-aware. Should pass sendmany_tx_0 = self.nodes[0].z_sendmany( taddr_0, [{ "address": self.nodes[1].z_getnewaddress('sprout'), "amount": 1 }]) wait_and_assert_operationid_status(self.nodes[0], sendmany_tx_0) print("taddr -> Sprout z_sendmany tx accepted before Canopy on node 0") self.nodes[0].generate(1) self.sync_all() # Create mergetoaddress taddr -> Sprout transaction and mine on node 0 before it is Canopy-aware. Should pass merge_tx_0 = self.nodes[0].z_mergetoaddress( ["ANY_TADDR"], self.nodes[1].z_getnewaddress('sprout')) wait_and_assert_operationid_status(self.nodes[0], merge_tx_0['opid']) print( "taddr -> Sprout z_mergetoaddress tx accepted before Canopy on node 0" ) # Mine to one block before Canopy activation on node 0; adding value # to the Sprout pool will fail now since the transaction must be # included in the next (or later) block, after Canopy has activated. self.nodes[0].generate(4) self.sync_all() # Shield coinbase to Sprout on node 0. Should fail errorString = '' try: sprout_addr = self.nodes[0].z_getnewaddress('sprout') self.nodes[0].z_shieldcoinbase(get_coinbase_address(self.nodes[0]), sprout_addr, 0) except JSONRPCException as e: errorString = e.error['message'] assert ("Sprout shielding is not supported after Canopy" in errorString) print( "taddr -> Sprout z_shieldcoinbase tx rejected at Canopy activation on node 0" ) # Create taddr -> Sprout z_sendmany transaction on node 0. Should fail errorString = '' try: sprout_addr = self.nodes[1].z_getnewaddress('sprout') self.nodes[0].z_sendmany(taddr_0, [{ "address": sprout_addr, "amount": 1 }]) except JSONRPCException as e: errorString = e.error['message'] assert ("Sprout shielding is not supported after Canopy" in errorString) print( "taddr -> Sprout z_sendmany tx rejected at Canopy activation on node 0" ) # Create z_mergetoaddress [taddr, Sprout] -> Sprout transaction on node 0. Should fail errorString = '' try: self.nodes[0].z_mergetoaddress( ["ANY_TADDR", "ANY_SPROUT"], self.nodes[1].z_getnewaddress('sprout')) except JSONRPCException as e: errorString = e.error['message'] assert ("Sprout shielding is not supported after Canopy" in errorString) print( "[taddr, Sprout] -> Sprout z_mergetoaddress tx rejected at Canopy activation on node 0" ) # Create z_mergetoaddress Sprout -> Sprout transaction on node 0. Should pass merge_tx_1 = self.nodes[0].z_mergetoaddress( ["ANY_SPROUT"], self.nodes[1].z_getnewaddress('sprout')) wait_and_assert_operationid_status(self.nodes[0], merge_tx_1['opid']) print( "Sprout -> Sprout z_mergetoaddress tx accepted at Canopy activation on node 0" ) self.nodes[0].generate(1) self.sync_all() # Shield coinbase to Sapling on node 0. Should pass sapling_addr = self.nodes[0].z_getnewaddress('sapling') myopid = self.nodes[0].z_shieldcoinbase( get_coinbase_address(self.nodes[0]), sapling_addr, 0)['opid'] wait_and_assert_operationid_status(self.nodes[0], myopid) print( "taddr -> Sapling z_shieldcoinbase tx accepted after Canopy on node 0" )
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)
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 = get_coinbase_address(self.nodes[0]) 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'))
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): # Activate Nu5 self.sync_all() self.nodes[0].generate(1) self.sync_all() account0 = self.nodes[0].z_getnewaccount()['account'] ua0_sapling = self.nodes[0].z_getaddressforaccount(account0, ['sapling'])['address'] ua0_orchard = self.nodes[0].z_getaddressforaccount(account0, ['orchard'])['address'] account1 = self.nodes[1].z_getnewaccount()['account'] ua1_sapling = self.nodes[1].z_getaddressforaccount(account1, ['sapling'])['address'] ua1 = self.nodes[1].z_getaddressforaccount(account1)['address'] # Fund both of ua0_sapling and ua0_orchard recipients = [{'address': ua0_sapling, 'amount': Decimal('9.99999000')}] opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, DEFAULT_FEE, 'AllowRevealedSenders') wait_and_assert_operationid_status(self.nodes[0], opid) recipients = [{'address': ua0_orchard, 'amount': Decimal('9.99999000')}] opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, DEFAULT_FEE, 'AllowRevealedSenders') wait_and_assert_operationid_status(self.nodes[0], opid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal( {'pools': {'sapling': {'valueZat': 999999000}, 'orchard': {'valueZat': 999999000}}, 'minimum_confirmations': 1}, self.nodes[0].z_getbalanceforaccount(account0)) # Send both amounts to ua1 in fully-shielded transactions. This will result # in account1 having both Sapling and Orchard balances. recipients = [{'address': ua1_sapling, 'amount': 5}] opid = self.nodes[0].z_sendmany(ua0_sapling, recipients, 1, DEFAULT_FEE) txid_sapling = wait_and_assert_operationid_status(self.nodes[0], opid) recipients = [{'address': ua1, 'amount': 5}] opid = self.nodes[0].z_sendmany(ua0_orchard, recipients, 1, DEFAULT_FEE) txid_orchard = wait_and_assert_operationid_status(self.nodes[0], opid) assert_equal(set([txid_sapling, txid_orchard]), set(self.nodes[0].getrawmempool())) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal([], self.nodes[0].getrawmempool()) assert_equal(1, self.nodes[0].gettransaction(txid_orchard)['confirmations']) assert_equal(1, self.nodes[0].gettransaction(txid_sapling)['confirmations']) assert_equal( {'pools': {'sapling': {'valueZat': 500000000}, 'orchard': {'valueZat': 500000000}}, 'minimum_confirmations': 1}, self.nodes[1].z_getbalanceforaccount(account1)) # Now send sapling->sapling, generating change. recipients = [{'address': ua0_sapling, 'amount': Decimal('2.5')}] opid = self.nodes[1].z_sendmany(ua1_sapling, recipients, 1, 0) txid_sapling = wait_and_assert_operationid_status(self.nodes[1], opid) self.sync_all() self.nodes[1].generate(1) self.sync_all() # Since this is entirely sapling->sapling, change should be returned # to the Sapling pool. assert_equal( {'pools': {'sapling': {'valueZat': 250000000}, 'orchard': {'valueZat': 500000000}}, 'minimum_confirmations': 1}, self.nodes[1].z_getbalanceforaccount(account1)) # If we send from an unrestricted UA, change should still not cross # the pool boundary, since we can build a purely sapling->sapling tx. recipients = [{'address': ua0_sapling, 'amount': Decimal('1.25')}] opid = self.nodes[1].z_sendmany(ua1, recipients, 1, 0) txid_sapling = 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': 125000000}, 'orchard': {'valueZat': 500000000}}, 'minimum_confirmations': 1}, self.nodes[1].z_getbalanceforaccount(account1))