def run_test (self): # Test the check_node_log utility function string_to_find = "Pastel version" check_node_log(self, 1, string_to_find) # Node 1 was stopped to check the logs, need to be restarted self.nodes[1] = self.start_node_with(1, []) connect_nodes(self.nodes[1], 0) assert_raises(AssertionError, check_node_log, self, 1, "Will not be found") # Need to start node 1 before leaving the test self.nodes[1] = self.start_node_with(1, []) connect_nodes(self.nodes[1], 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 string_to_find = "CreateNewBlock(): tx " + mytxid + " appears to violate " + POOL_NAME.capitalize( ) + " turnstile" check_node_log(self, 0, string_to_find) # 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 string_to_find1 = "ConnectBlock(): turnstile violation in " + POOL_NAME.capitalize( ) + " shielded value pool" string_to_find2 = "InvalidChainFound: invalid block=" string_to_find3 = "ConnectTip(): ConnectBlock " + newhash + " failed" check_node_log(self, 0, string_to_find1, True) check_node_log(self, 0, string_to_find2, False) check_node_log(self, 0, string_to_find3, False) self.start_and_sync_node(0) assert_equal(newhash, self.nodes[0].getbestblockhash())
def run_test (self): print("Mining blocks...") self.nodes[0].generate(4) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[3].getbalance(), 0) check_value_pool(self.nodes[0], 'sprout', 0) check_value_pool(self.nodes[1], 'sprout', 0) check_value_pool(self.nodes[2], 'sprout', 0) check_value_pool(self.nodes[3], 'sprout', 0) # Send will fail because we are enforcing the consensus rule that # coinbase utxos can only be sent to a zaddr. errorString = "" try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Coinbase funds can only be sent to a zaddr" in errorString, True) # Prepare to send taddr->zaddr mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Node 3 will test that watch only address utxos are not selected self.nodes[3].importaddress(mytaddr) recipients= [{"address":myzaddr, "amount": Decimal('1')}] myopid = self.nodes[3].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "Insufficient funds, no UTXOs found for taddr from address.", 10) # This send will fail because our wallet does not allow any change when shielding a coinbase utxo, # as it's currently not possible to specify a change address in z_sendmany. recipients = [] recipients.append({"address":myzaddr, "amount":Decimal('1.23456789')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) error_result = wait_and_assert_operationid_status_result(self.nodes[0], myopid, "failed", ("Change 8.76533211 not allowed. " "When shielding coinbase funds, the wallet does not allow any change " "as there is currently no way to specify a change address in z_sendmany."), 10) # Test that the returned status object contains a params field with the operation's input parameters assert_equal(error_result["method"], "z_sendmany") params = error_result["params"] assert_equal(params["fee"], Decimal('0.0001')) # default assert_equal(params["minconf"], Decimal('1')) # default assert_equal(params["fromaddress"], mytaddr) assert_equal(params["amounts"][0]["address"], myzaddr) assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789')) # Add viewing key for myzaddr to Node 3 myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr) self.nodes[3].z_importviewingkey(myviewingkey, "no") # This send will succeed. We send two coinbase utxos totalling 20.0 less a fee of 0.00010000, with no change. shieldvalue = Decimal('20.0') - Decimal('0.0001') recipients = [] recipients.append({"address":myzaddr, "amount": shieldvalue}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() # Verify that z_listunspent can return a note that has zero confirmations results = self.nodes[0].z_listunspent() assert(len(results) == 0) results = self.nodes[0].z_listunspent(0) # set minconf to zero assert(len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 0) # Mine the tx self.nodes[1].generate(1) self.sync_all() # Verify that z_listunspent returns one note which has been confirmed results = self.nodes[0].z_listunspent() assert(len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 1) assert_equal(results[0]["spendable"], True) # Verify that z_listunspent returns note for watchonly address on node 3. results = self.nodes[3].z_listunspent(1, 999, True) assert(len(results) == 1) assert_equal(results[0]["address"], myzaddr) assert_equal(results[0]["amount"], shieldvalue) assert_equal(results[0]["confirmations"], 1) assert_equal(results[0]["spendable"], False) # Verify that z_listunspent returns error when address spending key from node 0 is not available in wallet of node 1. try: results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr]) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Invalid parameter, spending key for address does not belong to wallet" in errorString, True) # Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid initialized_line = check_node_log(self, 0, myopid + ": z_sendmany initialized", False) finished_line = check_node_log(self, 0, myopid + ": z_sendmany finished", False) assert(initialized_line < finished_line) # check balances (the z_sendmany consumes 3 coinbase utxos) resp = self.nodes[0].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), Decimal('20.0')) assert_equal(Decimal(resp["private"]), Decimal('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 as e: errorString = e.error['message'] assert_equal("Insufficient funds" in errorString, True) # z_sendmany will fail because of insufficient funds recipients = [] recipients.append({"address":self.nodes[1].getnewaddress(), "amount":Decimal('10000.0')}) myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001") myopid = self.nodes[0].z_sendmany(myzaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient shielded funds, have 9.9998, need 10000.0001") # Send will fail because of insufficient funds unless sender uses coinbase utxos try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr" in errorString, True) # Verify that mempools accept tx with joinsplits which have at least the default z_sendmany fee. # If this test passes, it confirms that issue #1851 has been resolved, where sending from # a zaddr to 1385 taddr recipients fails because the default fee was considered too low # given the tx size, resulting in mempool rejection. errorString = '' recipients = [] num_t_recipients = 2500 amount_per_recipient = Decimal('0.00000546') # dust threshold # Note that regtest chainparams does not require standard tx, so setting the amount to be # less than the dust threshold, e.g. 0.00000001 will not result in mempool rejection. start_time = timeit.default_timer() for i in range(0,num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({"address":newtaddr, "amount":amount_per_recipient}) elapsed = timeit.default_timer() - start_time print("...invoked getnewaddress() {} times in {} seconds".format(num_t_recipients, elapsed)) # Issue #2263 Workaround START # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process # loop above to create new addresses, that when z_sendmany is called with a large amount of # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP # connection into a good state to handle a large amount of data in recipients. self.nodes[0].getinfo() # Issue #2263 Workaround END myopid = self.nodes[0].z_sendmany(myzaddr, recipients) try: wait_and_assert_operationid_status(self.nodes[0], myopid) except JSONRPCException as e: print("JSONRPC error: "+e.error['message']) assert(False) except Exception as e: print("Unexpected exception caught during testing: ", e.error['message'], str(sys.exc_info()[0])) assert(False) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check balance node2balance = amount_per_recipient * num_t_recipients sproutvalue -= node2balance + Decimal('0.0001') assert_equal(self.nodes[2].getbalance(), node2balance) check_value_pool(self.nodes[0], 'sprout', sproutvalue) # Send will fail because fee is negative try: self.nodes[0].z_sendmany(myzaddr, recipients, 1, -1) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Amount out of range" in errorString, True) # Send will fail because fee is larger than MAX_MONEY try: self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('21000000.00000001')) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Amount out of range" in errorString, True) # Send will fail because fee is larger than sum of outputs try: self.nodes[0].z_sendmany(myzaddr, recipients, 1, (amount_per_recipient * num_t_recipients) + Decimal('0.00000001')) except JSONRPCException as e: errorString = e.error['message'] assert_equal("is greater than the sum of outputs" in errorString, True) # Send will succeed because the balance of non-coinbase utxos is 10.0 try: self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 9) except JSONRPCException: assert(False) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check balance node2balance = node2balance + 9 assert_equal(self.nodes[2].getbalance(), node2balance) # Check that chained joinsplits in a single tx are created successfully. recipients = [] num_recipients = 3 amount_per_recipient = Decimal('0.002') minconf = 1 send_amount = num_recipients * amount_per_recipient custom_fee = Decimal('0.00012345') zbalance = self.nodes[0].z_getbalance(myzaddr) for i in range(0,num_recipients): newzaddr = self.nodes[2].z_getnewaddress('sprout') recipients.append({"address":newzaddr, "amount":amount_per_recipient}) myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, custom_fee) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check balances and unspent notes resp = self.nodes[2].z_gettotalbalance() assert_equal(Decimal(resp["private"]), send_amount) notes = self.nodes[2].z_listunspent() sum_of_notes = sum([note["amount"] for note in notes]) assert_equal(Decimal(resp["private"]), sum_of_notes) resp = self.nodes[0].z_getbalance(myzaddr) assert_equal(Decimal(resp), zbalance - custom_fee - send_amount) sproutvalue -= custom_fee check_value_pool(self.nodes[0], 'sprout', sproutvalue) notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr]) sum_of_notes = sum([note["amount"] for note in notes]) assert_equal(Decimal(resp), sum_of_notes)
def run_test(self): # Generate a Sapling address for node 1 node1_zaddr = self.nodes[1].z_getnewaddress('sapling') self.nodes[1].stop() bitcoind_processes[1].wait() self.nodes[1] = self.start_node_with(1, [ "-mineraddress=%s" % node1_zaddr, ]) connect_nodes(self.nodes[1], 0) # Node 0 can mine blocks, because it is targeting a transparent address print("Mining block with node 0") self.nodes[0].generate(1) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 3802400) assert_equal(walletinfo['balance'], 0) # Node 1 cannot mine blocks, because it is targeting a Sapling address # but Heartwood is not yet active print("Attempting to mine block with node 1") assert_raises(JSONRPCException, self.nodes[1].generate, 1) assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 0) assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 0) # Stop node 1 and check logs to verify the block was rejected correctly string_to_find = "CheckTransaction(): coinbase has output descriptions" check_node_log(self, 1, string_to_find) # Restart node 1 self.nodes[1] = self.start_node_with( 1, ["-mineraddress=%s" % node1_zaddr]) connect_nodes(self.nodes[1], 0) # Activate Heartwood print("Activating Heartwood") self.nodes[0].generate(8) self.sync_all() # Node 1 can now mine blocks! print("Mining block with node 1") self.nodes[1].generate(1) self.sync_all() # Transparent coinbase outputs are subject to coinbase maturity assert_equal(self.nodes[0].getbalance(), Decimal('0')) assert_equal(self.nodes[0].z_gettotalbalance()['transparent'], '0.00') assert_equal(self.nodes[0].z_gettotalbalance()['private'], '0.00') assert_equal(self.nodes[0].z_gettotalbalance()['total'], '0.00') # Shielded coinbase outputs are not subject to coinbase maturity assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 97) assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 97) assert_equal(self.nodes[1].z_gettotalbalance()['private'], '97.00') assert_equal(self.nodes[1].z_gettotalbalance()['total'], '97.00') # Send from Sapling coinbase to Sapling address and transparent address # (to check that a non-empty vout is allowed when spending shielded # coinbase) print("Sending Sapling coinbase to Sapling address") node0_zaddr = self.nodes[0].z_getnewaddress('sapling') node0_taddr = self.nodes[0].getnewaddress() recipients = [] recipients.append({"address": node0_zaddr, "amount": Decimal('2')}) recipients.append({"address": node0_taddr, "amount": Decimal('2')}) myopid = self.nodes[1].z_sendmany(node1_zaddr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(node0_zaddr), 2) assert_equal(self.nodes[0].z_getbalance(node0_taddr), 2) assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 93)
def run_test(self): # Generate a Sapling address for node 1 node1_zaddr = self.nodes[1].z_getnewaddress('sapling') self.nodes[1].stop() bitcoind_processes[1].wait() self.nodes[1] = self.start_node_with(1, [ "-mineraddress=%s" % node1_zaddr, ]) connect_nodes(self.nodes[1], 0) # Node 0 can mine blocks, because it is targeting a transparent address print("Mining block with node 0") self.nodes[0].generate(1) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 5) assert_equal(walletinfo['balance'], 0) # Node 1 cannot mine blocks, because it is targeting a Sapling address # but Heartwood is not yet active print("Attempting to mine block with node 1") assert_raises(JSONRPCException, self.nodes[1].generate, 1) assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 0) assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 0) # Stop node 1 and check logs to verify the block was rejected correctly string_to_find = "CheckTransaction(): coinbase has output descriptions" check_node_log(self, 1, string_to_find) # Restart node 1 self.nodes[1] = self.start_node_with( 1, ["-mineraddress=%s" % node1_zaddr]) connect_nodes(self.nodes[1], 0) # Activate Heartwood print("Activating Heartwood") self.nodes[0].generate(8) self.sync_all() # Node 1 can now mine blocks! print("Mining block with node 1") self.nodes[1].generate(1) self.sync_all() # Transparent coinbase outputs are subject to coinbase maturity assert_equal(self.nodes[0].getbalance(), Decimal('0')) assert_equal(self.nodes[0].z_gettotalbalance()['transparent'], '0.00') assert_equal(self.nodes[0].z_gettotalbalance()['private'], '0.00') assert_equal(self.nodes[0].z_gettotalbalance()['total'], '0.00') # Shielded coinbase outputs are not subject to coinbase maturity assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 5) assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 5) assert_equal(self.nodes[1].z_gettotalbalance()['private'], '5.00') assert_equal(self.nodes[1].z_gettotalbalance()['total'], '5.00') # Send from Sapling coinbase to Sapling address and transparent address # (to check that a non-empty vout is allowed when spending shielded # coinbase) print("Sending Sapling coinbase to Sapling address") node0_zaddr = self.nodes[0].z_getnewaddress('sapling') node0_taddr = self.nodes[0].getnewaddress() recipients = [] recipients.append({"address": node0_zaddr, "amount": Decimal('2')}) recipients.append({"address": node0_taddr, "amount": Decimal('2')}) myopid = self.nodes[1].z_sendmany(node1_zaddr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].z_getbalance(node0_zaddr), 2) assert_equal(self.nodes[0].z_getbalance(node0_taddr), 2) assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 1) # Generate a Unified Address for node 1 self.nodes[1].z_getnewaccount() node1_addr0 = self.nodes[1].z_getaddressforaccount(0) assert_equal(node1_addr0['account'], 0) assert_equal(set(node1_addr0['receiver_types']), set(['p2pkh', 'sapling', 'orchard'])) node1_ua = node1_addr0['address'] # Set node 1's miner address to the UA self.nodes[1].stop() bitcoind_processes[1].wait() self.nodes[1] = self.start_node_with(1, [ "-mineraddress=%s" % node1_ua, ]) connect_nodes(self.nodes[1], 0) # The UA starts with zero balance. assert_equal(self.nodes[1].z_getbalanceforaccount(0)['pools'], {}) # Node 1 can mine blocks because the miner selects the Sapling receiver # of its UA. print("Mining block with node 1") self.nodes[1].generate(1) self.sync_all() # The UA balance should show that Sapling funds were received. assert_equal(self.nodes[1].z_getbalanceforaccount(0)['pools'], { 'sapling': { 'valueZat': 5 * COIN }, }) # Activate NU5 print("Activating NU5") self.nodes[0].generate(7) self.sync_all() # Now any block mined by node 1 should use the Orchard receiver of its UA. print("Mining block with node 1") self.nodes[1].generate(1) self.sync_all() assert_equal( self.nodes[1].z_getbalanceforaccount(0)['pools'], { 'sapling': { 'valueZat': 5 * COIN }, # 6.25 ZEC because the FR always ends when Canopy activates, and # regtest has no defined funding streams. 'orchard': { 'valueZat': 6.25 * COIN }, })