Beispiel #1
0
    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)
Beispiel #3
0
    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'))
Beispiel #4
0
    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']
Beispiel #6
0
    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"])
Beispiel #7
0
    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())
Beispiel #8
0
    def run_test (self):
        print "Mining blocks..."

        self.nodes[0].generate(100)
        self.sync_all()
        self.nodes[1].generate(101)
        self.sync_all()

        mytaddr = 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'))
Beispiel #9
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'))
Beispiel #10
0
    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)
Beispiel #11
0
    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"])
Beispiel #12
0
    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'))
Beispiel #13
0
    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
Beispiel #15
0
    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())
Beispiel #16
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('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())
Beispiel #17
0
    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()
Beispiel #21
0
    def run_test(self):
        print "Mining blocks..."

        self.nodes[0].generate(100)
        self.sync_all()
        self.nodes[1].generate(101)
        self.sync_all()

        mytaddr = 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'))
Beispiel #22
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())
Beispiel #23
0
    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'])
Beispiel #24
0
    def run_test(self):
        # Sanity-check the test harness
        assert_equal(self.nodes[0].getblockcount(), 200)

        # Activate Overwinter
        self.nodes[2].generate(1)
        self.sync_all()

        # Verify RPCs disallow Sapling value transfer if Sapling is not active
        tmp_taddr = get_coinbase_address(self.nodes[3])
        tmp_zaddr = self.nodes[3].z_getnewaddress('sapling')
        try:
            recipients = []
            recipients.append({"address": tmp_zaddr, "amount": Decimal('10')})
            self.nodes[3].z_sendmany(tmp_taddr, recipients, 1, 0)
            raise AssertionError("Should have thrown an exception")
        except JSONRPCException as e:
            assert_equal("Invalid parameter, Sapling has not activated", e.error['message'])
        try:
            recipients = []
            recipients.append({"address": tmp_taddr, "amount": Decimal('10')})
            self.nodes[3].z_sendmany(tmp_zaddr, recipients, 1, 0)
            raise AssertionError("Should have thrown an exception")
        except JSONRPCException as e:
            assert_equal("Invalid parameter, Sapling has not activated", e.error['message'])
        try:
            self.nodes[3].z_shieldcoinbase(tmp_taddr, tmp_zaddr)
            raise AssertionError("Should have thrown an exception")
        except JSONRPCException as e:
            assert_equal("Invalid parameter, Sapling has not activated", e.error['message'])

        # Verify z_mergetoaddress RPC does not support Sapling yet
        try:
            self.nodes[3].z_mergetoaddress([tmp_taddr], tmp_zaddr)
            raise AssertionError("Should have thrown an exception")
        except JSONRPCException as e:
            assert_equal("Invalid parameter, Sapling has not activated", e.error['message'])
        try:
            self.nodes[3].z_mergetoaddress([tmp_zaddr], tmp_taddr)
            raise AssertionError("Should have thrown an exception")
        except JSONRPCException as e:
            # When sending from a zaddr we check for sapling activation only if
            # we find notes belonging to that address. Since sapling is not active
            # none can be generated and none will be found.
            assert_equal("Could not find any funds to merge.", e.error['message'])

        # Activate Sapling
        self.nodes[2].generate(2)
        self.sync_all()

        taddr1 = self.nodes[1].getnewaddress()
        saplingAddr0 = self.nodes[0].z_getnewaddress('sapling')
        saplingAddr1 = self.nodes[1].z_getnewaddress('sapling')

        # Verify addresses
        assert(saplingAddr0 in self.nodes[0].z_listaddresses())
        assert(saplingAddr1 in self.nodes[1].z_listaddresses())
        assert_equal(self.nodes[0].z_validateaddress(saplingAddr0)['type'], 'sapling')
        assert_equal(self.nodes[0].z_validateaddress(saplingAddr1)['type'], 'sapling')

        # Verify balance
        assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('0'))
        assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0'))
        assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0'))

        # Node 0 shields some funds
        # taddr -> Sapling
        recipients = []
        recipients.append({"address": saplingAddr0, "amount": Decimal('10')})
        myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)

        self.sync_all()

        # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000)
        mempool = self.nodes[0].getrawmempool(True)
        assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16'))

        # Shield another coinbase UTXO
        myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)

        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()

        # Verify balance
        assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('20'))
        assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0'))
        assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0'))

        # Node 0 sends some shielded funds to node 1
        # Sapling -> Sapling
        #         -> Sapling (change)
        recipients = []
        recipients.append({"address": saplingAddr1, "amount": Decimal('15')})
        myopid = self.nodes[0].z_sendmany(saplingAddr0, recipients, 1, 0)
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)

        self.sync_all()

        # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000)
        mempool = self.nodes[0].getrawmempool(True)
        assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16'))

        self.nodes[2].generate(1)
        self.sync_all()

        # Verify balance
        assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('15'))
        assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0'))

        # Node 1 sends some shielded funds to node 0, as well as unshielding
        # Sapling -> Sapling
        #         -> taddr
        #         -> Sapling (change)
        recipients = []
        recipients.append({"address": saplingAddr0, "amount": Decimal('5')})
        recipients.append({"address": taddr1, "amount": Decimal('5')})
        myopid = self.nodes[1].z_sendmany(saplingAddr1, recipients, 1, 0)
        mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid)

        self.sync_all()

        # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000)
        mempool = self.nodes[1].getrawmempool(True)
        assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16'))

        self.nodes[2].generate(1)
        self.sync_all()

        # Verify balance
        assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('10'))
        assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('5'))

        # Verify existence of Sapling related JSON fields
        resp = self.nodes[0].getrawtransaction(mytxid, 1)
        assert_equal(resp['valueBalance'], Decimal('5'))
        assert(len(resp['vShieldedSpend']) == 1)
        assert(len(resp['vShieldedOutput']) == 2)
        assert('bindingSig' in resp)
        shieldedSpend = resp['vShieldedSpend'][0]
        assert('cv' in shieldedSpend)
        assert('anchor' in shieldedSpend)
        assert('nullifier' in shieldedSpend)
        assert('rk' in shieldedSpend)
        assert('proof' in shieldedSpend)
        assert('spendAuthSig' in shieldedSpend)
        shieldedOutput = resp['vShieldedOutput'][0]
        assert('cv' in shieldedOutput)
        assert('cmu' in shieldedOutput)
        assert('ephemeralKey' in shieldedOutput)
        assert('encCiphertext' in shieldedOutput)
        assert('outCiphertext' in shieldedOutput)
        assert('proof' in shieldedOutput)

        # Verify importing a spending key will update the nullifiers and witnesses correctly
        sk0 = self.nodes[0].z_exportkey(saplingAddr0)
        self.nodes[2].z_importkey(sk0, "yes")
        assert_equal(self.nodes[2].z_getbalance(saplingAddr0), Decimal('10'))
        sk1 = self.nodes[1].z_exportkey(saplingAddr1)
        self.nodes[2].z_importkey(sk1, "yes")
        assert_equal(self.nodes[2].z_getbalance(saplingAddr1), Decimal('5'))

        # Make sure we get a useful error when trying to send to both sprout and sapling
        node4_sproutaddr = self.nodes[3].z_getnewaddress('sprout')
        node4_saplingaddr = self.nodes[3].z_getnewaddress('sapling')
        try:
            self.nodes[1].z_sendmany(
                taddr1,
                [{'address': node4_sproutaddr, 'amount': 2.5}, {'address': node4_saplingaddr, 'amount': 2.4999}],
                1, 0.0001
            )
            raise AssertionError("Should have thrown an exception")
        except JSONRPCException as e:
            assert_equal("Cannot send to both Sprout and Sapling addresses using z_sendmany", e.error['message'])
    def run_test(self):
        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)
Beispiel #26
0
    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"
        )
Beispiel #28
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)
Beispiel #29
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'))
Beispiel #30
0
    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"])
Beispiel #31
0
    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))