def z_send(from_node, from_addr, to_addr, amount):
     global fee
     opid = from_node.z_sendmany(from_addr,
         [{"address": to_addr, "amount": Decimal(amount)}], 1, fee)
     wait_and_assert_operationid_status(from_node, opid)
     self.sync_all()
     miner.generate(1)
     self.sync_all()
    def run_test(self):
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress()
        zaddr2 = self.nodes[1].z_getnewaddress()

        self.nodes[0].sendtoaddress(taddr, Decimal('1.0'))
        self.generate_and_sync()

        # Send 1 ZEC to a zaddr
        wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1.0, 'memo': 'c0ffee01'}], 1, 0))
        self.generate_and_sync()

        # Check that we have received 1 note which is not change
        receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        listunspent = self.nodes[1].z_listunspent()
        assert_equal(1, len(receivedbyaddress), "Should have received 1 note")
        assert_false(receivedbyaddress[0]['change'], "Note should not be change")
        assert_equal(1, len(listunspent), "Should have 1 unspent note")
        assert_false(listunspent[0]['change'], "Unspent note should not be change")

        # Generate some change
        wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{'address': zaddr2, 'amount': 0.6, 'memo': 'c0ffee02'}], 1, 0))
        self.generate_and_sync()

        # Check zaddr1 received
        sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr1, 0), key = lambda received: received['amount'])
        assert_equal(2, len(sortedreceived1), "zaddr1 Should have received 2 notes")
        assert_equal(Decimal('0.4'), sortedreceived1[0]['amount'])
        assert_true(sortedreceived1[0]['change'], "Note valued at 0.4 should be change")
        assert_equal(Decimal('1.0'), sortedreceived1[1]['amount'])
        assert_false(sortedreceived1[1]['change'], "Note valued at 1.0 should not be change")
        # Check zaddr2 received
        sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr2, 0), key = lambda received: received['amount'])
        assert_equal(1, len(sortedreceived2), "zaddr2 Should have received 1 notes")
        assert_equal(Decimal('0.6'), sortedreceived2[0]['amount'])
        assert_false(sortedreceived2[0]['change'], "Note valued at 0.6 should not be change")
        # Check unspent
        sortedunspent = sorted(self.nodes[1].z_listunspent(), key = lambda received: received['amount'])
        assert_equal(2, len(sortedunspent), "Should have 2 unspent notes")
        assert_equal(Decimal('0.4'), sortedunspent[0]['amount'])
        assert_true(sortedunspent[0]['change'], "Unspent note valued at 0.4 should be change")
        assert_equal(Decimal('0.6'), sortedunspent[1]['amount'])
        assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change")

        # Give node 0 a viewing key
        viewing_key = self.nodes[1].z_exportviewingkey(zaddr1)
        self.nodes[0].z_importviewingkey(viewing_key)
        received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(received_node0))
        unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True)
        assert_equal(2, len(unspent_node0))
        # node 0 only has a viewing key so does not see the change field
        assert_false('change' in received_node0[0])
        assert_false('change' in received_node0[1])
        assert_false('change' in unspent_node0[0])
        assert_false('change' in unspent_node0[1])
Exemple #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'))
    def run_test (self):
        print "Mining blocks..."

        self.nodes[0].generate(1)
        do_not_shield_taddr = self.nodes[0].getnewaddress()

        self.nodes[0].generate(4)
        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 50)
        assert_equal(walletinfo['balance'], 0)
        self.sync_all()
        self.nodes[2].generate(1)
        self.nodes[2].getnewaddress()
        self.nodes[2].generate(1)
        self.nodes[2].getnewaddress()
        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[1].generate(101)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), 50)
        assert_equal(self.nodes[1].getbalance(), 10)
        assert_equal(self.nodes[2].getbalance(), 30)

        # Shield the coinbase
        myzaddr = self.nodes[0].z_getnewaddress()
        result = self.nodes[0].z_shieldcoinbase("*", myzaddr, 0)
        wait_and_assert_operationid_status(self.nodes[0], result['opid'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Prepare some UTXOs and notes for merging
        mytaddr = self.nodes[0].getnewaddress()
        mytaddr2 = self.nodes[0].getnewaddress()
        mytaddr3 = self.nodes[0].getnewaddress()
        result = self.nodes[0].z_sendmany(myzaddr, [
            {'address': do_not_shield_taddr, 'amount': 10},
            {'address': mytaddr, 'amount': 10},
            {'address': mytaddr2, 'amount': 10},
            {'address': mytaddr3, 'amount': 10},
            ], 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], result)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Merging will fail because from arguments need to be in an array
        try:
            self.nodes[0].z_mergetoaddress("*", myzaddr)
            assert(False)
        except JSONRPCException,e:
            errorString = e.error['message']
    def run_test(self):
        self.nodes[0].generate(1)
        self.sync_all()
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress('sprout')

        self.nodes[0].sendtoaddress(taddr, 2.0)
        self.nodes[0].generate(1)
        self.sync_all()

        # Create and sign Overwinter transaction.
        # If the incorrect consensus branch id is selected, there will be a signing error. 
        opid = self.nodes[1].z_sendmany(taddr,
            [{'address': zaddr1, 'amount': 1}])
        wait_and_assert_operationid_status(self.nodes[1], opid)
    def run_test(self):
        self.nodes[1].generate(100)
        self.sync_all()

        # Mine 97 blocks. After this, nodes[1] blocks
        # 1 to 97 are spend-able.
        self.nodes[0].generate(97)
        self.sync_all()

        # Shield some ZEC
        node1_taddr = get_coinbase_address(self.nodes[1])
        node0_zaddr = self.nodes[0].z_getnewaddress('sprout')
        recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}]
        myopid = self.nodes[1].z_sendmany(node1_taddr, recipients, 1, Decimal('0'))
        print wait_and_assert_operationid_status(self.nodes[1], myopid)
        self.sync_all()

        # Mempool checks for activation of upgrade Y at height H on base X
        def nu_activation_checks():
            # Mine block H - 2. After this, the mempool expects
            # block H - 1, which is the last X block.
            self.nodes[0].generate(1)
            self.sync_all()

            # Mempool should be empty.
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Check node 0 shielded balance
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))

            # Fill the mempool with twice as many transactions as can fit into blocks
            node0_taddr = self.nodes[0].getnewaddress()
            x_txids = []
            info = self.nodes[0].getblockchaininfo()
            chaintip_branchid = info["consensus"]["chaintip"]
            while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000:
                try:
                    x_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')))
                    assert_equal(chaintip_branchid, "00000000")
                except JSONRPCException:
                    # This fails due to expiring soon threshold, which applies from Overwinter onwards.
                    assert_equal(info["upgrades"][chaintip_branchid]["name"], "Overwinter")
                    break
            self.sync_all()

            # Spends should be in the mempool
            x_mempool = set(self.nodes[0].getrawmempool())
            assert_equal(x_mempool, set(x_txids))

            # Mine block H - 1. After this, the mempool expects
            # block H, which is the first Y block.
            self.nodes[0].generate(1)
            self.sync_all()

            # mempool should be empty.
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # When transitioning from Sprout to Overwinter, where expiring soon threshold does not apply:
            # Block H - 1 should contain a subset of the original mempool
            # (with all other transactions having been dropped)
            block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx']
            if chaintip_branchid is "00000000":
                assert(len(block_txids) < len(x_txids))
                for txid in block_txids[1:]: # Exclude coinbase
                    assert(txid in x_txids)

            # Create some transparent Y transactions
            y_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)]
            self.sync_all()

            # Create a shielded Y transaction
            recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}]
            myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0'))
            shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)
            assert(shielded != None)
            y_txids.append(shielded)
            self.sync_all()

            # Spends should be in the mempool
            assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids))

            # Node 0 note should be unspendable
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0'))

            # Invalidate block H - 1.
            block_hm1 = self.nodes[0].getbestblockhash()
            self.nodes[0].invalidateblock(block_hm1)

            # BUG: Ideally, the mempool should now only contain the transactions
            # that were in block H - 1, the Y transactions having been dropped.
            # However, because chainActive is not updated until after the transactions
            # in the disconnected block have been re-added to the mempool, the height
            # seen by AcceptToMemoryPool is one greater than it should be. This causes
            # the block H - 1 transactions to be validated against the Y rules,
            # and rejected because they (obviously) fail.
            #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:]))
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Node 0 note should be spendable again
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))

            # Reconsider block H - 1.
            self.nodes[0].reconsiderblock(block_hm1)

            # Mine blocks on node 1, so that the Y transactions in its mempool
            # will be cleared.
            self.nodes[1].generate(6)
            self.sync_all()

        print('Testing Sprout -> Overwinter activation boundary')
        # Current height = 197
        nu_activation_checks()
        # Current height = 205

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

        print('Testing Overwinter -> Sapling activation boundary')
        # Current height = 207
        nu_activation_checks()
Exemple #7
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)
Exemple #8
0
        errorString = ""
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999)
        except JSONRPCException, e:
            errorString = e.error['message']
        assert_equal("Insufficient funds" in errorString, True)

        # z_sendmany will fail because of insufficient funds
        recipients = []
        recipients.append({
            "address": self.nodes[1].getnewaddress(),
            "amount": Decimal('10000.0')
        })
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(
            self.nodes[0], myopid, "failed",
            "Insufficient transparent funds, have 10.00, need 10000.0001")
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
        wait_and_assert_operationid_status(
            self.nodes[0], myopid, "failed",
            "Insufficient shielded funds, have 9.9998, need 10000.0001")

        # Send will fail because of insufficient funds unless sender uses coinbase utxos
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21)
        except JSONRPCException, e:
            errorString = e.error['message']
        assert_equal(
            "Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr"
            in errorString, True)
Exemple #9
0
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(102)
        self.sync_all()

        # Send some ZEL to Sprout/Sapling addresses
        coinbase_addr = get_coinbase_address(self.nodes[0])
        sproutAddr = self.nodes[0].z_getnewaddress('sprout')
        saplingAddr = self.nodes[0].z_getnewaddress('sapling')
        t_addr = self.nodes[1].getnewaddress()

        opid = self.nodes[0].z_sendmany(coinbase_addr, [{
            "address": sproutAddr,
            "amount": Decimal('10')
        }], 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], opid)
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10'))
        assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0'))
        assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]),
                     Decimal('0'))
        # Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sprout Notes
        assert_mergetoaddress_exception(
            "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress",
            lambda: self.nodes[0].z_mergetoaddress(
                ["ANY_SPROUT", "ANY_SAPLING"], t_addr))
        opid = self.nodes[0].z_sendmany(coinbase_addr, [{
            "address": saplingAddr,
            "amount": Decimal('10')
        }], 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], opid)
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]),
                     Decimal('0'))

        # Merge Sprout -> taddr
        result = self.nodes[0].z_mergetoaddress(["ANY_SPROUT"], t_addr, 0)
        wait_and_assert_operationid_status(self.nodes[0], result['opid'])
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0'))
        assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('10'))
        assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]),
                     Decimal('10'))

        # Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sapling Notes
        assert_mergetoaddress_exception(
            "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress",
            lambda: self.nodes[0].z_mergetoaddress(
                ["ANY_SPROUT", "ANY_SAPLING"], t_addr))
        # Merge Sapling -> taddr
        result = self.nodes[0].z_mergetoaddress(["ANY_SAPLING"], t_addr, 0)
        wait_and_assert_operationid_status(self.nodes[0], result['opid'])
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0'))
        assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0'))
        assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]),
                     Decimal('20'))
    def run_test(self, test):
        print "Mining blocks..."

        test.nodes[0].generate(1)
        do_not_shield_taddr = test.nodes[0].getnewaddress()

        test.nodes[0].generate(4)
        walletinfo = test.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 50)
        assert_equal(walletinfo['balance'], 0)
        test.sync_all()
        test.nodes[2].generate(1)
        test.nodes[2].getnewaddress()
        test.nodes[2].generate(1)
        test.nodes[2].getnewaddress()
        test.nodes[2].generate(1)
        test.sync_all()
        test.nodes[1].generate(101)
        test.sync_all()
        assert_equal(test.nodes[0].getbalance(), 50)
        assert_equal(test.nodes[1].getbalance(), 10)
        assert_equal(test.nodes[2].getbalance(), 30)

        # Shield the coinbase
        myzaddr = test.nodes[0].z_getnewaddress(self.addr_type)
        result = test.nodes[0].z_shieldcoinbase("*", myzaddr, 0)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Prepare some UTXOs and notes for merging
        mytaddr = test.nodes[0].getnewaddress()
        mytaddr2 = test.nodes[0].getnewaddress()
        mytaddr3 = test.nodes[0].getnewaddress()
        result = test.nodes[0].z_sendmany(myzaddr, [
            {'address': do_not_shield_taddr, 'amount': 10},
            {'address': mytaddr, 'amount': 10},
            {'address': mytaddr2, 'amount': 10},
            {'address': mytaddr3, 'amount': 10},
            ], 1, 0)
        wait_and_assert_operationid_status(test.nodes[0], result)
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Merging will fail because from arguments need to be in an array
        assert_mergetoaddress_exception(
            "JSON value is not an array as expected",
            lambda: test.nodes[0].z_mergetoaddress("notanarray", myzaddr))

        # Merging will fail when trying to spend from watch-only address
        test.nodes[2].importaddress(mytaddr)
        assert_mergetoaddress_exception(
            "Could not find any funds to merge.",
            lambda: test.nodes[2].z_mergetoaddress([mytaddr], myzaddr))

        # Merging will fail because fee is negative
        assert_mergetoaddress_exception(
            "Amount out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, -1))

        # Merging will fail because fee is larger than MAX_MONEY
        assert_mergetoaddress_exception(
            "Amount out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('21000000.00000001')))

        # Merging will fail because fee is larger than sum of UTXOs
        assert_mergetoaddress_exception(
            "Insufficient funds, have 50.00, which is less than miners fee 999.00",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 999))

        # Merging will fail because transparent limit parameter must be at least 0
        assert_mergetoaddress_exception(
            "Limit on maximum number of UTXOs cannot be negative",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), -1))

        # Merging will fail because transparent limit parameter is absurdly large
        assert_mergetoaddress_exception(
            "JSON integer out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 99999999999999))

        # Merging will fail because shielded limit parameter must be at least 0
        assert_mergetoaddress_exception(
            "Limit on maximum number of notes cannot be negative",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, -1))

        # Merging will fail because shielded limit parameter is absurdly large
        assert_mergetoaddress_exception(
            "JSON integer out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, 99999999999999))

        # Merging will fail for this specific case where it would spend a fee and do nothing
        assert_mergetoaddress_exception(
            "Destination address is also the only source address, and all its funds are already merged.",
            lambda: test.nodes[0].z_mergetoaddress([mytaddr], mytaddr))

        # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000
        result = test.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone
        assert_equal(test.nodes[0].getbalance(), 10)
        assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0'))
        assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000'))
        assert_equal(test.nodes[1].getbalance(), 40)
        assert_equal(test.nodes[2].getbalance(), 30)

        # Shield all notes to another z-addr
        myzaddr2 = test.nodes[0].z_getnewaddress(self.addr_type)
        result = test.nodes[0].z_mergetoaddress(self.any_zaddr, myzaddr2, 0)
        assert_equal(result["mergingUTXOs"], Decimal('0'))
        assert_equal(result["remainingUTXOs"], Decimal('0'))
        assert_equal(result["mergingNotes"], Decimal('2'))
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        blockhash = test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(len(test.nodes[0].getblock(blockhash[0])['tx']), 2)
        assert_equal(test.nodes[0].z_getbalance(myzaddr), 0)
        assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000'))

        # Shield coinbase UTXOs from any node 2 taddr, and set fee to 0
        result = test.nodes[2].z_shieldcoinbase("*", myzaddr, 0)
        wait_and_assert_operationid_status(test.nodes[2], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(test.nodes[0].getbalance(), 10)
        assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('30'))
        assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000'))
        assert_equal(test.nodes[1].getbalance(), 60)
        assert_equal(test.nodes[2].getbalance(), 0)

        # Merge all notes from node 0 into a node 0 taddr, and set fee to 0
        result = test.nodes[0].z_mergetoaddress(self.any_zaddr, mytaddr, 0)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(test.nodes[0].getbalance(), Decimal('79.99990000'))
        assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0'))
        assert_equal(test.nodes[0].z_getbalance(mytaddr), Decimal('69.99990000'))
        assert_equal(test.nodes[0].z_getbalance(myzaddr), 0)
        assert_equal(test.nodes[0].z_getbalance(myzaddr2), 0)
        assert_equal(test.nodes[1].getbalance(), 70)
        assert_equal(test.nodes[2].getbalance(), 0)

        # Merge all node 0 UTXOs together into a node 1 taddr, and set fee to 0
        test.nodes[1].getnewaddress()  # Ensure we have an empty address
        n1taddr = test.nodes[1].getnewaddress()
        result = test.nodes[0].z_mergetoaddress(["ANY_TADDR"], n1taddr, 0)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(test.nodes[0].getbalance(), 0)
        assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), 0)
        assert_equal(test.nodes[0].z_getbalance(mytaddr), 0)
        assert_equal(test.nodes[0].z_getbalance(myzaddr), 0)
        assert_equal(test.nodes[1].getbalance(), Decimal('159.99990000'))
        assert_equal(test.nodes[1].z_getbalance(n1taddr), Decimal('79.99990000'))
        assert_equal(test.nodes[2].getbalance(), 0)

        # Generate self.utxos_to_generate regular UTXOs on node 0, and 20 regular UTXOs on node 2
        mytaddr = test.nodes[0].getnewaddress()
        n2taddr = test.nodes[2].getnewaddress()
        test.nodes[1].generate(1000)
        test.sync_all()
        for i in range(self.utxos_to_generate):
            test.nodes[1].sendtoaddress(mytaddr, 1)
        for i in range(20):
            test.nodes[1].sendtoaddress(n2taddr, 1)
        test.nodes[1].generate(1)
        test.sync_all()

        # Merging the UTXOs will conditionally occur over two transactions, since max tx size is 100,000 bytes before Sapling and 2,000,000 after.
        # We don't verify mergingTransparentValue as UTXOs are not selected in any specific order, so value can change on each test run.
        # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of UTXOs.
        result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 99999)
        assert_equal(result["mergingUTXOs"], self.utxos_in_tx1)
        assert_equal(result["remainingUTXOs"], self.utxos_in_tx2)
        assert_equal(result["mergingNotes"], Decimal('0'))
        assert_equal(result["mergingShieldedValue"], Decimal('0'))
        assert_equal(result["remainingNotes"], Decimal('0'))
        assert_equal(result["remainingShieldedValue"], Decimal('0'))
        remainingTransparentValue = result["remainingTransparentValue"]
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])

        # For sapling we do not check that this occurs over two transactions because of the time that it would take
        if self.utxos_in_tx2 > 0:
            # Verify that UTXOs are locked (not available for selection) by queuing up another merging operation
            result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 0)
            assert_equal(result["mergingUTXOs"], self.utxos_in_tx2)
            assert_equal(result["mergingTransparentValue"], Decimal(remainingTransparentValue))
            assert_equal(result["remainingUTXOs"], Decimal('0'))
            assert_equal(result["remainingTransparentValue"], Decimal('0'))
            assert_equal(result["mergingNotes"], Decimal('0'))
            assert_equal(result["mergingShieldedValue"], Decimal('0'))
            assert_equal(result["remainingNotes"], Decimal('0'))
            assert_equal(result["remainingShieldedValue"], Decimal('0'))
            wait_and_assert_operationid_status(test.nodes[0], result['opid'])

        # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected.
        # So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated
        # which mines tx1 and tx2, all nodes will have an empty mempool which can then be synced.
        sync_blocks(test.nodes[:2])
        sync_mempools(test.nodes[:2])
        # Generate enough blocks to ensure all transactions are mined
        while test.nodes[1].getmempoolinfo()['size'] > 0:
            test.nodes[1].generate(1)
        test.sync_all()

        # Verify maximum number of UTXOs which node 2 can shield is limited by option -mempooltxinputlimit
        # This option is used when the limit parameter is set to 0.

        # -mempooltxinputlimit is not used after overwinter activation
        if self.test_mempooltxinputlimit:
            expected_to_merge = 7
            expected_remaining = 13
        else:
            expected_to_merge = 20
            expected_remaining = 0

        result = test.nodes[2].z_mergetoaddress([n2taddr], myzaddr, Decimal('0.0001'), 0)
        assert_equal(result["mergingUTXOs"], expected_to_merge)
        assert_equal(result["remainingUTXOs"], expected_remaining)
        assert_equal(result["mergingNotes"], Decimal('0'))
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[2], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Verify maximum number of UTXOs which node 0 can shield is set by default limit parameter of 50
        mytaddr = test.nodes[0].getnewaddress()
        for i in range(100):
            test.nodes[1].sendtoaddress(mytaddr, 1)
        test.nodes[1].generate(1)
        test.sync_all()
        result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001'))
        assert_equal(result["mergingUTXOs"], Decimal('50'))
        assert_equal(result["remainingUTXOs"], Decimal('50'))
        assert_equal(result["mergingNotes"], Decimal('0'))
        # Remaining notes are only counted if we are trying to merge any notes
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])

        # Verify maximum number of UTXOs which node 0 can shield can be set by the limit parameter
        result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001'), 33)
        assert_equal(result["mergingUTXOs"], Decimal('33'))
        assert_equal(result["remainingUTXOs"], Decimal('17'))
        assert_equal(result["mergingNotes"], Decimal('0'))
        # Remaining notes are only counted if we are trying to merge any notes
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit
        sync_blocks(test.nodes[:2])
        sync_mempools(test.nodes[:2])
        test.nodes[1].generate(1)
        test.sync_all()

        # Verify maximum number of notes which node 0 can shield can be set by the limit parameter
        # Also check that we can set off a second merge before the first one is complete

        # myzaddr will have 5 notes if testing before to Sapling activation and 4 otherwise
        num_notes = len(test.nodes[0].z_listunspent(0))
        result1 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2)
        result2 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2)

        # First merge should select from all notes
        assert_equal(result1["mergingUTXOs"], Decimal('0'))
        # Remaining UTXOs are only counted if we are trying to merge any UTXOs
        assert_equal(result1["remainingUTXOs"], Decimal('0'))
        assert_equal(result1["mergingNotes"], Decimal('2'))
        assert_equal(result1["remainingNotes"], num_notes - 2)

        # Second merge should ignore locked notes
        assert_equal(result2["mergingUTXOs"], Decimal('0'))
        assert_equal(result2["remainingUTXOs"], Decimal('0'))
        assert_equal(result2["mergingNotes"], Decimal('2'))
        assert_equal(result2["remainingNotes"], num_notes - 4)
        wait_and_assert_operationid_status(test.nodes[0], result1['opid'])
        wait_and_assert_operationid_status(test.nodes[0], result2['opid'])

        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Shield both UTXOs and notes to a z-addr
        result = test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 0, 10, 2)
        assert_equal(result["mergingUTXOs"], Decimal('10'))
        assert_equal(result["remainingUTXOs"], Decimal('7'))
        assert_equal(result["mergingNotes"], Decimal('2'))
        assert_equal(result["remainingNotes"], num_notes - 4)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit
        sync_blocks(test.nodes[:2])
        sync_mempools(test.nodes[:2])
        test.nodes[1].generate(1)
        test.sync_all()
Exemple #11
0
            errorString = e.error['message']
        assert_equal(
            "Limit on maximum number of utxos cannot be negative"
            in errorString, True)

        # Shielding will fail because limit parameter is absurdly large
        try:
            self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'),
                                           99999999999999)
        except JSONRPCException, e:
            errorString = e.error['message']
        assert_equal("JSON integer out of range" in errorString, True)

        # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000
        result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr)
        wait_and_assert_operationid_status(self.nodes[0], result['opid'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Confirm balances and that do_not_shield_taddr containing funds of 12.5 was left alone
        assert_equal(self.nodes[0].getbalance(), 12.5)
        assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr),
                     Decimal('12.5'))
        assert_equal(self.nodes[0].z_getbalance(myzaddr),
                     Decimal('49.99990000'))
        assert_equal(self.nodes[1].getbalance(), 25)
        assert_equal(self.nodes[2].getbalance(), 37.5)

        # Shield coinbase utxos from any node 2 taddr, and set fee to 0
        result = self.nodes[2].z_shieldcoinbase("*", myzaddr, 0)
Exemple #12
0
    def run_test (self):
        print "Mining blocks..."

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

        mytaddr = self.nodes[0].getnewaddress()     # where coins were mined
        myzaddr = self.nodes[0].z_getnewaddress()

        # Spend coinbase utxos to create three notes of 9.99990000 each
        recipients = []
        recipients.append({"address":myzaddr, "amount":Decimal('10.0') - Decimal('0.0001')})
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Check balance
        resp = self.nodes[0].z_getbalance(myzaddr)
        assert_equal(Decimal(resp), Decimal('9.9999') * 3 )

        # We want to test a real-world situation where during the time spent creating a transaction
        # with joinsplits, other transactions containing joinsplits have been mined into new blocks,
        # which result in the treestate changing whilst creating the transaction.

        # Tx 1 will change the treestate while Tx 2 containing chained joinsplits is still being generated
        recipients = []
        recipients.append({"address":self.nodes[2].z_getnewaddress(), "amount":Decimal('10.0') - Decimal('0.0001')})
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Tx 2 will consume all three notes, which must take at least two joinsplits.  This is regardless of
        # the z_sendmany implementation because there are only two inputs per joinsplit.
        recipients = []
        recipients.append({"address":self.nodes[2].z_getnewaddress(), "amount":Decimal('18')})
        recipients.append({"address":self.nodes[2].z_getnewaddress(), "amount":Decimal('11.9997') - Decimal('0.0001')})
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)

        # Wait for Tx 2 to begin executing...
        for x in xrange(1, 60):
            results = self.nodes[0].z_getoperationstatus([myopid])
            status = results[0]["status"]
            if status == "executing":
                break
            time.sleep(1)

        # Now mine Tx 1 which will change global treestate before Tx 2's second joinsplit begins processing
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Wait for Tx 2 to be created
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Note that a bug existed in v1.0.0-1.0.3 where Tx 2 creation would fail with an error:
        # "Witness for spendable note does not have same anchor as change input"

        # Check balance
        resp = self.nodes[0].z_getbalance(myzaddr)
        assert_equal(Decimal(resp), Decimal('0.0'))
Exemple #13
0
    def run_test(self):
        # z_sendmany is expected to fail if tx size breaks limit
        myzaddr = self.nodes[0].z_getnewaddress()

        recipients = []
        num_t_recipients = 1000
        num_z_recipients = 2100
        amount_per_recipient = Decimal('0.00000001')
        errorString = ''
        for i in range(0, num_t_recipients):
            newtaddr = self.nodes[2].getnewaddress()
            recipients.append({
                "address": newtaddr,
                "amount": amount_per_recipient
            })
        for i in range(0, num_z_recipients):
            newzaddr = self.nodes[2].z_getnewaddress()
            recipients.append({
                "address": newzaddr,
                "amount": amount_per_recipient
            })

        # Issue #2759 Workaround START
        # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process
        # loop above to create new addresses, that when z_sendmany is called with a large amount of
        # rpc data in recipients, the connection fails with a 'broken pipe' error.  Making a RPC call
        # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP
        # connection into a good state to handle a large amount of data in recipients.
        self.nodes[0].getinfo()
        # Issue #2759 Workaround END

        try:
            self.nodes[0].z_sendmany(myzaddr, recipients)
        except JSONRPCException as e:
            errorString = e.error['message']
        assert ("size of raw transaction would be larger than limit"
                in errorString)

        # add zaddr to node 2
        myzaddr = self.nodes[2].z_getnewaddress()

        # add taddr to node 2
        mytaddr = self.nodes[2].getnewaddress()

        # send from node 0 to node 2 taddr
        mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # send node 2 taddr to zaddr
        recipients = []
        recipients.append({"address": myzaddr, "amount": 7})
        opid = self.nodes[2].z_sendmany(mytaddr, recipients)
        mytxid = wait_and_assert_operationid_status(self.nodes[2], opid)

        self.sync_all()

        # check balances
        zsendmanynotevalue = Decimal('7.0')
        zsendmanyfee = DEFAULT_FEE
        node2utxobalance = Decimal(
            '260.00000000') - zsendmanynotevalue - zsendmanyfee

        # check shielded balance status with getwalletinfo
        wallet_info = self.nodes[2].getwalletinfo()
        assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]),
                     zsendmanynotevalue)
        assert_equal(Decimal(wallet_info["shielded_balance"]), Decimal('0.0'))

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

        assert_equal(self.nodes[2].getbalance(), node2utxobalance)
        assert_equal(self.nodes[2].getbalance("*"), node2utxobalance)

        # check zaddr balance with z_getbalance
        zbalance = zsendmanynotevalue
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zbalance)

        # check via z_gettotalbalance
        resp = self.nodes[2].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), node2utxobalance)
        assert_equal(Decimal(resp["private"]), zbalance)
        assert_equal(Decimal(resp["total"]), node2utxobalance + zbalance)

        # check confirmed shielded balance with getwalletinfo
        wallet_info = self.nodes[2].getwalletinfo()
        assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]),
                     Decimal('0.0'))
        assert_equal(Decimal(wallet_info["shielded_balance"]),
                     zsendmanynotevalue)

        # there should be at least one Sapling output
        mytxdetails = self.nodes[2].getrawtransaction(mytxid, 1)
        assert_greater_than(len(mytxdetails["vShieldedOutput"]), 0)
        # the Sapling output should take in all the public value
        assert_equal(mytxdetails["valueBalance"], -zsendmanynotevalue)

        # send from private note to node 0 and node 2
        node0balance = self.nodes[0].getbalance()
        # The following assertion fails nondeterministically
        # assert_equal(node0balance, Decimal('25.99798873'))
        node2balance = self.nodes[2].getbalance()
        # The following assertion might fail nondeterministically
        # assert_equal(node2balance, Decimal('16.99799000'))

        recipients = []
        recipients.append({
            "address": self.nodes[0].getnewaddress(),
            "amount": 1
        })
        recipients.append({
            "address": self.nodes[2].getnewaddress(),
            "amount": 1.0
        })

        opid = self.nodes[2].z_sendmany(myzaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[2], opid)
        zbalance -= Decimal('2.0') + zsendmanyfee

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

        node0balance += Decimal('11.0')
        node2balance += Decimal('1.0')
        assert_equal(Decimal(self.nodes[0].getbalance()), node0balance)
        assert_equal(Decimal(self.nodes[0].getbalance("*")), node0balance)
        assert_equal(Decimal(self.nodes[2].getbalance()), node2balance)
        assert_equal(Decimal(self.nodes[2].getbalance("*")), node2balance)

        # Get a new unified account on node 2 & generate a UA
        n0account0 = self.nodes[0].z_getnewaccount()['account']
        n0ua0 = self.nodes[0].z_getaddressforaccount(n0account0)['address']

        # Change went to a fresh address, so use `ANY_TADDR` which
        # should hold the rest of our transparent funds.
        source = 'ANY_TADDR'
        recipients = []
        recipients.append({"address": n0ua0, "amount": 10})

        # If we attempt to spend with the default privacy policy, z_sendmany
        # fails because it needs to spend transparent coins in a transaction
        # involving a Unified Address.
        revealed_senders_msg = 'This transaction requires selecting transparent coins, which is not enabled by default because it will publicly reveal transaction senders and amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedSenders` or weaker if you wish to allow this transaction to proceed anyway.'
        opid = self.nodes[2].z_sendmany(source, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[2], opid, 'failed',
                                           revealed_senders_msg)

        # We can't create a transaction with an unknown privacy policy.
        assert_raises_message(
            JSONRPCException, 'Unknown privacy policy name \'ZcashIsAwesome\'',
            self.nodes[2].z_sendmany, source, recipients, 1, 0,
            'ZcashIsAwesome')

        # If we set any policy that does not include AllowRevealedSenders,
        # z_sendmany also fails.
        for policy in [
                'FullPrivacy',
                'AllowRevealedAmounts',
                'AllowRevealedRecipients',
        ]:
            opid = self.nodes[2].z_sendmany(source, recipients, 1, 0, policy)
            wait_and_assert_operationid_status(self.nodes[2], opid, 'failed',
                                               revealed_senders_msg)

        # By setting the correct policy, we can create the transaction.
        opid = self.nodes[2].z_sendmany(source, recipients, 1, 0,
                                        'AllowRevealedSenders')
        wait_and_assert_operationid_status(self.nodes[2], opid)

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

        node2balance -= Decimal('10.0')
        node0balance += Decimal('10.0')
        assert_equal(Decimal(self.nodes[2].getbalance()), node2balance)
        assert_equal(Decimal(self.nodes[0].getbalance()), node0balance)
        self.check_balance(0, 0, n0ua0, {'sapling': 10})

        # Send some funds to a specific legacy taddr that we can spend from
        recipients = []
        recipients.append({"address": mytaddr, "amount": 5})

        # If we attempt to spend with the default privacy policy, z_sendmany
        # returns an error because it needs to create a transparent recipient in
        # a transaction involving a Unified Address.
        revealed_recipients_msg = "This transaction would have transparent recipients, which is not enabled by default because it will publicly reveal transaction recipients and amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedRecipients` or weaker if you wish to allow this transaction to proceed anyway."
        opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], opid, 'failed',
                                           revealed_recipients_msg)

        # If we set any policy that does not include AllowRevealedRecipients,
        # z_sendmany also returns an error.
        for policy in [
                'FullPrivacy',
                'AllowRevealedAmounts',
                'AllowRevealedSenders',
                'AllowLinkingAccountAddresses',
        ]:
            opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0, policy)
            wait_and_assert_operationid_status(self.nodes[0], opid, 'failed',
                                               revealed_recipients_msg)

        # By setting the correct policy, we can create the transaction.
        opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0,
                                        'AllowRevealedRecipients')
        wait_and_assert_operationid_status(self.nodes[0], opid)

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

        node2balance += Decimal('5.0')
        self.check_balance(0, 0, n0ua0, {'sapling': 5})
        assert_equal(Decimal(self.nodes[2].getbalance()), node2balance)

        # Send some funds to a legacy sapling address that we can spend from
        recipients = []
        recipients.append({"address": myzaddr, "amount": 3})
        opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], opid)

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

        zbalance += Decimal('3.0')
        self.check_balance(0, 0, n0ua0, {'sapling': 2})
        assert_equal(Decimal(self.nodes[2].z_getbalance(myzaddr)), zbalance)

        # Send funds back from the legacy taddr to the UA. This requires
        # AllowRevealedSenders, but we can also use any weaker policy that
        # includes it.
        recipients = []
        recipients.append({"address": n0ua0, "amount": 4})
        opid = self.nodes[2].z_sendmany(mytaddr, recipients, 1, 0,
                                        'AllowFullyTransparent')
        wait_and_assert_operationid_status(self.nodes[2], opid)

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

        node2balance -= Decimal('4.0')
        self.check_balance(0, 0, n0ua0, {'sapling': 6})
        assert_equal(Decimal(self.nodes[2].getbalance()), node2balance)

        # Send funds back from the legacy zaddr to the UA
        recipients = []
        recipients.append({"address": n0ua0, "amount": 2})
        opid = self.nodes[2].z_sendmany(myzaddr, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[2], opid)

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

        zbalance -= Decimal('2.0')
        self.check_balance(0, 0, n0ua0, {'sapling': 8})
        assert_equal(Decimal(self.nodes[2].z_getbalance(myzaddr)), zbalance)

        #
        # Test that z_sendmany avoids UA linkability unless we allow it.
        #

        # Generate a new account with two new addresses.
        n1account = self.nodes[1].z_getnewaccount()['account']
        n1ua0 = self.nodes[1].z_getaddressforaccount(n1account)['address']
        n1ua1 = self.nodes[1].z_getaddressforaccount(n1account)['address']

        # Send funds to the transparent receivers of both addresses.
        for ua in [n1ua0, n1ua1]:
            taddr = self.nodes[1].z_listunifiedreceivers(ua)['p2pkh']
            self.nodes[0].sendtoaddress(taddr, 2)

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

        # The account should see all funds.
        assert_equal(
            self.nodes[1].z_getbalanceforaccount(n1account)['pools'],
            {'transparent': {
                'valueZat': 4 * COIN
            }},
        )

        # The addresses should see only the transparent funds sent to them.
        assert_equal(self.nodes[1].z_getbalance(n1ua0), 2)
        assert_equal(self.nodes[1].z_getbalance(n1ua1), 2)

        # If we try to send 3 ZEC from n1ua0, it will fail with too-few funds.
        recipients = [{"address": n0ua0, "amount": 3}]
        linked_addrs_msg = 'Insufficient funds: have 2.00, need 3.00 (This transaction may require selecting transparent coins that were sent to multiple Unified Addresses, which is not enabled by default because it would create a public link between the transparent receivers of these addresses. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowLinkingAccountAddresses` or weaker if you wish to allow this transaction to proceed anyway.)'
        opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[1], opid, 'failed',
                                           linked_addrs_msg)

        # If we try it again with any policy that is too strong, it also fails.
        for policy in [
                'FullPrivacy',
                'AllowRevealedAmounts',
                'AllowRevealedRecipients',
                'AllowRevealedSenders',
                'AllowFullyTransparent',
        ]:
            opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, policy)
            wait_and_assert_operationid_status(self.nodes[1], opid, 'failed',
                                               linked_addrs_msg)

        # Once we provide a sufficiently-weak policy, the transaction succeeds.
        opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0,
                                        'AllowLinkingAccountAddresses')
        wait_and_assert_operationid_status(self.nodes[1], opid)

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

        # The account should see the remaining funds, and they should have been
        # sent to the Sapling change address (because NU5 is not active).
        assert_equal(
            self.nodes[1].z_getbalanceforaccount(n1account)['pools'],
            {'sapling': {
                'valueZat': 1 * COIN
            }},
        )

        # The addresses should both show the same balance, as they both show the
        # Sapling balance.
        assert_equal(self.nodes[1].z_getbalance(n1ua0), 1)
        assert_equal(self.nodes[1].z_getbalance(n1ua1), 1)

        #
        # Test NoPrivacy policy
        #

        # Send some legacy transparent funds to n1ua0, creating Sapling outputs.
        recipients = [{"address": n1ua0, "amount": 10}]
        # This requires the AllowRevealedSenders policy...
        opid = self.nodes[2].z_sendmany('ANY_TADDR', recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[2], opid, 'failed',
                                           revealed_senders_msg)
        # ... which we can always override with the NoPrivacy policy.
        opid = self.nodes[2].z_sendmany('ANY_TADDR', recipients, 1, 0,
                                        'NoPrivacy')
        wait_and_assert_operationid_status(self.nodes[2], opid)

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

        # Send some funds from node 1's account to a transparent address.
        recipients = [{"address": mytaddr, "amount": 5}]
        # This requires the AllowRevealedRecipients policy...
        opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[1], opid, 'failed',
                                           revealed_recipients_msg)
        # ... which we can always override with the NoPrivacy policy.
        opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'NoPrivacy')
        wait_and_assert_operationid_status(self.nodes[1], opid)

        # Activate NU5

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

        #
        # Test AllowRevealedAmounts policy
        #

        assert_equal(
            {
                'pools': {
                    'sapling': {
                        'valueZat': 600000000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[1].z_getbalanceforaccount(n1account))

        # Sending some funds to the Orchard pool in n0account0 ...
        n0ua1 = self.nodes[0].z_getaddressforaccount(n0account0,
                                                     ["orchard"])['address']
        recipients = [{"address": n0ua1, "amount": 6}]

        # Should fail under default and 'FullPrivacy' policies ...
        revealed_amounts_msg = 'Sending from the Sapling shielded pool to the Orchard shielded pool is not enabled by default because it will publicly reveal the transaction amount. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedAmounts` or weaker if you wish to allow this transaction to proceed anyway.'
        opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[1], opid, 'failed',
                                           revealed_amounts_msg)

        opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'FullPrivacy')
        wait_and_assert_operationid_status(self.nodes[1], opid, 'failed',
                                           revealed_amounts_msg)

        # Should succeed under 'AllowRevealedAmounts'
        opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0,
                                        'AllowRevealedAmounts')
        wait_and_assert_operationid_status(self.nodes[1], opid)

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

        assert_equal(
            {
                'pools': {
                    'sapling': {
                        'valueZat': 1100000000
                    },
                    'orchard': {
                        'valueZat': 600000000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[0].z_getbalanceforaccount(n0account0))

        # A total that requires selecting from both pools should fail under default and
        # FullPrivacy policies...

        recipients = [{"address": n1ua0, "amount": 15}]
        opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], opid, 'failed',
                                           revealed_amounts_msg)

        opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0, 'FullPrivacy')
        wait_and_assert_operationid_status(self.nodes[0], opid, 'failed',
                                           revealed_amounts_msg)

        # Should succeed under 'AllowRevealedAmounts'
        opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0,
                                        'AllowRevealedAmounts')
        wait_and_assert_operationid_status(self.nodes[0], opid)

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

        # All funds should be received to the Orchard pool
        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 1500000000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[1].z_getbalanceforaccount(n1account))

        # And all change should be optimistically shielded
        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 200000000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[0].z_getbalanceforaccount(n0account0))
Exemple #14
0
    def run_test(self, test):
        print "Mining blocks..."

        test.nodes[0].generate(1)
        do_not_shield_taddr = test.nodes[0].getnewaddress()

        test.nodes[0].generate(4)
        walletinfo = test.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 50)
        assert_equal(walletinfo['balance'], 0)
        test.sync_all()
        test.nodes[2].generate(1)
        test.nodes[2].getnewaddress()
        test.nodes[2].generate(1)
        test.nodes[2].getnewaddress()
        test.nodes[2].generate(1)
        test.sync_all()
        test.nodes[1].generate(101)
        test.sync_all()
        assert_equal(test.nodes[0].getbalance(), 50)
        assert_equal(test.nodes[1].getbalance(), 10)
        assert_equal(test.nodes[2].getbalance(), 30)

        # Shield the coinbase
        myzaddr = test.nodes[0].z_getnewaddress(self.addr_type)
        result = test.nodes[0].z_shieldcoinbase("*", myzaddr, 0)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Prepare some UTXOs and notes for merging
        mytaddr = test.nodes[0].getnewaddress()
        mytaddr2 = test.nodes[0].getnewaddress()
        mytaddr3 = test.nodes[0].getnewaddress()
        result = test.nodes[0].z_sendmany(myzaddr, [
            {'address': do_not_shield_taddr, 'amount': 10},
            {'address': mytaddr, 'amount': 10},
            {'address': mytaddr2, 'amount': 10},
            {'address': mytaddr3, 'amount': 10},
            ], 1, 0)
        wait_and_assert_operationid_status(test.nodes[0], result)
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Merging will fail because from arguments need to be in an array
        assert_mergetoaddress_exception(
            "JSON value is not an array as expected",
            lambda: test.nodes[0].z_mergetoaddress("notanarray", myzaddr))

        # Merging will fail when trying to spend from watch-only address
        test.nodes[2].importaddress(mytaddr)
        assert_mergetoaddress_exception(
            "Could not find any funds to merge.",
            lambda: test.nodes[2].z_mergetoaddress([mytaddr], myzaddr))

        # Merging will fail because fee is negative
        assert_mergetoaddress_exception(
            "Amount out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, -1))

        # Merging will fail because fee is larger than MAX_MONEY
        assert_mergetoaddress_exception(
            "Amount out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('21000000.00000001')))

        # Merging will fail because fee is larger than sum of UTXOs
        assert_mergetoaddress_exception(
            "Insufficient funds, have 50.00, which is less than miners fee 999.00",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 999))

        # Merging will fail because transparent limit parameter must be at least 0
        assert_mergetoaddress_exception(
            "Limit on maximum number of UTXOs cannot be negative",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), -1))

        # Merging will fail because transparent limit parameter is absurdly large
        assert_mergetoaddress_exception(
            "JSON integer out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 99999999999999))

        # Merging will fail because shielded limit parameter must be at least 0
        assert_mergetoaddress_exception(
            "Limit on maximum number of notes cannot be negative",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, -1))

        # Merging will fail because shielded limit parameter is absurdly large
        assert_mergetoaddress_exception(
            "JSON integer out of range",
            lambda: test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, Decimal('0.001'), 50, 99999999999999))

        # Merging will fail for this specific case where it would spend a fee and do nothing
        assert_mergetoaddress_exception(
            "Destination address is also the only source address, and all its funds are already merged.",
            lambda: test.nodes[0].z_mergetoaddress([mytaddr], mytaddr))

        # Merging will fail for this specific case where it would spend a fee and do nothing
        assert_mergetoaddress_exception(
            "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress",
            lambda: test.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], mytaddr))

        # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000
        result = test.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone
        assert_equal(test.nodes[0].getbalance(), 10)
        assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0'))
        assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000'))
        assert_equal(test.nodes[1].getbalance(), 40)
        assert_equal(test.nodes[2].getbalance(), 30)

        # Shield all notes to another z-addr
        myzaddr2 = test.nodes[0].z_getnewaddress(self.addr_type)
        result = test.nodes[0].z_mergetoaddress(self.any_zaddr, myzaddr2, 0)
        assert_equal(result["mergingUTXOs"], Decimal('0'))
        assert_equal(result["remainingUTXOs"], Decimal('0'))
        assert_equal(result["mergingNotes"], Decimal('2'))
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        blockhash = test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(len(test.nodes[0].getblock(blockhash[0])['tx']), 2)
        assert_equal(test.nodes[0].z_getbalance(myzaddr), 0)
        assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000'))

        # Shield coinbase UTXOs from any node 2 taddr, and set fee to 0
        result = test.nodes[2].z_shieldcoinbase("*", myzaddr, 0)
        wait_and_assert_operationid_status(test.nodes[2], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(test.nodes[0].getbalance(), 10)
        assert_equal(test.nodes[0].z_getbalance(myzaddr), Decimal('30'))
        assert_equal(test.nodes[0].z_getbalance(myzaddr2), Decimal('39.99990000'))
        assert_equal(test.nodes[1].getbalance(), 60)
        assert_equal(test.nodes[2].getbalance(), 0)

        # Merge all notes from node 0 into a node 0 taddr, and set fee to 0
        result = test.nodes[0].z_mergetoaddress(self.any_zaddr, mytaddr, 0)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(test.nodes[0].getbalance(), Decimal('79.99990000'))
        assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0'))
        assert_equal(test.nodes[0].z_getbalance(mytaddr), Decimal('69.99990000'))
        assert_equal(test.nodes[0].z_getbalance(myzaddr), 0)
        assert_equal(test.nodes[0].z_getbalance(myzaddr2), 0)
        assert_equal(test.nodes[1].getbalance(), 70)
        assert_equal(test.nodes[2].getbalance(), 0)

        # Merge all node 0 UTXOs together into a node 1 taddr, and set fee to 0
        test.nodes[1].getnewaddress()  # Ensure we have an empty address
        n1taddr = test.nodes[1].getnewaddress()
        result = test.nodes[0].z_mergetoaddress(["ANY_TADDR"], n1taddr, 0)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        assert_equal(test.nodes[0].getbalance(), 0)
        assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), 0)
        assert_equal(test.nodes[0].z_getbalance(mytaddr), 0)
        assert_equal(test.nodes[0].z_getbalance(myzaddr), 0)
        assert_equal(test.nodes[1].getbalance(), Decimal('159.99990000'))
        assert_equal(test.nodes[1].z_getbalance(n1taddr), Decimal('79.99990000'))
        assert_equal(test.nodes[2].getbalance(), 0)

        # Generate self.utxos_to_generate regular UTXOs on node 0, and 20 regular UTXOs on node 2
        mytaddr = test.nodes[0].getnewaddress()
        n2taddr = test.nodes[2].getnewaddress()
        test.nodes[1].generate(1000)
        test.sync_all()
        for i in range(self.utxos_to_generate):
            test.nodes[1].sendtoaddress(mytaddr, 1)
        for i in range(20):
            test.nodes[1].sendtoaddress(n2taddr, 1)
        test.nodes[1].generate(1)
        test.sync_all()

        # Merging the UTXOs will conditionally occur over two transactions, since max tx size is 100,000 bytes before Sapling and 2,000,000 after.
        # We don't verify mergingTransparentValue as UTXOs are not selected in any specific order, so value can change on each test run.
        # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of UTXOs.
        result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 99999)
        assert_equal(result["mergingUTXOs"], self.utxos_in_tx1)
        assert_equal(result["remainingUTXOs"], self.utxos_in_tx2)
        assert_equal(result["mergingNotes"], Decimal('0'))
        assert_equal(result["mergingShieldedValue"], Decimal('0'))
        assert_equal(result["remainingNotes"], Decimal('0'))
        assert_equal(result["remainingShieldedValue"], Decimal('0'))
        remainingTransparentValue = result["remainingTransparentValue"]
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])

        # For sapling we do not check that this occurs over two transactions because of the time that it would take
        if self.utxos_in_tx2 > 0:
            # Verify that UTXOs are locked (not available for selection) by queuing up another merging operation
            result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 0)
            assert_equal(result["mergingUTXOs"], self.utxos_in_tx2)
            assert_equal(result["mergingTransparentValue"], Decimal(remainingTransparentValue))
            assert_equal(result["remainingUTXOs"], Decimal('0'))
            assert_equal(result["remainingTransparentValue"], Decimal('0'))
            assert_equal(result["mergingNotes"], Decimal('0'))
            assert_equal(result["mergingShieldedValue"], Decimal('0'))
            assert_equal(result["remainingNotes"], Decimal('0'))
            assert_equal(result["remainingShieldedValue"], Decimal('0'))
            wait_and_assert_operationid_status(test.nodes[0], result['opid'])

        # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected.
        # So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated
        # which mines tx1 and tx2, all nodes will have an empty mempool which can then be synced.
        sync_blocks(test.nodes[:2])
        sync_mempools(test.nodes[:2])
        # Generate enough blocks to ensure all transactions are mined
        while test.nodes[1].getmempoolinfo()['size'] > 0:
            test.nodes[1].generate(1)
        test.sync_all()

        # Verify maximum number of UTXOs which node 2 can shield is limited by option -mempooltxinputlimit
        # This option is used when the limit parameter is set to 0.

        # -mempooltxinputlimit is not used after overwinter activation
        if self.test_mempooltxinputlimit:
            expected_to_merge = 7
            expected_remaining = 13
        else:
            expected_to_merge = 20
            expected_remaining = 0

        result = test.nodes[2].z_mergetoaddress([n2taddr], myzaddr, Decimal('0.0001'), 0)
        assert_equal(result["mergingUTXOs"], expected_to_merge)
        assert_equal(result["remainingUTXOs"], expected_remaining)
        assert_equal(result["mergingNotes"], Decimal('0'))
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[2], result['opid'])
        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Verify maximum number of UTXOs which node 0 can shield is set by default limit parameter of 50
        mytaddr = test.nodes[0].getnewaddress()
        for i in range(100):
            test.nodes[1].sendtoaddress(mytaddr, 1)
        test.nodes[1].generate(1)
        test.sync_all()
        result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001'))
        assert_equal(result["mergingUTXOs"], Decimal('50'))
        assert_equal(result["remainingUTXOs"], Decimal('50'))
        assert_equal(result["mergingNotes"], Decimal('0'))
        # Remaining notes are only counted if we are trying to merge any notes
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])

        # Verify maximum number of UTXOs which node 0 can shield can be set by the limit parameter
        result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, Decimal('0.0001'), 33)
        assert_equal(result["mergingUTXOs"], Decimal('33'))
        assert_equal(result["remainingUTXOs"], Decimal('17'))
        assert_equal(result["mergingNotes"], Decimal('0'))
        # Remaining notes are only counted if we are trying to merge any notes
        assert_equal(result["remainingNotes"], Decimal('0'))
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit
        sync_blocks(test.nodes[:2])
        sync_mempools(test.nodes[:2])
        test.nodes[1].generate(1)
        test.sync_all()

        # Verify maximum number of notes which node 0 can shield can be set by the limit parameter
        # Also check that we can set off a second merge before the first one is complete

        # myzaddr will have 5 notes if testing before to Sapling activation and 4 otherwise
        num_notes = len(test.nodes[0].z_listunspent(0))
        result1 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2)
        result2 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2)

        # First merge should select from all notes
        assert_equal(result1["mergingUTXOs"], Decimal('0'))
        # Remaining UTXOs are only counted if we are trying to merge any UTXOs
        assert_equal(result1["remainingUTXOs"], Decimal('0'))
        assert_equal(result1["mergingNotes"], Decimal('2'))
        assert_equal(result1["remainingNotes"], num_notes - 2)

        # Second merge should ignore locked notes
        assert_equal(result2["mergingUTXOs"], Decimal('0'))
        assert_equal(result2["remainingUTXOs"], Decimal('0'))
        assert_equal(result2["mergingNotes"], Decimal('2'))
        assert_equal(result2["remainingNotes"], num_notes - 4)
        wait_and_assert_operationid_status(test.nodes[0], result1['opid'])
        wait_and_assert_operationid_status(test.nodes[0], result2['opid'])

        test.sync_all()
        test.nodes[1].generate(1)
        test.sync_all()

        # Shield both UTXOs and notes to a z-addr
        result = test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 0, 10, 2)
        assert_equal(result["mergingUTXOs"], Decimal('10'))
        assert_equal(result["remainingUTXOs"], Decimal('7'))
        assert_equal(result["mergingNotes"], Decimal('2'))
        assert_equal(result["remainingNotes"], num_notes - 4)
        wait_and_assert_operationid_status(test.nodes[0], result['opid'])
        # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit
        sync_blocks(test.nodes[:2])
        sync_mempools(test.nodes[:2])
        test.nodes[1].generate(1)
        test.sync_all()
Exemple #15
0
    def run_test(self):
        alice = self.nodes[0].getnewaddress()
        z_alice = self.nodes[0].z_getnewaddress('sapling')
        bob = self.nodes[2].getnewaddress()
        z_bob = self.nodes[2].z_getnewaddress('sapling')

        print("Splitting network...")
        self.split_network()

        # Test dependent txs
        firstTx = self.nodes[0].sendtoaddress(alice, 0.1)
        firstTxInfo = self.nodes[0].getrawtransaction(firstTx, 1)
        assert_equal(firstTxInfo["version"], 4)
        assert_equal(firstTxInfo["overwintered"], True)
        assert ("expiryheight" in firstTxInfo)
        print("First tx expiry height:", firstTxInfo['expiryheight'])
        # Mine first transaction
        self.nodes[0].generate(1)
        for outpoint in firstTxInfo['vout']:
            if outpoint['value'] == Decimal('0.10000000'):
                vout = outpoint
                break
        inputs = [{
            'txid': firstTx,
            'vout': vout['n'],
            'scriptPubKey': vout['scriptPubKey']['hex']
        }]
        outputs = {alice: 0.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[0].signrawtransaction(rawTx)
        assert (rawTxSigned['complete'])
        secondTx = self.nodes[0].sendrawtransaction(rawTxSigned['hex'])
        secondTxInfo = self.nodes[0].getrawtransaction(secondTx, 1)
        print("Second tx expiry height:", secondTxInfo['expiryheight'])
        # Mine second, dependent transaction
        self.nodes[0].generate(1)
        print("Mine %d competing blocks on Node 2..." % (2 + TX_EXPIRY_DELTA))
        blocks = self.nodes[2].generate(2 + TX_EXPIRY_DELTA)
        print("Connect nodes to force a reorg")
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False
        print("Syncing blocks")
        sync_blocks(self.nodes)
        print("Ensure that both txs are dropped from mempool of node 0")
        print("Blockheight node 0:",
              self.nodes[0].getblockchaininfo()['blocks'])
        print("Blockheight node 2:",
              self.nodes[2].getblockchaininfo()['blocks'])
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        assert_equal(set(self.nodes[2].getrawmempool()), set())

        ## Shield one of Alice's coinbase funds to her zaddr
        res = self.nodes[0].z_shieldcoinbase("*", z_alice, DEFAULT_FEE, 1)
        wait_and_assert_operationid_status(self.nodes[0], res['opid'])
        self.nodes[0].generate(1)
        self.sync_all()

        # Get balance on node 0
        bal = self.nodes[0].z_gettotalbalance()
        print("Balance before zsend, after shielding 10: ", bal)
        assert_equal(Decimal(bal["private"]), Decimal('97.0') - DEFAULT_FEE)

        print("Splitting network...")
        self.split_network()

        # Create transactions
        blockheight = self.nodes[0].getblockchaininfo()['blocks']
        zsendamount = Decimal('1.0') - DEFAULT_FEE
        recipients = []
        recipients.append({"address": z_bob, "amount": zsendamount})
        myopid = self.nodes[0].z_sendmany(z_alice, recipients)
        persist_shielded = wait_and_assert_operationid_status(
            self.nodes[0], myopid)
        persist_transparent = self.nodes[0].sendtoaddress(bob, 0.01)
        # Verify transparent transaction is version 4 intended for Sapling branch
        rawtx = self.nodes[0].getrawtransaction(persist_transparent, 1)
        assert_equal(rawtx["version"], 4)
        assert_equal(rawtx["overwintered"], True)
        assert_equal(rawtx["expiryheight"], blockheight + 1 + TX_EXPIRY_DELTA)
        print(
            "Blockheight at persist_transparent & persist_shielded creation:",
            self.nodes[0].getblockchaininfo()['blocks'])
        print("Expiryheight of persist_transparent:", rawtx['expiryheight'])
        # Verify shielded transaction is version 4 intended for Sapling branch
        rawtx = self.nodes[0].getrawtransaction(persist_shielded, 1)
        print("Expiryheight of persist_shielded", rawtx['expiryheight'])
        assert_equal(rawtx["version"], 4)
        assert_equal(rawtx["overwintered"], True)
        assert_equal(rawtx["expiryheight"], blockheight + 1 + TX_EXPIRY_DELTA)

        print(
            "\nBlockheight advances to less than expiry block height. After reorg, txs should persist in mempool"
        )
        assert (persist_transparent in self.nodes[0].getrawmempool())
        assert (persist_shielded in self.nodes[0].getrawmempool())
        assert_equal(set(self.nodes[2].getrawmempool()), set())
        print("mempool node 0:", self.nodes[0].getrawmempool())
        print("mempool node 2:", self.nodes[2].getrawmempool())
        bal = self.nodes[0].z_gettotalbalance()
        print(
            "Printing balance before persist_shielded & persist_transparent are initially mined from mempool",
            bal)
        # Txs are mined on node 0; will later be rolled back
        self.nodes[0].generate(1)
        print("Node 0 generated 1 block")
        print("Node 0 height:", self.nodes[0].getblockchaininfo()['blocks'])
        print("Node 2 height:", self.nodes[2].getblockchaininfo()['blocks'])
        bal = self.nodes[0].z_gettotalbalance()
        print(
            "Printing balance after persist_shielded & persist_transparent are mined:",
            bal)
        assert_equal(set(self.nodes[0].getrawmempool()), set())

        print("Mine 2 competing blocks on Node 2...")
        blocks = self.nodes[2].generate(2)
        for block in blocks:
            blk = self.nodes[2].getblock(block)
            print("Height: {0}, Mined block txs: {1}".format(
                blk["height"], blk["tx"]))
        print("Connect nodes to force a reorg")
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False

        print("Syncing blocks")
        sync_blocks(self.nodes)

        print("Ensure that txs are back in mempool of node 0")
        print("Blockheight node 0:",
              self.nodes[0].getblockchaininfo()['blocks'])
        print("Blockheight node 2:",
              self.nodes[2].getblockchaininfo()['blocks'])
        print("mempool node 0: ", self.nodes[0].getrawmempool())
        print("mempool node 2: ", self.nodes[2].getrawmempool())
        assert (persist_transparent in self.nodes[0].getrawmempool())
        assert (persist_shielded in self.nodes[0].getrawmempool())
        bal = self.nodes[0].z_gettotalbalance()
        # Mine txs to get them out of the way of mempool sync in split_network()
        print("Generating another block on node 0 to clear txs from mempool")
        self.nodes[0].generate(1)
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        sync_blocks(self.nodes)

        print("Splitting network...")
        self.split_network()

        print(
            "\nBlockheight advances to equal expiry block height. After reorg, txs should persist in mempool"
        )
        myopid = self.nodes[0].z_sendmany(z_alice, recipients)
        persist_shielded_2 = wait_and_assert_operationid_status(
            self.nodes[0], myopid)
        persist_transparent_2 = self.nodes[0].sendtoaddress(bob, 0.01)
        rawtx_trans = self.nodes[0].getrawtransaction(persist_transparent_2, 1)
        rawtx_shield = self.nodes[0].getrawtransaction(persist_shielded_2, 1)
        print("Blockheight node 0 at persist_transparent_2 creation:",
              self.nodes[0].getblockchaininfo()['blocks'])
        print("Blockheight node 2 at persist_transparent_2 creation:",
              self.nodes[2].getblockchaininfo()['blocks'])
        print("Expiryheight of persist_transparent_2:",
              rawtx_trans['expiryheight'])
        print("Expiryheight of persist_shielded_2:",
              rawtx_shield['expiryheight'])
        blocks = self.nodes[2].generate(4)
        for block in blocks:
            blk = self.nodes[2].getblock(block)
            print("Height: {0}, Mined block txs: {1}".format(
                blk["height"], blk["tx"]))
        print("Connect nodes to force a reorg")
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False
        sync_blocks(self.nodes)
        print(
            "Ensure that persist_transparent_2 & persist_shielded_2 are in mempool at expiry block height"
        )
        print("Blockheight node 0:",
              self.nodes[0].getblockchaininfo()['blocks'])
        print("Blockheight node 2:",
              self.nodes[2].getblockchaininfo()['blocks'])
        print("mempool node 0: ", self.nodes[0].getrawmempool())
        print("mempool node 2: ", self.nodes[2].getrawmempool())
        assert (persist_transparent_2 in self.nodes[0].getrawmempool())
        assert (persist_shielded_2 in self.nodes[0].getrawmempool())
        # Mine persist txs to get them out of the way of mempool sync in split_network()
        self.nodes[0].generate(1)
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        sync_blocks(self.nodes)
        print(
            "Balance after persist_shielded_2 is mined to remove from mempool: ",
            self.nodes[0].z_gettotalbalance())

        print("Splitting network...")
        self.split_network()

        print(
            "\nBlockheight advances to greater than expiry block height. After reorg, txs should expire from mempool"
        )
        print("Balance before expire_shielded is sent: ",
              self.nodes[0].z_gettotalbalance())
        myopid = self.nodes[0].z_sendmany(z_alice, recipients)
        expire_shielded = wait_and_assert_operationid_status(
            self.nodes[0], myopid)
        expire_transparent = self.nodes[0].sendtoaddress(bob, 0.01)
        print("Blockheight node 0 at expire_transparent creation:",
              self.nodes[0].getblockchaininfo()['blocks'])
        print("Blockheight node 2 at expire_shielded creation:",
              self.nodes[2].getblockchaininfo()['blocks'])
        print(
            "Expiryheight of expire_transparent:",
            self.nodes[0].getrawtransaction(expire_transparent,
                                            1)['expiryheight'])
        print(
            "Expiryheight of expire_shielded:",
            self.nodes[0].getrawtransaction(expire_shielded,
                                            1)['expiryheight'])
        assert (expire_transparent in self.nodes[0].getrawmempool())
        assert (expire_shielded in self.nodes[0].getrawmempool())
        blocks = self.nodes[2].generate(1 + TX_EXPIRY_DELTA + 1)
        for block in blocks:
            blk = self.nodes[2].getblock(block)
            print("Height: {0}, Mined block txs: {1}".format(
                blk["height"], blk["tx"]))
        print("Connect nodes to force a reorg")
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False
        sync_blocks(self.nodes)
        print(
            "Ensure that expire_transparent & expire_shielded are not in mempool after expiry block height"
        )
        print("mempool node 0: ", self.nodes[0].getrawmempool())
        print("mempool node 2: ", self.nodes[2].getrawmempool())
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        print("Ensure balance of node 0 is correct")
        bal = self.nodes[0].z_gettotalbalance()
        print("Balance after expire_shielded has expired: ", bal)
        assert_equal(Decimal(bal["private"]), Decimal('95.0') - DEFAULT_FEE)

        print("Splitting network...")
        self.split_network()

        print(
            "\nBlockheight advances to just before expiring soon threshold.  Txs should be rejected from entering mempool."
        )
        print("Balance before expire_shielded is sent: ",
              self.nodes[0].z_gettotalbalance())
        myopid = self.nodes[0].z_sendmany(z_alice, recipients)
        expire_shielded = wait_and_assert_operationid_status(
            self.nodes[0], myopid)
        expire_transparent = self.nodes[0].sendtoaddress(bob, 0.01)
        print("Blockheight node 0 at expire_transparent creation:",
              self.nodes[0].getblockchaininfo()['blocks'])
        print("Blockheight node 2 at expire_shielded creation:",
              self.nodes[2].getblockchaininfo()['blocks'])
        print(
            "Expiryheight of expire_transparent:",
            self.nodes[0].getrawtransaction(expire_transparent,
                                            1)['expiryheight'])
        print(
            "Expiryheight of expire_shielded:",
            self.nodes[0].getrawtransaction(expire_shielded,
                                            1)['expiryheight'])
        assert (expire_transparent in self.nodes[0].getrawmempool())
        assert (expire_shielded in self.nodes[0].getrawmempool())
        blocks = self.nodes[2].generate(1 + TX_EXPIRY_DELTA -
                                        TX_EXPIRING_SOON_THRESHOLD - 1)
        for block in blocks:
            blk = self.nodes[2].getblock(block)
            print("Height: {0}, Mined block txs: {1}".format(
                blk["height"], blk["tx"]))
        print("Connect nodes to force a reorg")
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False
        sync_blocks(self.nodes)
        print(
            "Ensure that expire_transparent & expire_shielded are in node 0 mempool but not node 2 mempool"
        )
        print("mempool node 0: ", self.nodes[0].getrawmempool())
        print("mempool node 2: ", self.nodes[2].getrawmempool())
        assert (expire_transparent in self.nodes[0].getrawmempool())
        assert (expire_shielded in self.nodes[0].getrawmempool())
        assert (expire_transparent not in self.nodes[2].getrawmempool())
        assert (expire_shielded not in self.nodes[2].getrawmempool())

        # Now try to add the transactions to Node 2 mempool.
        # Node 2 mempool will accept a transaction since block height has not reached the expiring soon threshold.
        rawtx = self.nodes[0].getrawtransaction(expire_transparent)
        self.nodes[2].sendrawtransaction(rawtx)

        # Generate a block and enter the expiring soon threshold.
        self.nodes[2].generate(1)
        # Node 2 mempool will reject a transaction which is expiring soon.
        try:
            rawtx = self.nodes[0].getrawtransaction(expire_shielded)
            self.nodes[2].sendrawtransaction(rawtx)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("tx-expiring-soon" in errorString)
Exemple #16
0
    def run_test(self):
        print "Mining blocks..."
        print "On REGTEST... \n\treward is {} per block\n\t100 blocks to maturity".format(
            self._reward)

        self.nodes[0].generate(4)
        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], self._reward * 4)
        assert_equal(walletinfo['balance'], 0)
        self.sync_all()
        self.nodes[2].generate(3)
        self.sync_all()
        self.nodes[1].generate(101)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), self._reward * 4)
        assert_equal(self.nodes[1].getbalance(), self._reward * 1)
        assert_equal(self.nodes[2].getbalance(), self._reward * 3)

        mytaddr = self.nodes[0].getnewaddress()
        myzaddr = self.nodes[0].z_getnewaddress()

        # Check that Node 2 has payment disclosure disabled.
        try:
            self.nodes[2].z_getpaymentdisclosure("invalidtxid", 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("payment disclosure is disabled" in errorString)

        # Check that Node 0 returns an error for an unknown txid
        try:
            self.nodes[0].z_getpaymentdisclosure("invalidtxid", 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("No information available about transaction"
                    in errorString)

        # Shield coinbase utxos from node 0 of value 40, standard fee of 0.10000
        recipients = [{
            "address": myzaddr,
            "amount": Decimal(self._reward * 4) - self._fee
        }]
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        txid = wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Check the tx has joinsplits
        assert (len(self.nodes[0].getrawtransaction("" + txid,
                                                    1)["vjoinsplit"]) > 0)

        # Sync mempools
        self.sync_all()

        # Confirm that you can't create a payment disclosure for an unconfirmed tx
        try:
            self.nodes[0].z_getpaymentdisclosure(txid, 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Transaction has not been confirmed yet" in errorString)

        try:
            self.nodes[1].z_getpaymentdisclosure(txid, 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Transaction has not been confirmed yet" in errorString)

        # Mine tx
        self.nodes[0].generate(1)
        self.sync_all()

        # Confirm that Node 1 cannot create a payment disclosure for a transaction which does not impact its wallet
        try:
            self.nodes[1].z_getpaymentdisclosure(txid, 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Transaction does not belong to the wallet" in errorString)

        # Check that an invalid joinsplit index is rejected
        try:
            self.nodes[0].z_getpaymentdisclosure(txid, 1, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Invalid js_index" in errorString)

        try:
            self.nodes[0].z_getpaymentdisclosure(txid, -1, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Invalid js_index" in errorString)

        # Check that an invalid output index is rejected
        try:
            self.nodes[0].z_getpaymentdisclosure(txid, 0, 2)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Invalid output_index" in errorString)

        try:
            self.nodes[0].z_getpaymentdisclosure(txid, 0, -1)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Invalid output_index" in errorString)

        # Ask Node 0 to create and validate a payment disclosure for output 0
        message = "Here is proof of my payment!"
        pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, message)
        result = self.nodes[0].z_validatepaymentdisclosure(pd)
        assert (result["valid"])
        output_value_sum = Decimal(result["value"])

        # Ask Node 1 to confirm the payment disclosure is valid
        result = self.nodes[1].z_validatepaymentdisclosure(pd)
        assert (result["valid"])
        assert_equal(result["message"], message)
        assert_equal(result["value"], output_value_sum)

        # Confirm that payment disclosure begins with prefix zpd:
        assert (pd.startswith("zpd:"))

        # Confirm that payment disclosure without prefix zpd: fails validation
        try:
            self.nodes[1].z_validatepaymentdisclosure(pd[4:])
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("payment disclosure prefix not found" in errorString)

        # Check that total value of output index 0 and index 1 should equal shielding amount of 40 less standard fee.
        pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 1)
        result = self.nodes[0].z_validatepaymentdisclosure(pd)
        output_value_sum += Decimal(result["value"])
        assert_equal(output_value_sum, Decimal(self._reward * 4) - self._fee)

        # Create a z->z transaction, sending shielded funds from node 0 to node 1
        node1zaddr = self.nodes[1].z_getnewaddress()
        recipients = [{"address": node1zaddr, "amount": Decimal('1')}]
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
        txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Confirm that Node 0 can create a valid payment disclosure
        pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0,
                                                  "a message of your choice")
        result = self.nodes[0].z_validatepaymentdisclosure(pd)
        assert (result["valid"])

        # Confirm that Node 1, even as recipient of shielded funds, cannot create a payment disclosure
        # as the transaction was created by Node 0 and Node 1's payment disclosure database does not
        # contain the necessary data to do so, where the data would only have been available on Node 0
        # when executing z_shieldcoinbase.
        try:
            self.nodes[1].z_getpaymentdisclosure(txid, 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert (
                "Could not find payment disclosure info for the given joinsplit output"
                in errorString)

        # Payment disclosures cannot be created for transparent transactions.
        txid = self.nodes[2].sendtoaddress(mytaddr, 1.0)
        self.sync_all()

        # No matter the type of transaction, if it has not been confirmed, it is ignored.
        try:
            self.nodes[0].z_getpaymentdisclosure(txid, 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Transaction has not been confirmed yet" in errorString)

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

        # Confirm that a payment disclosure can only be generated for a shielded transaction.
        try:
            self.nodes[0].z_getpaymentdisclosure(txid, 0, 0)
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            assert ("Transaction is not a shielded transaction" in errorString)
Exemple #17
0
        def nu_activation_checks():
            # Mine block H - 2. After this, the mempool expects
            # block H - 1, which is the last X block.
            self.nodes[0].generate(1)
            self.sync_all()

            # Mempool should be empty.
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Check node 0 shielded balance
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr),
                         Decimal('10'))

            # Fill the mempool with twice as many transactions as can fit into blocks
            node0_taddr = self.nodes[0].getnewaddress()
            x_txids = []
            while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000:
                x_txids.append(self.nodes[1].sendtoaddress(
                    node0_taddr, Decimal('0.001')))
            self.sync_all()

            # Spends should be in the mempool
            x_mempool = set(self.nodes[0].getrawmempool())
            assert_equal(x_mempool, set(x_txids))

            # Mine block H - 1. After this, the mempool expects
            # block H, which is the first Y block.
            self.nodes[0].generate(1)
            self.sync_all()

            # mempool should be empty.
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Block H - 1 should contain a subset of the original mempool
            # (with all other transactions having been dropped)
            block_txids = self.nodes[0].getblock(
                self.nodes[0].getbestblockhash())['tx']
            assert (len(block_txids) < len(x_txids))
            for txid in block_txids[1:]:  # Exclude coinbase
                assert (txid in x_txids)

            # Create some transparent Y transactions
            y_txids = [
                self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001'))
                for i in range(10)
            ]
            self.sync_all()

            # Create a shielded Y transaction
            recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}]
            myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1,
                                              Decimal('0'))
            shielded = wait_and_assert_operationid_status(
                self.nodes[0], myopid)
            assert (shielded != None)
            y_txids.append(shielded)
            self.sync_all()

            # Spends should be in the mempool
            assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids))

            # Node 0 note should be unspendable
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0'))

            # Invalidate block H - 1.
            block_hm1 = self.nodes[0].getbestblockhash()
            self.nodes[0].invalidateblock(block_hm1)

            # BUG: Ideally, the mempool should now only contain the transactions
            # that were in block H - 1, the Y transactions having been dropped.
            # However, because chainActive is not updated until after the transactions
            # in the disconnected block have been re-added to the mempool, the height
            # seen by AcceptToMemoryPool is one greater than it should be. This causes
            # the block H - 1 transactions to be validated against the Y rules,
            # and rejected because they (obviously) fail.
            #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:]))
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Node 0 note should be spendable again
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr),
                         Decimal('10'))

            # Reconsider block H - 1.
            self.nodes[0].reconsiderblock(block_hm1)

            # Mine blocks on node 1, so that the Y transactions in its mempool
            # will be cleared.
            self.nodes[1].generate(6)
            self.sync_all()
Exemple #18
0
    def run_test(self):
        [alice, bob, charlie, david, miner] = self.nodes

        # the sender loses 'amount' plus fee; to_addr receives exactly 'amount'
        def z_send(from_node, from_addr, to_addr, amount):
            global fee
            opid = from_node.z_sendmany(from_addr,
                [{"address": to_addr, "amount": Decimal(amount)}], 1, fee)
            wait_and_assert_operationid_status(from_node, opid)
            self.sync_all()
            miner.generate(1)
            self.sync_all()

        def verify_utxos(node, amts, zaddr):
            amts.sort(reverse=True)
            txs = node.z_listreceivedbyaddress(zaddr)

            def cmp_confirmations_high_to_low(a, b):
                return cmp(b["amount"], a["amount"])

            txs.sort(cmp_confirmations_high_to_low)
            print("Sorted txs", txs)
            print("amts", amts)

            try:
                assert_equal(amts, [tx["amount"] for tx in txs])
                for tx in txs:
                    # make sure JoinSplit keys exist and have valid values
                    assert_equal("jsindex" in tx, True)
                    assert_equal("jsoutindex" in tx, True)
                    assert_greater_than(tx["jsindex"], -1)
                    assert_greater_than(tx["jsoutindex"], -1)
            except AssertionError:
                logging.error(
                    'Expected amounts: %r; txs: %r',
                    amts, txs)
                raise

        def get_private_balance(node):
            balance = node.z_gettotalbalance()
            return balance['private']

        def find_imported_key(node, import_zaddr):
            zaddrs = node.z_listaddresses()
            assert(import_zaddr in zaddrs)
            return import_zaddr

        # Seed Alice with some funds
        alice.generate(10)
        self.sync_all()
        miner.generate(100)
        self.sync_all()
        # Shield Alice's coinbase funds to her zaddr
        alice_zaddr = alice.z_getnewaddress('sprout')
        res = alice.z_shieldcoinbase("*", alice_zaddr)
        wait_and_assert_operationid_status(alice, res['opid'])
        self.sync_all()
        miner.generate(1)
        self.sync_all()

        # Now get a pristine z-address for receiving transfers:
        bob_zaddr = bob.z_getnewaddress('sprout')
        verify_utxos(bob, [], bob_zaddr)
        # TODO: Verify that charlie doesn't have funds in addr
        # verify_utxos(charlie, [])

        # the amounts of each txn embodied which generates a single UTXO:
        amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19'])

        # Internal test consistency assertion:
        assert_greater_than(
            get_private_balance(alice),
            reduce(Decimal.__add__, amounts))

        logging.info("Sending pre-export txns...")
        for amount in amounts[0:2]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        logging.info("Exporting privkey from bob...")
        bob_privkey = bob.z_exportkey(bob_zaddr)

        logging.info("Sending post-export txns...")
        for amount in amounts[2:4]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        verify_utxos(bob, amounts[:4], bob_zaddr)
        # verify_utxos(charlie, [])

        logging.info("Importing bob_privkey into charlie...")
        # z_importkey rescan defaults to "whenkeyisnew", so should rescan here
        charlie.z_importkey(bob_privkey)
        ipk_zaddr = find_imported_key(charlie, bob_zaddr)

        # z_importkey should have rescanned for new key, so this should pass:
        verify_utxos(charlie, amounts[:4], ipk_zaddr)

        # Verify idempotent behavior:
        charlie.z_importkey(bob_privkey)
        ipk_zaddr2 = find_imported_key(charlie, bob_zaddr)
        assert_equal(ipk_zaddr, ipk_zaddr2)

        # amounts should be unchanged
        verify_utxos(charlie, amounts[:4], ipk_zaddr2)

        logging.info("Sending post-import txns...")
        for amount in amounts[4:]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        verify_utxos(bob, amounts, bob_zaddr)
        verify_utxos(charlie, amounts, ipk_zaddr)
        verify_utxos(charlie, amounts, ipk_zaddr2)

        # keep track of the fees incurred by bob (his sends)
        bob_fee = Decimal(0)

        # Try to reproduce zombie balance reported in #1936
        # At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice
        for amount in amounts[:2]:
            print("Sending amount from bob to alice: ", amount)
            z_send(bob, bob_zaddr, alice_zaddr, amount)
            bob_fee += fee

        bob_balance = sum(amounts[2:]) - bob_fee
        assert_equal(bob.z_getbalance(bob_zaddr), bob_balance)

        # z_import onto new node "david" (blockchain rescan, default or True?)
        david.z_importkey(bob_privkey)
        d_ipk_zaddr = find_imported_key(david, bob_zaddr)

        # Check if amt bob spent is deducted for charlie and david
        assert_equal(charlie.z_getbalance(ipk_zaddr), bob_balance)
        assert_equal(david.z_getbalance(d_ipk_zaddr), bob_balance)
    def run_test(self):
        print("Mining blocks...")

        self.nodes[0].generate(4)
        self.sync_all()

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 40)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), 40)
        assert_equal(self.nodes[1].getbalance(), 10)
        assert_equal(self.nodes[2].getbalance(), 0)
        assert_equal(self.nodes[3].getbalance(), 0)

        check_value_pool(self.nodes[0], 'sprout', 0)
        check_value_pool(self.nodes[1], 'sprout', 0)
        check_value_pool(self.nodes[2], 'sprout', 0)
        check_value_pool(self.nodes[3], 'sprout', 0)

        # Send will fail because we are enforcing the consensus rule that
        # coinbase utxos can only be sent to a zaddr.
        errorString = ""
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1)
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal(
            "Coinbase funds can only be sent to a zaddr" in errorString, True)

        # Prepare to send taddr->zaddr
        mytaddr = get_coinbase_address(self.nodes[0])
        myzaddr = self.nodes[0].z_getnewaddress('sprout')

        # Node 3 will test that watch only address utxos are not selected
        self.nodes[3].importaddress(mytaddr)
        recipients = [{"address": myzaddr, "amount": Decimal('1')}]
        myopid = self.nodes[3].z_sendmany(mytaddr, recipients)

        wait_and_assert_operationid_status(
            self.nodes[3], myopid, "failed",
            "Insufficient transparent funds, no UTXOs found for taddr from address.",
            10)

        # This send will fail because our wallet does not allow any change when shielding a coinbase utxo,
        # as it's currently not possible to specify a change address in z_sendmany.
        recipients = []
        recipients.append({
            "address": myzaddr,
            "amount": Decimal('1.23456789')
        })

        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        error_result = wait_and_assert_operationid_status_result(
            self.nodes[0], myopid, "failed",
            ("Change 8.76542211 not allowed. "
             "When shielding coinbase funds, the wallet does not allow any change "
             "as there is currently no way to specify a change address in z_sendmany."
             ), 10)

        # Test that the returned status object contains a params field with the operation's input parameters
        assert_equal(error_result["method"], "z_sendmany")
        params = error_result["params"]
        assert_equal(params["fee"], DEFAULT_FEE)  # default
        assert_equal(params["minconf"], Decimal('1'))  # default
        assert_equal(params["fromaddress"], mytaddr)
        assert_equal(params["amounts"][0]["address"], myzaddr)
        assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789'))

        # Add viewing key for myzaddr to Node 3
        myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr)
        self.nodes[3].z_importviewingkey(myviewingkey, "no")

        # This send will succeed.  We send two coinbase utxos totalling 20.0 less a default fee, with no change.
        shieldvalue = Decimal('20.0') - DEFAULT_FEE
        recipients = []
        recipients.append({"address": myzaddr, "amount": shieldvalue})
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()

        # Verify that z_listunspent can return a note that has zero confirmations
        results = self.nodes[0].z_listunspent()
        assert (len(results) == 0)
        results = self.nodes[0].z_listunspent(0)  # set minconf to zero
        assert (len(results) == 1)
        assert_equal(results[0]["address"], myzaddr)
        assert_equal(results[0]["amount"], shieldvalue)
        assert_equal(results[0]["confirmations"], 0)

        # Mine the tx
        self.nodes[1].generate(1)
        self.sync_all()

        # Verify that z_listunspent returns one note which has been confirmed
        results = self.nodes[0].z_listunspent()
        assert (len(results) == 1)
        assert_equal(results[0]["address"], myzaddr)
        assert_equal(results[0]["amount"], shieldvalue)
        assert_equal(results[0]["confirmations"], 1)
        assert_equal(results[0]["spendable"], True)

        # Verify that z_listunspent returns note for watchonly address on node 3.
        results = self.nodes[3].z_listunspent(1, 999, True)
        assert (len(results) == 1)
        assert_equal(results[0]["address"], myzaddr)
        assert_equal(results[0]["amount"], shieldvalue)
        assert_equal(results[0]["confirmations"], 1)
        assert_equal(results[0]["spendable"], False)

        # Verify that z_listunspent returns error when address spending key from node 0 is not available in wallet of node 1.
        try:
            results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr])
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal(
            "Invalid parameter, spending key for address does not belong to wallet"
            in errorString, True)

        # Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid
        initialized_line = check_node_log(self, 0,
                                          myopid + ": z_sendmany initialized",
                                          False)
        finished_line = check_node_log(self, 0,
                                       myopid + ": z_sendmany finished", False)
        assert (initialized_line < finished_line)

        # check balances (the z_sendmany consumes 3 coinbase utxos)
        resp = self.nodes[0].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
        assert_equal(Decimal(resp["private"]), Decimal('20.0') - DEFAULT_FEE)
        assert_equal(Decimal(resp["total"]), Decimal('40.0') - DEFAULT_FEE)

        # The Sprout value pool should reflect the send
        sproutvalue = shieldvalue
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        # A custom fee of 0 is okay.  Here the node will send the note value back to itself.
        recipients = []
        recipients.append({
            "address": myzaddr,
            "amount": Decimal('20.0') - DEFAULT_FEE
        })
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1,
                                          Decimal('0.0'))
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        resp = self.nodes[0].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
        assert_equal(Decimal(resp["private"]), Decimal('20.0') - DEFAULT_FEE)
        assert_equal(Decimal(resp["total"]), Decimal('40.0') - DEFAULT_FEE)

        # The Sprout value pool should be unchanged
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        # convert note to transparent funds
        unshieldvalue = Decimal('10.0')
        recipients = []
        recipients.append({"address": mytaddr, "amount": unshieldvalue})
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        assert (mytxid is not None)
        self.sync_all()

        # check that priority of the tx sending from a zaddr is not 0
        mempool = self.nodes[0].getrawmempool(True)
        assert (Decimal(mempool[mytxid]['startingpriority']) >=
                Decimal('1000000000000'))

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

        # check balances
        sproutvalue -= unshieldvalue + DEFAULT_FEE
        resp = self.nodes[0].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), Decimal('30.0'))
        assert_equal(Decimal(resp["private"]),
                     Decimal('10.0') - 2 * DEFAULT_FEE)
        assert_equal(Decimal(resp["total"]), Decimal('40.0') - 2 * DEFAULT_FEE)
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        # z_sendmany will return an error if there is transparent change output considered dust.
        # UTXO selection in z_sendmany sorts in ascending order, so smallest utxos are consumed first.
        # At this point in time, unspent notes all have a value of 10.0.
        recipients = []
        amount = Decimal('10.0') - DEFAULT_FEE - Decimal(
            '0.00000001'
        )  # this leaves change at 1 zatoshi less than dust threshold
        recipients.append({
            "address": self.nodes[0].getnewaddress(),
            "amount": amount
        })
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(
            self.nodes[0], myopid, "failed",
            "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)"
        )

        # Send will fail because send amount is too big, even when including coinbase utxos
        errorString = ""
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999)
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal("Insufficient funds" in errorString, True)

        # z_sendmany will fail because of insufficient funds
        recipients = []
        recipients.append({
            "address": self.nodes[1].getnewaddress(),
            "amount": Decimal('10000.0')
        })
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(
            self.nodes[0], myopid, "failed",
            "Insufficient transparent funds, have 10.00, need 10000.00001")
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
        wait_and_assert_operationid_status(
            self.nodes[0], myopid, "failed",
            "Insufficient shielded funds, have 9.99998, need 10000.00001")

        # Send will fail because of insufficient funds unless sender uses coinbase utxos
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21)
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal(
            "Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr"
            in errorString, True)

        # Verify that mempools accept tx with joinsplits which have at least the default z_sendmany fee.
        # If this test passes, it confirms that issue #1851 has been resolved, where sending from
        # a zaddr to 1385 taddr recipients fails because the default fee was considered too low
        # given the tx size, resulting in mempool rejection.
        errorString = ''
        recipients = []
        num_t_recipients = 2500
        amount_per_recipient = Decimal('0.00000546')  # dust threshold
        # Note that regtest chainparams does not require standard tx, so setting the amount to be
        # less than the dust threshold, e.g. 0.00000001 will not result in mempool rejection.
        start_time = timeit.default_timer()
        for i in range(0, num_t_recipients):
            newtaddr = self.nodes[2].getnewaddress()
            recipients.append({
                "address": newtaddr,
                "amount": amount_per_recipient
            })
        elapsed = timeit.default_timer() - start_time
        print("...invoked getnewaddress() {} times in {} seconds".format(
            num_t_recipients, elapsed))

        # Issue #2263 Workaround START
        # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process
        # loop above to create new addresses, that when z_sendmany is called with a large amount of
        # rpc data in recipients, the connection fails with a 'broken pipe' error.  Making a RPC call
        # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP
        # connection into a good state to handle a large amount of data in recipients.
        self.nodes[0].getinfo()
        # Issue #2263 Workaround END

        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
        try:
            wait_and_assert_operationid_status(self.nodes[0], myopid)
        except JSONRPCException as e:
            print("JSONRPC error: " + e.error['message'])
            assert (False)
        except Exception as e:
            print("Unexpected exception caught during testing: ",
                  e.error['message'], str(sys.exc_info()[0]))
            assert (False)

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

        # check balance
        node2balance = amount_per_recipient * num_t_recipients
        sproutvalue -= node2balance + DEFAULT_FEE
        assert_equal(self.nodes[2].getbalance(), node2balance)
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        # Send will fail because fee is negative
        try:
            self.nodes[0].z_sendmany(myzaddr, recipients, 1, -1)
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal("Amount out of range" in errorString, True)

        # Send will fail because fee is larger than MAX_MONEY
        try:
            self.nodes[0].z_sendmany(myzaddr, recipients, 1,
                                     Decimal('21000000.00000001'))
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal("Amount out of range" in errorString, True)

        # Send will fail because fee is larger than sum of outputs
        try:
            self.nodes[0].z_sendmany(
                myzaddr, recipients, 1,
                (amount_per_recipient * num_t_recipients) +
                Decimal('0.00000001'))
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal("is greater than the sum of outputs" in errorString, True)

        # Send will succeed because the balance of non-coinbase utxos is 10.0
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 9)
        except JSONRPCException:
            assert (False)

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

        # check balance
        node2balance = node2balance + 9
        assert_equal(self.nodes[2].getbalance(), node2balance)

        # Check that chained joinsplits in a single tx are created successfully.
        recipients = []
        num_recipients = 3
        amount_per_recipient = Decimal('0.002')
        minconf = 1
        send_amount = num_recipients * amount_per_recipient
        custom_fee = Decimal('0.00012345')
        zbalance = self.nodes[0].z_getbalance(myzaddr)
        for i in range(0, num_recipients):
            newzaddr = self.nodes[2].z_getnewaddress('sprout')
            recipients.append({
                "address": newzaddr,
                "amount": amount_per_recipient
            })
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf,
                                          custom_fee)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # check balances and unspent notes
        resp = self.nodes[2].z_gettotalbalance()
        assert_equal(Decimal(resp["private"]), send_amount)

        notes = self.nodes[2].z_listunspent()
        sum_of_notes = sum([note["amount"] for note in notes])
        assert_equal(Decimal(resp["private"]), sum_of_notes)

        resp = self.nodes[0].z_getbalance(myzaddr)
        assert_equal(Decimal(resp), zbalance - custom_fee - send_amount)
        sproutvalue -= custom_fee
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr])
        sum_of_notes = sum([note["amount"] for note in notes])
        assert_equal(Decimal(resp), sum_of_notes)
Exemple #20
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())
Exemple #21
0
            newzaddr = self.nodes[2].z_getnewaddress()
            recipients.append({"address":newzaddr, "amount":amount_per_recipient})
        try:
            self.nodes[0].z_sendmany(myzaddr, recipients)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert("Invalid parameter, too many zaddr outputs" in errorString)

        # add zaddr to node 2
        myzaddr = self.nodes[2].z_getnewaddress()

        # send node 2 taddr to zaddr
        recipients = []
        recipients.append({"address":myzaddr, "amount":7})

        mytxid = wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(mytaddr, recipients))

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

        # check balances
        zsendmanynotevalue = Decimal('7.0')
        zsendmanyfee = Decimal('0.0001')
        node2utxobalance = Decimal('23.998') - zsendmanynotevalue - zsendmanyfee

        assert_equal(self.nodes[2].getbalance(), node2utxobalance)
        assert_equal(self.nodes[2].getbalance("*"), node2utxobalance)

        # check zaddr balance
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue)
            assert(False)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert_equal("JSON integer out of range" in errorString, True)

        # Merging will fail for this specific case where it would spend a fee and do nothing
        try:
            self.nodes[0].z_mergetoaddress([mytaddr], mytaddr)
            assert(False)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert_equal("Destination address is also the only source address, and all its funds are already merged" in errorString, True)

        # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000
        result = self.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr)
        wait_and_assert_operationid_status(self.nodes[0], result['opid'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Confirm balances and that do_not_shield_taddr containing funds of 10 was left alone
        assert_equal(self.nodes[0].getbalance(), 10)
        assert_equal(self.nodes[0].z_getbalance(do_not_shield_taddr), Decimal('10.0'))
        assert_equal(self.nodes[0].z_getbalance(myzaddr), Decimal('39.99990000'))
        assert_equal(self.nodes[1].getbalance(), 40)
        assert_equal(self.nodes[2].getbalance(), 30)

        # Shield all notes to another z-addr
        myzaddr2 = self.nodes[0].z_getnewaddress()
        result = self.nodes[0].z_mergetoaddress(["ANY_ZADDR"], myzaddr2, 0)
        assert_equal(result["mergingUTXOs"], Decimal('0'))
Exemple #23
0
    def run_test(self):
        [alice, bob, charlie, miner] = self.nodes

        # the sender loses 'amount' plus fee; to_addr receives exactly 'amount'
        def z_send(from_node, from_addr, to_addr, amount):
            global fee
            opid = from_node.z_sendmany(from_addr, [{
                "address": to_addr,
                "amount": Decimal(amount)
            }], 1, fee)
            wait_and_assert_operationid_status(from_node, opid)
            self.sync_all()
            miner.generate(1)
            self.sync_all()

        def verify_utxos(node, amts, zaddr):
            amts.sort(reverse=True)
            txs = node.z_listreceivedbyaddress(zaddr)

            def cmp_confirmations_high_to_low(a, b):
                return cmp(b["amount"], a["amount"])

            txs.sort(cmp_confirmations_high_to_low)

            try:
                assert_equal(amts, [tx["amount"] for tx in txs])
            except AssertionError:
                logging.error('Expected amounts: %r; txs: %r', amts, txs)
                raise

        def get_private_balance(node):
            balance = node.z_gettotalbalance()
            return balance['private']

        def find_imported_zaddr(node, import_zaddr):
            zaddrs = node.z_listaddresses()
            assert (import_zaddr in zaddrs)
            return import_zaddr

        # activate sapling
        alice.generate(102)
        self.sync_all()

        # sanity-check the test harness
        assert_equal(self.nodes[0].getblockcount(), 102)

        # shield alice's coinbase funds to her zaddr
        alice_zaddr = alice.z_getnewaddress('sapling')
        res = alice.z_shieldcoinbase("*", alice_zaddr)
        wait_and_assert_operationid_status(alice, res['opid'])
        self.sync_all()
        miner.generate(1)
        self.sync_all()

        amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19'])

        # internal test consistency assertion:
        assert_greater_than(get_private_balance(alice),
                            reduce(Decimal.__add__, amounts))

        # now get a pristine z-address for receiving transfers:
        bob_zaddr = bob.z_getnewaddress('sapling')
        verify_utxos(bob, [], bob_zaddr)

        logging.info("sending pre-export txns...")
        for amount in amounts[0:2]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        logging.info("exporting ivk from bob...")
        bob_ivk = bob.z_exportviewingkey(bob_zaddr)

        logging.info("sending post-export txns...")
        for amount in amounts[2:4]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        verify_utxos(bob, amounts[:4], bob_zaddr)

        logging.info("importing bob_ivk into charlie...")
        # we need to pass bob_zaddr since it's a sapling address
        charlie.z_importviewingkey(bob_ivk, 'yes', 0, bob_zaddr)

        # z_importkey should have rescanned for new key, so this should pass:
        verify_utxos(charlie, amounts[:4], bob_zaddr)

        # verify idempotent behavior:
        charlie.z_importviewingkey(bob_ivk, 'yes', 0, bob_zaddr)
        verify_utxos(charlie, amounts[:4], bob_zaddr)

        logging.info("Sending post-import txns...")
        for amount in amounts[4:]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        verify_utxos(bob, amounts, bob_zaddr)
        verify_utxos(charlie, amounts, bob_zaddr)
    def run_test(self):
        self.nodes[0].generate(100)
        self.sync_all()
        # Mine three blocks. After this, nodes[0] blocks
        # 1, 2, and 3 are spend-able.
        self.nodes[1].generate(3)
        self.sync_all()

        # Check 1: z_sendmany is limited by -mempooltxinputlimit

        # Add zaddr to node 0
        node0_zaddr = self.nodes[0].z_getnewaddress('sprout')

        # Send three inputs from node 0 taddr to zaddr to get out of coinbase
        node0_taddr = get_coinbase_address(self.nodes[0])
        recipients = []
        recipients.append({"address":node0_zaddr, "amount":Decimal('30.0')-Decimal('0.0001')}) # utxo amount less fee
        myopid = self.nodes[0].z_sendmany(node0_taddr, recipients)

        # Spend should fail due to -mempooltxinputlimit
        wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Too many transparent inputs 3 > limit 2", 120)

        # Mempool should be empty.
        assert_equal(set(self.nodes[0].getrawmempool()), set())

        # Reduce amount to only use two inputs
        spend_zaddr_amount = Decimal('20.0') - Decimal('0.0001')
        spend_zaddr_id = self.call_z_sendmany(node0_taddr, node0_zaddr, spend_zaddr_amount) # utxo amount less fee
        self.sync_all()

        # Spend should be in the mempool
        assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_zaddr_id ]))

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

        # mempool should be empty.
        assert_equal(set(self.nodes[0].getrawmempool()), set())

        # Check 2: sendfrom is limited by -mempooltxinputlimit
        recipients = []
        spend_taddr_amount = spend_zaddr_amount - Decimal('0.0001')
        spend_taddr_output = Decimal('8')

        # Create three outputs
        recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_output})
        recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_output})
        recipients.append({"address":self.nodes[1].getnewaddress(), "amount": spend_taddr_amount - spend_taddr_output - spend_taddr_output})

        myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Should use three UTXOs and fail
        try:
            self.nodes[1].sendfrom("", node0_taddr, spend_taddr_amount - Decimal('1'))
            assert(False)
        except JSONRPCException,e:
            msg = e.error['message']
            assert_equal("Too many transparent inputs 3 > limit 2", msg)
    def test_received_sapling(self, height):
        self.generate_and_sync(height + 1)
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress('sapling')
        zaddrExt = self.nodes[2].z_getnewaddress('sapling')

        txid_taddr = self.nodes[0].sendtoaddress(taddr, 4.0)
        self.generate_and_sync(height + 2)

        # Send 1 ZEC to zaddr1
        opid = self.nodes[1].z_sendmany(taddr, [
            {
                'address': zaddr1,
                'amount': 1,
                'memo': my_memo
            },
            {
                'address': zaddrExt,
                'amount': 2
            },
        ])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()

        # Decrypted transaction details should be correct
        pt = self.nodes[1].z_viewtransaction(txid)

        assert_equal(pt['txid'], txid)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 2)

        # Outputs are not returned in a defined order but the amounts are deterministic
        outputs = sorted(pt['outputs'], key=lambda x: x['valueZat'])
        assert_equal(outputs[0]['type'], 'sapling')
        assert_equal(outputs[0]['address'], zaddr1)
        assert_equal(outputs[0]['value'], Decimal('1'))
        assert_equal(outputs[0]['valueZat'], 100000000)
        assert_equal(outputs[0]['output'], 0)
        assert_equal(outputs[0]['outgoing'], False)
        assert_equal(outputs[0]['memo'], my_memo)
        assert_equal(outputs[0]['memoStr'], my_memo_str)

        assert_equal(outputs[1]['type'], 'sapling')
        assert_equal(outputs[1]['address'], zaddrExt)
        assert_equal(outputs[1]['value'], Decimal('2'))
        assert_equal(outputs[1]['valueZat'], 200000000)
        assert_equal(outputs[1]['output'], 1)
        assert_equal(outputs[1]['outgoing'], True)
        assert_equal(outputs[1]['memo'], no_memo)
        assert 'memoStr' not in outputs[1]

        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")
        c = self.nodes[1].z_getnotescount()
        assert_equal(0, c['sapling'], "Count of confirmed notes should be 0")

        # No confirmation required, one note should be present
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(1, len(r), "Should have received one (unconfirmed) note")
        assert_equal(txid, r[0]['txid'])
        assert_equal(1, r[0]['amount'])
        assert_equal(100000000, r[0]['amountZat'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(my_memo, r[0]['memo'])
        assert_equal(0, r[0]['confirmations'])
        assert_equal(-1, r[0]['blockindex'])
        assert_equal(0, r[0]['blockheight'])

        c = self.nodes[1].z_getnotescount(0)
        assert_equal(1, c['sapling'], "Count of unconfirmed notes should be 1")

        # Confirm transaction (1 ZEC from taddr to zaddr1)
        self.generate_and_sync(height + 3)

        # adjust confirmations
        r[0]['confirmations'] = 1
        # adjust blockindex
        r[0]['blockindex'] = 1
        # adjust height
        r[0]['blockheight'] = height + 3

        # Require one confirmation, note should be present
        assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1))

        # Generate some change by sending part of zaddr1 to zaddr2
        txidPrev = txid
        zaddr2 = self.nodes[1].z_getnewaddress('sapling')
        opid = self.nodes[1].z_sendmany(zaddr1, [{
            'address': zaddr2,
            'amount': 0.6
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        self.generate_and_sync(height + 4)

        # Decrypted transaction details should be correct
        pt = self.nodes[1].z_viewtransaction(txid)
        assert_equal(pt['txid'], txid)
        assert_equal(len(pt['spends']), 1)
        assert_equal(len(pt['outputs']), 2)

        assert_equal(pt['spends'][0]['type'], 'sapling')
        assert_equal(pt['spends'][0]['txidPrev'], txidPrev)
        assert_equal(pt['spends'][0]['spend'], 0)
        assert_equal(pt['spends'][0]['outputPrev'], 0)
        assert_equal(pt['spends'][0]['address'], zaddr1)
        assert_equal(pt['spends'][0]['value'], Decimal('1.0'))
        assert_equal(pt['spends'][0]['valueZat'], 100000000)

        # Outputs are not returned in a defined order but the amounts are deterministic
        outputs = sorted(pt['outputs'], key=lambda x: x['valueZat'])
        assert_equal(outputs[0]['type'], 'sapling')
        assert_equal(outputs[0]['address'], zaddr1)
        assert_equal(outputs[0]['value'], Decimal('0.4') - DEFAULT_FEE)
        assert_equal(outputs[0]['valueZat'], 40000000 - DEFAULT_FEE_ZATS)
        assert_equal(outputs[0]['output'], 1)
        assert_equal(outputs[0]['outgoing'], False)
        assert_equal(outputs[0]['memo'], no_memo)
        assert 'memoStr' not in outputs[0]

        assert_equal(outputs[1]['type'], 'sapling')
        assert_equal(outputs[1]['address'], zaddr2)
        assert_equal(outputs[1]['value'], Decimal('0.6'))
        assert_equal(outputs[1]['valueZat'], 60000000)
        assert_equal(outputs[1]['output'], 0)
        assert_equal(outputs[1]['outgoing'], False)
        assert_equal(outputs[1]['memo'], no_memo)
        assert 'memoStr' not in outputs[1]

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.4') - DEFAULT_FEE, r[0]['amount'])
        assert_equal(40000000 - DEFAULT_FEE_ZATS, r[0]['amountZat'])
        assert_equal(
            r[0]['change'], True,
            "Note valued at (0.4-" + str(DEFAULT_FEE) + ") should be change")
        assert_equal(no_memo, r[0]['memo'])

        # The old note still exists (it's immutable), even though it is spent
        assert_equal(Decimal('1.0'), r[1]['amount'])
        assert_equal(100000000, r[1]['amountZat'])
        assert_equal(r[1]['change'], False,
                     "Note valued at 1.0 should not be change")
        assert_equal(my_memo, r[1]['memo'])

        # zaddr2 should not have change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0)
        assert_equal(len(r), 1, "zaddr2 Should have received 1 notes")
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(r[0]['txid'], txid)
        assert_equal(r[0]['amount'], Decimal('0.6'))
        assert_equal(r[0]['amountZat'], 60000000)
        assert_equal(r[0]['change'], False,
                     "Note valued at 0.6 should not be change")
        assert_equal(r[0]['memo'], no_memo)
        assert 0 <= r[0]['outindex'] < 2

        c = self.nodes[1].z_getnotescount(0)
        assert_equal(
            c['sapling'], 3,
            "Count of unconfirmed notes should be 3(2 in zaddr1 + 1 in zaddr2)"
        )

        # As part of UA support, a transparent address is now accepted
        r = self.nodes[1].z_listreceivedbyaddress(taddr, 0)
        assert_equal(len(r), 1)
        assert_equal(r[0]['pool'], 'transparent')
        assert_equal(r[0]['txid'], txid_taddr)
        assert_equal(r[0]['amount'], Decimal('4'))
        assert_equal(r[0]['amountZat'], 400000000)
        assert_equal(r[0]['confirmations'], 3)
        assert 0 <= r[0]['outindex'] < 2

        # Test unified address
        node = self.nodes[1]

        # Create a unified address on one node, try z_listreceivedbyaddress on another node
        account = self.nodes[0].z_getnewaccount()['account']
        r = self.nodes[0].z_getaddressforaccount(account)
        unified_addr = r['address']
        # this address isn't in node1's wallet
        assert_raises_message(JSONRPCException,
                              "From address does not belong to this node",
                              node.z_listreceivedbyaddress, unified_addr, 0)

        # create a UA on node1
        r = node.z_getnewaccount()
        account = r['account']
        r = node.z_getaddressforaccount(account)
        unified_addr = r['address']
        receivers = node.z_listunifiedreceivers(unified_addr)
        assert_equal(len(receivers), 3)
        assert 'p2pkh' in receivers
        assert 'sapling' in receivers
        assert 'orchard' in receivers
        assert_raises_message(
            JSONRPCException,
            "The provided address is a bare receiver from a Unified Address in this wallet.",
            node.z_listreceivedbyaddress, receivers['p2pkh'], 0)
        assert_raises_message(
            JSONRPCException,
            "The provided address is a bare receiver from a Unified Address in this wallet.",
            node.z_listreceivedbyaddress, receivers['sapling'], 0)

        # Wallet contains no notes
        r = node.z_listreceivedbyaddress(unified_addr, 0)
        assert_equal(len(r), 0, "unified_addr should have received zero notes")

        # Create a note in this UA on node1
        opid = node.z_sendmany(zaddr1, [{
            'address': unified_addr,
            'amount': 0.1
        }])
        txid_sapling = wait_and_assert_operationid_status(node, opid)
        self.generate_and_sync(height + 5)

        # Create a UTXO that unified_address's transparent component references, on node1
        outputs = {receivers['p2pkh']: 0.2}
        txid_taddr = node.sendmany("", outputs)

        r = node.z_listreceivedbyaddress(unified_addr, 0)
        assert_equal(len(r), 2, "unified_addr should have received 2 payments")
        # The return list order isn't defined, so sort by pool name
        r = sorted(r, key=lambda x: x['pool'])
        assert_equal(r[0]['pool'], 'sapling')
        assert_equal(r[0]['txid'], txid_sapling)
        assert_equal(r[0]['amount'], Decimal('0.1'))
        assert_equal(r[0]['amountZat'], 10000000)
        assert_equal(r[0]['memo'], no_memo)
        assert 0 <= r[0]['outindex'] < 2
        assert_equal(r[0]['confirmations'], 1)
        assert_equal(r[0]['change'], False)
        assert_equal(r[0]['blockheight'], height + 5)
        assert_equal(r[0]['blockindex'], 1)
        assert 'blocktime' in r[0]

        assert_equal(r[1]['pool'], 'transparent')
        assert_equal(r[1]['txid'], txid_taddr)
        assert_equal(r[1]['amount'], Decimal('0.2'))
        assert_equal(r[1]['amountZat'], 20000000)
        assert 0 <= r[1]['outindex'] < 2
        assert_equal(r[1]['confirmations'], 0)
        assert_equal(r[1]['change'], False)
        assert 'memo' not in r[1]
        assert_equal(r[1]['blockheight'], 0)  # not yet mined
        assert_equal(r[1]['blockindex'], -1)  # not yet mined
        assert 'blocktime' in r[1]
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)")

        # Send will fail because send amount is too big, even when including coinbase utxos
        errorString = ""
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert_equal("Insufficient funds" in errorString, True)

        # z_sendmany will fail because of insufficient funds
        recipients = []
        recipients.append({"address":self.nodes[1].getnewaddress(), "amount":Decimal('10000.0')})
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001")
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient shielded funds, have 9.9998, need 10000.0001")

        # Send will fail because of insufficient funds unless sender uses coinbase utxos
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert_equal("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr" in errorString, True)

        # Verify that mempools accept tx with joinsplits which have at least the default z_sendmany fee.
        # If this test passes, it confirms that issue #1851 has been resolved, where sending from
        # a zaddr to 1385 taddr recipients fails because the default fee was considered too low
        # given the tx size, resulting in mempool rejection.
        errorString = ''
    def test_received_orchard(self, height):
        self.generate_and_sync(height + 1)
        taddr = self.nodes[1].getnewaddress()
        acct1 = self.nodes[1].z_getnewaccount()['account']
        acct2 = self.nodes[1].z_getnewaccount()['account']

        addrResO = self.nodes[1].z_getaddressforaccount(acct1, ['orchard'])
        assert_equal(addrResO['receiver_types'], ['orchard'])
        uao = addrResO['address']

        addrResSO = self.nodes[1].z_getaddressforaccount(
            acct2, ['sapling', 'orchard'])
        assert_equal(addrResSO['receiver_types'], ['sapling', 'orchard'])
        uaso = addrResSO['address']

        self.nodes[0].sendtoaddress(taddr, 4.0)
        self.generate_and_sync(height + 2)

        acct_node0 = self.nodes[0].z_getnewaccount()['account']
        ua_node0 = self.nodes[0].z_getaddressforaccount(
            acct_node0, ['sapling', 'orchard'])['address']

        opid = self.nodes[1].z_sendmany(taddr, [
            {
                'address': uao,
                'amount': 1,
                'memo': my_memo
            },
            {
                'address': uaso,
                'amount': 2
            },
        ], 1, 0, 'AllowRevealedSenders')
        txid0 = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()

        # Decrypted transaction details should be correct, even though
        # the transaction is still just in the mempool
        pt = self.nodes[1].z_viewtransaction(txid0)

        assert_equal(pt['txid'], txid0)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 2)

        # Outputs are not returned in a defined order but the amounts are deterministic
        outputs = sorted(pt['outputs'], key=lambda x: x['valueZat'])
        assert_equal(outputs[0]['type'], 'orchard')
        assert_equal(outputs[0]['address'], uao)
        assert_equal(outputs[0]['value'], Decimal('1'))
        assert_equal(outputs[0]['valueZat'], 100000000)
        assert_equal(outputs[0]['outgoing'], False)
        assert_equal(outputs[0]['memo'], my_memo)
        assert_equal(outputs[0]['memoStr'], my_memo_str)
        actionToSpend = outputs[0]['action']

        assert_equal(outputs[1]['type'], 'orchard')
        assert_equal(outputs[1]['address'], uaso)
        assert_equal(outputs[1]['value'], Decimal('2'))
        assert_equal(outputs[1]['valueZat'], 200000000)
        assert_equal(outputs[1]['outgoing'], False)
        assert_equal(outputs[1]['memo'], no_memo)
        assert 'memoStr' not in outputs[1]

        self.generate_and_sync(height + 3)

        opid = self.nodes[1].z_sendmany(uao, [{
            'address': uaso,
            'amount': Decimal('0.3')
        }, {
            'address': ua_node0,
            'amount': Decimal('0.2')
        }])
        txid1 = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()

        pt = self.nodes[1].z_viewtransaction(txid1)

        assert_equal(pt['txid'], txid1)
        assert_equal(len(pt['spends']), 1)  # one spend we can see
        assert_equal(len(pt['outputs']),
                     3)  # one output + one change output we can see

        spends = pt['spends']
        assert_equal(spends[0]['type'], 'orchard')
        assert_equal(spends[0]['txidPrev'], txid0)
        assert_equal(spends[0]['actionPrev'], actionToSpend)
        assert_equal(spends[0]['address'], uao)
        assert_equal(spends[0]['value'], Decimal('1.0'))
        assert_equal(spends[0]['valueZat'], 100000000)

        outputs = sorted(pt['outputs'], key=lambda x: x['valueZat'])
        assert_equal(outputs[0]['type'], 'orchard')
        assert_equal(outputs[0]['address'], ua_node0)
        assert_equal(outputs[0]['value'], Decimal('0.2'))
        assert_equal(outputs[0]['valueZat'], 20000000)
        assert_equal(outputs[0]['outgoing'], True)
        assert_equal(outputs[0]['walletInternal'], False)
        assert_equal(outputs[0]['memo'], no_memo)

        assert_equal(outputs[1]['type'], 'orchard')
        assert_equal(outputs[1]['address'], uaso)
        assert_equal(outputs[1]['value'], Decimal('0.3'))
        assert_equal(outputs[1]['valueZat'], 30000000)
        assert_equal(outputs[1]['outgoing'], False)
        assert_equal(outputs[1]['walletInternal'], False)
        assert_equal(outputs[1]['memo'], no_memo)

        # Verify that we observe the change output
        assert_equal(outputs[2]['type'], 'orchard')
        assert_equal(outputs[2]['value'], Decimal('0.49999'))
        assert_equal(outputs[2]['valueZat'], 49999000)
        assert_equal(outputs[2]['outgoing'], False)
        assert_equal(outputs[2]['walletInternal'], True)
        assert_equal(outputs[2]['memo'], no_memo)
        # The change address should have been erased
        assert_true('address' not in outputs[2])
Exemple #28
0
    def run_test(self):
        self.nodes[0].generate(1)
        self.sync_all()

        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress('sprout')
        zaddr2 = self.nodes[1].z_getnewaddress('sprout')

        self.nodes[0].sendtoaddress(taddr, Decimal('1.0'))
        self.generate_and_sync()

        # Send 1 ZEC to a zaddr
        wait_and_assert_operationid_status(
            self.nodes[1], self.nodes[1].z_sendmany(taddr, [{
                'address': zaddr1,
                'amount': 1.0,
                'memo': 'c0ffee01'
            }], 1, 0))
        self.generate_and_sync()

        # Check that we have received 1 note which is not change
        receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        listunspent = self.nodes[1].z_listunspent()
        assert_equal(1, len(receivedbyaddress), "Should have received 1 note")
        assert_false(receivedbyaddress[0]['change'],
                     "Note should not be change")
        assert_equal(1, len(listunspent), "Should have 1 unspent note")
        assert_false(listunspent[0]['change'],
                     "Unspent note should not be change")

        # Generate some change
        wait_and_assert_operationid_status(
            self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{
                'address': zaddr2,
                'amount': 0.6,
                'memo': 'c0ffee02'
            }], 1, 0))
        self.generate_and_sync()

        # Check zaddr1 received
        sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(
            zaddr1, 0),
                                 key=lambda received: received['amount'])
        assert_equal(2, len(sortedreceived1),
                     "zaddr1 Should have received 2 notes")
        assert_equal(Decimal('0.4'), sortedreceived1[0]['amount'])
        assert_true(sortedreceived1[0]['change'],
                    "Note valued at 0.4 should be change")
        assert_equal(Decimal('1.0'), sortedreceived1[1]['amount'])
        assert_false(sortedreceived1[1]['change'],
                     "Note valued at 1.0 should not be change")
        # Check zaddr2 received
        sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(
            zaddr2, 0),
                                 key=lambda received: received['amount'])
        assert_equal(1, len(sortedreceived2),
                     "zaddr2 Should have received 1 notes")
        assert_equal(Decimal('0.6'), sortedreceived2[0]['amount'])
        assert_false(sortedreceived2[0]['change'],
                     "Note valued at 0.6 should not be change")
        # Check unspent
        sortedunspent = sorted(self.nodes[1].z_listunspent(),
                               key=lambda received: received['amount'])
        assert_equal(2, len(sortedunspent), "Should have 2 unspent notes")
        assert_equal(Decimal('0.4'), sortedunspent[0]['amount'])
        assert_true(sortedunspent[0]['change'],
                    "Unspent note valued at 0.4 should be change")
        assert_equal(Decimal('0.6'), sortedunspent[1]['amount'])
        assert_false(sortedunspent[1]['change'],
                     "Unspent note valued at 0.6 should not be change")

        # Give node 0 a viewing key
        viewing_key = self.nodes[1].z_exportviewingkey(zaddr1)
        self.nodes[0].z_importviewingkey(viewing_key)
        received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(received_node0))
        unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True)
        assert_equal(2, len(unspent_node0))
        # node 0 only has a viewing key so does not see the change field
        assert_false('change' in received_node0[0])
        assert_false('change' in received_node0[1])
        assert_false('change' in unspent_node0[0])
        assert_false('change' in unspent_node0[1])
    def test_received_sprout(self, height):
        self.generate_and_sync(height + 2)

        zaddr1 = self.nodes[1].z_getnewaddress('sprout')

        # Send 10 ZEC each zaddr1 and zaddrExt via z_shieldcoinbase
        result = self.nodes[0].z_shieldcoinbase(
            get_coinbase_address(self.nodes[0]), zaddr1, 0, 1)
        txid_shielding1 = wait_and_assert_operationid_status(
            self.nodes[0], result['opid'])

        zaddrExt = self.nodes[2].z_getnewaddress('sprout')
        result = self.nodes[0].z_shieldcoinbase(
            get_coinbase_address(self.nodes[0]), zaddrExt, 0, 1)
        txid_shieldingExt = wait_and_assert_operationid_status(
            self.nodes[0], result['opid'])

        self.sync_all()

        # Decrypted transaction details should not be visible on node 0
        pt = self.nodes[0].z_viewtransaction(txid_shielding1)
        assert_equal(pt['txid'], txid_shielding1)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 0)

        # Decrypted transaction details should be correct on node 1
        pt = self.nodes[1].z_viewtransaction(txid_shielding1)
        assert_equal(pt['txid'], txid_shielding1)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 1)
        assert_equal(pt['outputs'][0]['type'], 'sprout')
        assert_equal(pt['outputs'][0]['js'], 0)
        assert_equal(pt['outputs'][0]['address'], zaddr1)
        assert_equal(pt['outputs'][0]['value'], Decimal('10'))
        assert_equal(pt['outputs'][0]['valueZat'], 1000000000)
        assert_equal(pt['outputs'][0]['memo'], no_memo)
        jsOutputPrev = pt['outputs'][0]['jsOutput']

        # Second transaction should not be known to node 1
        assert_raises_message(JSONRPCException,
                              "Invalid or non-wallet transaction id",
                              self.nodes[1].z_viewtransaction,
                              txid_shieldingExt)

        # Second transaction should be visible on node0
        pt = self.nodes[2].z_viewtransaction(txid_shieldingExt)
        assert_equal(pt['txid'], txid_shieldingExt)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 1)
        assert_equal(pt['outputs'][0]['type'], 'sprout')
        assert_equal(pt['outputs'][0]['js'], 0)
        assert_equal(pt['outputs'][0]['address'], zaddrExt)
        assert_equal(pt['outputs'][0]['value'], Decimal('10'))
        assert_equal(pt['outputs'][0]['valueZat'], 1000000000)
        assert_equal(pt['outputs'][0]['memo'], no_memo)

        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")
        c = self.nodes[1].z_getnotescount()
        assert_equal(0, c['sprout'], "Count of confirmed notes should be 0")

        # No confirmation required, one note should be present
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(1, len(r), "Should have received one (unconfirmed) note")
        assert_equal(txid_shielding1, r[0]['txid'])
        assert_equal(10, r[0]['amount'])
        assert_equal(1000000000, r[0]['amountZat'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(no_memo, r[0]['memo'])
        assert_equal(0, r[0]['confirmations'])
        assert_equal(-1, r[0]['blockindex'])
        assert_equal(0, r[0]['blockheight'])

        c = self.nodes[1].z_getnotescount(0)
        assert_equal(1, c['sprout'], "Count of unconfirmed notes should be 1")

        # Confirm transaction (10 ZEC shielded)
        self.generate_and_sync(height + 3)

        # Require one confirmation, note should be present
        r0 = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(1, len(r0), "Should have received one (unconfirmed) note")
        assert_equal(txid_shielding1, r0[0]['txid'])
        assert_equal(10, r0[0]['amount'])
        assert_equal(1000000000, r0[0]['amountZat'])
        assert_false(r0[0]['change'], "Note should not be change")
        assert_equal(no_memo, r0[0]['memo'])
        assert_equal(1, r0[0]['confirmations'])
        assert_equal(height + 3, r0[0]['blockheight'])

        taddr = self.nodes[1].getnewaddress()
        # Generate some change by sending part of zaddr1 back to taddr
        opid = self.nodes[1].z_sendmany(zaddr1, [{
            'address': taddr,
            'amount': 0.6
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)

        self.generate_and_sync(height + 4)

        # Decrypted transaction details should be correct
        pt = self.nodes[1].z_viewtransaction(txid)
        assert_equal(pt['txid'], txid)
        assert_equal(len(pt['spends']), 1)
        # TODO: enable once z_viewtransaction displays transparent elements
        # assert_equal(len(pt['outputs']), 2)
        assert_equal(len(pt['outputs']), 1)

        assert_equal(pt['spends'][0]['type'], 'sprout')
        assert_equal(pt['spends'][0]['txidPrev'], txid_shielding1)
        assert_equal(pt['spends'][0]['js'], 0)
        assert_equal(pt['spends'][0]['jsPrev'], 0)
        assert_equal(pt['spends'][0]['jsOutputPrev'], jsOutputPrev)
        assert_equal(pt['spends'][0]['address'], zaddr1)
        assert_equal(pt['spends'][0]['value'], Decimal('10.0'))
        assert_equal(pt['spends'][0]['valueZat'], 1000000000)

        # We expect a transparent output and a Sprout output, but the RPC does
        # not define any particular ordering of these within the returned JSON.
        outputs = [{
            'type': output['type'],
            'address': output['address'],
            'value': output['value'],
            'valueZat': output['valueZat'],
        } for output in pt['outputs']]
        for (i, output) in enumerate(pt['outputs']):
            if 'memo' in output:
                outputs[i]['memo'] = output['memo']

        # TODO: enable once z_viewtransaction displays transparent elements
        # assert({
        #     'type': 'transparent',
        #     'address': taddr,
        #     'value': Decimal('0.6'),
        #     'valueZat': 60000000,
        # } in outputs)
        assert ({
            'type': 'sprout',
            'address': zaddr1,
            'value': Decimal('9.4') - DEFAULT_FEE,
            'valueZat': 940000000 - DEFAULT_FEE_ZATS,
            'memo': no_memo,
        } in outputs)

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('9.4') - DEFAULT_FEE, r[0]['amount'])
        assert_equal(940000000 - DEFAULT_FEE_ZATS, r[0]['amountZat'])
        assert_true(
            r[0]['change'],
            "Note valued at (9.4-" + str(DEFAULT_FEE) + ") should be change")
        assert_equal(no_memo, r[0]['memo'])

        # The old note still exists (it's immutable), even though it is spent
        assert_equal(Decimal('10.0'), r[1]['amount'])
        assert_equal(1000000000, r[1]['amountZat'])
        assert_false(r[1]['change'],
                     "Note valued at 10.0 should not be change")
        assert_equal(no_memo, r[1]['memo'])
Exemple #30
0
class WalletShieldingCoinbaseTest(BitcoinTestFramework):
    def setup_chain(self):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, 4)

    # Start nodes with -regtestshieldcoinbase to set fCoinbaseMustBeShielded to true.
    def setup_network(self, split=False):
        self.nodes = start_nodes(
            4,
            self.options.tmpdir,
            extra_args=[['-regtestshieldcoinbase', '-debug=zrpcunsafe']] * 4)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        connect_nodes_bi(self.nodes, 0, 3)
        self.is_network_split = False
        self.sync_all()

    def run_test(self):
        print "Mining blocks..."

        self.nodes[0].generate(4)
        self.sync_all()

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 40)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), 40)
        assert_equal(self.nodes[1].getbalance(), 10)
        assert_equal(self.nodes[2].getbalance(), 0)
        assert_equal(self.nodes[3].getbalance(), 0)

        check_value_pool(self.nodes[0], 'sprout', 0)
        check_value_pool(self.nodes[1], 'sprout', 0)
        check_value_pool(self.nodes[2], 'sprout', 0)
        check_value_pool(self.nodes[3], 'sprout', 0)

        # Send will fail because we are enforcing the consensus rule that
        # coinbase utxos can only be sent to a zaddr.
        errorString = ""
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1)
        except JSONRPCException, e:
            errorString = e.error['message']
        assert_equal(
            "Coinbase funds can only be sent to a zaddr" in errorString, True)

        # Prepare to send taddr->zaddr
        mytaddr = get_coinbase_address(self.nodes[0])
        myzaddr = self.nodes[0].z_getnewaddress('sprout')

        # Node 3 will test that watch only address utxos are not selected
        self.nodes[3].importaddress(mytaddr)
        recipients = [{"address": myzaddr, "amount": Decimal('1')}]
        myopid = self.nodes[3].z_sendmany(mytaddr, recipients)

        wait_and_assert_operationid_status(
            self.nodes[3], myopid, "failed",
            "Insufficient funds, no UTXOs found for taddr from address.", 10)

        # This send will fail because our wallet does not allow any change when shielding a coinbase utxo,
        # as it's currently not possible to specify a change address in z_sendmany.
        recipients = []
        recipients.append({
            "address": myzaddr,
            "amount": Decimal('1.23456789')
        })

        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        error_result = wait_and_assert_operationid_status_result(
            self.nodes[0], myopid, "failed",
            ("Change 8.76533211 not allowed. "
             "When shielding coinbase funds, the wallet does not allow any change "
             "as there is currently no way to specify a change address in z_sendmany."
             ), 10)

        # Test that the returned status object contains a params field with the operation's input parameters
        assert_equal(error_result["method"], "z_sendmany")
        params = error_result["params"]
        assert_equal(params["fee"], Decimal('0.0001'))  # default
        assert_equal(params["minconf"], Decimal('1'))  # default
        assert_equal(params["fromaddress"], mytaddr)
        assert_equal(params["amounts"][0]["address"], myzaddr)
        assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789'))

        # Add viewing key for myzaddr to Node 3
        myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr)
        self.nodes[3].z_importviewingkey(myviewingkey, "no")

        # This send will succeed.  We send two coinbase utxos totalling 20.0 less a fee of 0.00010000, with no change.
        shieldvalue = Decimal('20.0') - Decimal('0.0001')
        recipients = []
        recipients.append({"address": myzaddr, "amount": shieldvalue})
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()

        # Verify that z_listunspent can return a note that has zero confirmations
        results = self.nodes[0].z_listunspent()
        assert (len(results) == 0)
        results = self.nodes[0].z_listunspent(0)  # set minconf to zero
        assert (len(results) == 1)
        assert_equal(results[0]["address"], myzaddr)
        assert_equal(results[0]["amount"], shieldvalue)
        assert_equal(results[0]["confirmations"], 0)

        # Mine the tx
        self.nodes[1].generate(1)
        self.sync_all()

        # Verify that z_listunspent returns one note which has been confirmed
        results = self.nodes[0].z_listunspent()
        assert (len(results) == 1)
        assert_equal(results[0]["address"], myzaddr)
        assert_equal(results[0]["amount"], shieldvalue)
        assert_equal(results[0]["confirmations"], 1)
        assert_equal(results[0]["spendable"], True)

        # Verify that z_listunspent returns note for watchonly address on node 3.
        results = self.nodes[3].z_listunspent(1, 999, True)
        assert (len(results) == 1)
        assert_equal(results[0]["address"], myzaddr)
        assert_equal(results[0]["amount"], shieldvalue)
        assert_equal(results[0]["confirmations"], 1)
        assert_equal(results[0]["spendable"], False)

        # Verify that z_listunspent returns error when address spending key from node 0 is not available in wallet of node 1.
        try:
            results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr])
        except JSONRPCException as e:
            errorString = e.error['message']
        assert_equal(
            "Invalid parameter, spending key for address does not belong to wallet"
            in errorString, True)

        # Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid
        logpath = self.options.tmpdir + "/node0/regtest/debug.log"
        logcounter = 0
        with open(logpath, "r") as myfile:
            logdata = myfile.readlines()
        for logline in logdata:
            if myopid + ": z_sendmany initialized" in logline and mytaddr in logline and myzaddr in logline:
                assert_equal(logcounter, 0)  # verify order of log messages
                logcounter = logcounter + 1
            if myopid + ": z_sendmany finished" in logline and mytxid in logline:
                assert_equal(logcounter, 1)
                logcounter = logcounter + 1
        assert_equal(logcounter, 2)

        # check balances (the z_sendmany consumes 3 coinbase utxos)
        resp = self.nodes[0].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
        assert_equal(Decimal(resp["private"]), Decimal('19.9999'))
        assert_equal(Decimal(resp["total"]), Decimal('39.9999'))

        # The Sprout value pool should reflect the send
        sproutvalue = shieldvalue
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        # A custom fee of 0 is okay.  Here the node will send the note value back to itself.
        recipients = []
        recipients.append({"address": myzaddr, "amount": Decimal('19.9999')})
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1,
                                          Decimal('0.0'))
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        resp = self.nodes[0].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
        assert_equal(Decimal(resp["private"]), Decimal('19.9999'))
        assert_equal(Decimal(resp["total"]), Decimal('39.9999'))

        # The Sprout value pool should be unchanged
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        # convert note to transparent funds
        unshieldvalue = Decimal('10.0')
        recipients = []
        recipients.append({"address": mytaddr, "amount": unshieldvalue})
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
        mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        assert (mytxid is not None)
        self.sync_all()

        # check that priority of the tx sending from a zaddr is not 0
        mempool = self.nodes[0].getrawmempool(True)
        assert (Decimal(mempool[mytxid]['startingpriority']) >=
                Decimal('1000000000000'))

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

        # check balances
        sproutvalue -= unshieldvalue + Decimal('0.0001')
        resp = self.nodes[0].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), Decimal('30.0'))
        assert_equal(Decimal(resp["private"]), Decimal('9.9998'))
        assert_equal(Decimal(resp["total"]), Decimal('39.9998'))
        check_value_pool(self.nodes[0], 'sprout', sproutvalue)

        # z_sendmany will return an error if there is transparent change output considered dust.
        # UTXO selection in z_sendmany sorts in ascending order, so smallest utxos are consumed first.
        # At this point in time, unspent notes all have a value of 10.0 and standard z_sendmany fee is 0.0001.
        recipients = []
        amount = Decimal('10.0') - Decimal('0.00010000') - Decimal(
            '0.00000001'
        )  # this leaves change at 1 zatoshi less than dust threshold
        recipients.append({
            "address": self.nodes[0].getnewaddress(),
            "amount": amount
        })
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(
            self.nodes[0], myopid, "failed",
            "Insufficient transparent funds, have 10.00, need 0.00000053 more to avoid creating invalid change output 0.00000001 (dust threshold is 0.00000054)"
        )

        # Send will fail because send amount is too big, even when including coinbase utxos
        errorString = ""
        try:
            self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999)
        except JSONRPCException, e:
            errorString = e.error['message']
Exemple #31
0
 def send_to_sprout_zaddr(self, tAddr, sproutAddr):
     # Send some ZEC to a Sprout address
     opid = self.nodes[0].z_sendmany(tAddr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0)
     wait_and_assert_operationid_status(self.nodes[0], opid)
     self.nodes[0].generate(1)
     self.sync_all()
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(4)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], self._reward * 4)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), self._reward * 4)
        assert_equal(self.nodes[1].getbalance(), self._reward * 2)
        assert_equal(self.nodes[2].getbalance(), 0)

        # At this point in time, commitment tree is the empty root

        # Node 0 creates a joinsplit transaction
        mytaddr0 = self.nodes[0].getnewaddress()
        myzaddr0 = self.nodes[0].z_getnewaddress('sprout')
        recipients = []
        recipients.append({
            "address": myzaddr0,
            "amount": self._reward - self._fee
        })
        myopid = self.nodes[0].z_sendmany(mytaddr0, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Sync up mempools and mine the transaction.  All nodes have the same anchor.
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Stop nodes.
        stop_nodes(self.nodes)
        wait_bitcoinds()

        # Relaunch nodes and partition network into two:
        # A: node 0
        # B: node 1, 2
        self.nodes = start_nodes(3,
                                 self.options.tmpdir,
                                 extra_args=[['-debug=zrpc']] * 3)
        connect_nodes_bi(self.nodes, 1, 2)

        # Partition B, node 1 mines an empty block
        self.nodes[1].generate(1)

        # Partition A, node 0 creates a joinsplit transaction
        recipients = []
        recipients.append({
            "address": myzaddr0,
            "amount": self._reward - self._fee
        })
        myopid = self.nodes[0].z_sendmany(mytaddr0, recipients)
        txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        rawhex = self.nodes[0].getrawtransaction(txid)

        # Partition A, node 0 mines a block with the transaction
        self.nodes[0].generate(1)

        # Partition B, node 1 mines the same joinsplit transaction
        txid2 = self.nodes[1].sendrawtransaction(rawhex)
        assert_equal(txid, txid2)
        self.nodes[1].generate(1)

        # Check that Partition B is one block ahead and that they have different tips
        assert_equal(self.nodes[0].getblockcount() + 1,
                     self.nodes[1].getblockcount())
        assert (self.nodes[0].getbestblockhash() !=
                self.nodes[1].getbestblockhash())

        # Shut down all nodes so any in-memory state is saved to disk
        stop_nodes(self.nodes)
        wait_bitcoinds()

        # Relaunch nodes and reconnect the entire network
        self.nodes = start_nodes(3,
                                 self.options.tmpdir,
                                 extra_args=[['-debug=zrpc']] * 3)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)

        # Mine a new block and let it propagate
        self.nodes[1].generate(1)

        # Due to a bug in v1.0.0-1.0.3, node 0 will die with a tree root assertion, so sync_all() will throw an exception.
        self.sync_all()

        # v1.0.4 will reach here safely
        assert_equal(self.nodes[0].getbestblockhash(),
                     self.nodes[1].getbestblockhash())
        assert_equal(self.nodes[1].getbestblockhash(),
                     self.nodes[2].getbestblockhash())
    def run_test(self):
        print "Mining blocks..."

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

        mytaddr = self.nodes[0].getnewaddress()  # where coins were mined
        myzaddr = self.nodes[0].z_getnewaddress()

        # Spend coinbase utxos to create three notes of 9.99990000 each
        recipients = []
        recipients.append({
            "address": myzaddr,
            "amount": Decimal(self._coin) - Decimal('0.0001')
        })
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Check balance
        resp = self.nodes[0].z_getbalance(myzaddr)
        assert_equal(Decimal(resp),
                     (Decimal(self._coin) - Decimal('0.0001')) * 3)

        # We want to test a real-world situation where during the time spent creating a transaction
        # with joinsplits, other transactions containing joinsplits have been mined into new blocks,
        # which result in the treestate changing whilst creating the transaction.

        # Tx 1 will change the treestate while Tx 2 containing chained joinsplits is still being generated
        recipients = []
        recipients.append({
            "address": self.nodes[2].z_getnewaddress(),
            "amount": Decimal(self._coin) - Decimal('0.0001')
        })
        myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Tx 2 will consume all three notes, which must take at least two joinsplits.  This is regardless of
        # the z_sendmany implementation because there are only two inputs per joinsplit.
        recipients = []
        recipients.append({
            "address": self.nodes[2].z_getnewaddress(),
            "amount": Decimal('18')
        })
        recipients.append({
            "address":
            self.nodes[2].z_getnewaddress(),
            "amount": (Decimal(self._coin) - Decimal('0.0001')) * 3 -
            Decimal('18') - Decimal('0.0001')
        })
        myopid = self.nodes[0].z_sendmany(myzaddr, recipients)

        # Wait for Tx 2 to begin executing...
        for x in xrange(1, 60):
            results = self.nodes[0].z_getoperationstatus([myopid])
            status = results[0]["status"]
            if status == "executing":
                break
            time.sleep(1)

        # Now mine Tx 1 which will change global treestate before Tx 2's second joinsplit begins processing
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # Wait for Tx 2 to be created
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Note that a bug existed in v1.0.0-1.0.3 where Tx 2 creation would fail with an error:
        # "Witness for spendable note does not have same anchor as change input"

        # Check balance
        resp = self.nodes[0].z_getbalance(myzaddr)
        assert_equal(Decimal(resp), Decimal('0.0'))
    def run_test_release(self, release, height):
        self.generate_and_sync(height+1)
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress(release)

        self.nodes[0].sendtoaddress(taddr, 2.0)
        self.generate_and_sync(height+2)

        # Send 1 ZEC to zaddr1
        opid = self.nodes[1].z_sendmany(taddr,
            [{'address': zaddr1, 'amount': 1, 'memo': my_memo}])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")

        # No confirmation required, one note should be present
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(1, len(r), "Should have received one (unconfirmed) note")
        assert_equal(txid, r[0]['txid'])
        assert_equal(1, r[0]['amount'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(my_memo, r[0]['memo'])

        # Confirm transaction (1 ZEC from taddr to zaddr1)
        self.generate_and_sync(height+3)

        # Require one confirmation, note should be present
        assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1))

        # Generate some change by sending part of zaddr1 to zaddr2
        zaddr2 = self.nodes[1].z_getnewaddress(release)
        opid = self.nodes[1].z_sendmany(zaddr1,
            [{'address': zaddr2, 'amount': 0.6}])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        self.generate_and_sync(height+4)

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        r = sorted(r, key = lambda received: received['amount'])
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")

        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.4')-fee, r[0]['amount'])
        assert_true(r[0]['change'], "Note valued at (0.4-fee) should be change")
        assert_equal(no_memo, r[0]['memo'])

        # The old note still exists (it's immutable), even though it is spent
        assert_equal(Decimal('1.0'), r[1]['amount'])
        assert_false(r[1]['change'], "Note valued at 1.0 should not be change")
        assert_equal(my_memo, r[1]['memo'])

        # zaddr2 should not have change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0)
        r = sorted(r, key = lambda received: received['amount'])
        assert_equal(1, len(r), "zaddr2 Should have received 1 notes")
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.6'), r[0]['amount'])
        assert_false(r[0]['change'], "Note valued at 0.6 should not be change")
        assert_equal(no_memo, r[0]['memo'])
Exemple #35
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)
Exemple #36
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 = self.nodes[0].getnewaddress()
        recipients = []
        recipients.append({"address": sapling_addr, "amount": Decimal('20')})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Verify shielded balance
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20'))
        
        # Verify size of shielded pools
        pools = self.nodes[0].getblockchaininfo()['valuePools']
        assert_equal(pools[0]['chainValue'], Decimal('0'))  # Sprout
        assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
        
        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify size of shielded pools
        pools = self.nodes[0].getblockchaininfo()['valuePools']
        assert_equal(pools[0]['chainValue'], Decimal('0'))  # Sprout
        assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling

        # Node 0 sends some shielded funds to Node 1
        dest_addr = self.nodes[1].z_getnewaddress('sapling')
        recipients = []
        recipients.append({"address": dest_addr, "amount": Decimal('15')})
        myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Verify balances
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15'))

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify balances
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15'))

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

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify nullifiers persisted correctly by checking balance
        # Prior to PR #3590, there will be an error as spent notes are considered unspent:
        #    Assertion failed: expected: <25.00000000> but was: <5>
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5'))

        # Verity witnesses persisted correctly by sending shielded funds
        recipients = []
        recipients.append({"address": dest_addr, "amount": Decimal('1')})
        myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[2], myopid)

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

        # Verify balances
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
        try:
            self.nodes[0].createrawtransaction([], {}, 0, 200)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert_equal("Invalid parameter, expiryheight should be at least 203 to avoid transaction expiring soon" in errorString, True)

        # Node 0 sends transparent funds to Node 3
        tsendamount = Decimal('1.0')
        txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount)
        self.sync_all()

        # Node 3 sends the zero-confirmation transparent funds to Node 1 using z_sendmany
        recipients = []
        recipients.append({"address":taddr1, "amount": Decimal('0.5')})
        myopid = self.nodes[3].z_sendmany(taddr3, recipients, 0)
        txid_zsendmany = wait_and_assert_operationid_status(self.nodes[3], myopid)

        # Node 0 shields to Node 3, a coinbase utxo of value 10.0 less fee 0.00010000
        zsendamount = Decimal('10.0') - Decimal('0.0001')
        recipients = []
        recipients.append({"address":zaddr3, "amount": zsendamount})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients)
        txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Mine the first Overwinter block
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        bci = self.nodes[0].getblockchaininfo()

        # size_on_disk should be > 0
Exemple #38
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'])
Exemple #39
0
    def run_test(self):
        # Current height = 200 -> Sprout
        assert_equal(200, self.nodes[0].getblockcount())

        # test that we can create a sapling zaddr before sapling activates
        saplingzaddr = self.nodes[0].z_getnewaddress('sapling')

        # Set current height to 204 -> Sapling
        self.nodes[0].generate(2)
        self.sync_all()
        assert_equal(204, self.nodes[0].getblockcount())

        # No funds in saplingzaddr yet
        assert_equal(
            0, len(self.nodes[0].z_listunspent(0, 9999, False,
                                               [saplingzaddr])))

        # Send 0.9999 to our sapling zaddr
        # (sending from a sprout zaddr to a sapling zaddr is disallowed,
        # so send from coin base)
        receive_amount_2 = Decimal('2.0') - Decimal('0.0001')
        recipients = [{"address": saplingzaddr, "amount": receive_amount_2}]
        myopid = self.nodes[0].z_sendmany(mining_addr, recipients)
        txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        unspent_tx = self.nodes[0].z_listunspent(0)
        assert_equal(3, len(unspent_tx))

        # low-to-high in amount
        unspent_tx = sorted(unspent_tx, key=lambda k: k['amount'])

        assert_equal(False, unspent_tx[0]['change'])
        assert_equal(txid_2, unspent_tx[0]['txid'])
        assert_equal(True, unspent_tx[0]['spendable'])
        assert_equal(sproutzaddr2, unspent_tx[0]['address'])
        assert_equal(receive_amount_1, unspent_tx[0]['amount'])

        assert_equal(False, unspent_tx[1]['change'])
        assert_equal(txid_3, unspent_tx[1]['txid'])
        assert_equal(True, unspent_tx[1]['spendable'])
        assert_equal(saplingzaddr, unspent_tx[1]['address'])
        assert_equal(receive_amount_2, unspent_tx[1]['amount'])

        assert_equal(True, unspent_tx[2]['change'])
        assert_equal(txid_2, unspent_tx[2]['txid'])
        assert_equal(True, unspent_tx[2]['spendable'])
        assert_equal(sproutzaddr, unspent_tx[2]['address'])
        assert_equal(change_amount_9, unspent_tx[2]['amount'])

        unspent_tx_filter = self.nodes[0].z_listunspent(
            0, 9999, False, [saplingzaddr])
        assert_equal(1, len(unspent_tx_filter))
        assert_equal(unspent_tx[1], unspent_tx_filter[0])

        # test that pre- and post-sapling can be filtered in a single call
        unspent_tx_filter = self.nodes[0].z_listunspent(
            0, 9999, False, [sproutzaddr, saplingzaddr])
        assert_equal(2, len(unspent_tx_filter))
        unspent_tx_filter = sorted(unspent_tx_filter,
                                   key=lambda k: k['amount'])
        assert_equal(unspent_tx[1], unspent_tx_filter[0])
        assert_equal(unspent_tx[2], unspent_tx_filter[1])

        # so far, this node has no watchonly addresses, so results are the same
        unspent_tx_watchonly = self.nodes[0].z_listunspent(0, 9999, True)
        unspent_tx_watchonly = sorted(unspent_tx_watchonly,
                                      key=lambda k: k['amount'])
        assert_equal(unspent_tx, unspent_tx_watchonly)
Exemple #40
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())
 def send_to_sprout_zaddr(self, tAddr, sproutAddr):
     # Send some ZEC to a Sprout address
     opid = self.nodes[0].z_sendmany(tAddr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0)
     wait_and_assert_operationid_status(self.nodes[0], opid)
     self.nodes[0].generate(1)
     self.sync_all()
Exemple #42
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'])
Exemple #43
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 = self.nodes[0].getnewaddress()
        recipients = []
        recipients.append({"address": sapling_addr, "amount": Decimal('20')})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Verify shielded balance
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20'))

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Node 0 sends some shielded funds to Node 1
        dest_addr = self.nodes[1].z_getnewaddress('sapling')
        recipients = []
        recipients.append({"address": dest_addr, "amount": Decimal('15')})
        myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Verify balances
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15'))

        # Verify size of shielded pools
        pools = self.nodes[0].getblockchaininfo()['valuePools']
        assert_equal(pools[0]['chainValue'], Decimal('0'))  # Sprout
        assert_equal(pools[1]['chainValue'], Decimal('20'))  # Sapling

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify size of shielded pools
        pools = self.nodes[0].getblockchaininfo()['valuePools']
        assert_equal(pools[0]['chainValue'], Decimal('0'))  # Sprout
        assert_equal(pools[1]['chainValue'], Decimal('20'))  # Sapling

        # Verify balances
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15'))

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

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify nullifiers persisted correctly by checking balance
        # Prior to PR #3590, there will be an error as spent notes are considered unspent:
        #    Assertion failed: expected: <25.00000000> but was: <5>
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5'))

        # Verity witnesses persisted correctly by sending shielded funds
        recipients = []
        recipients.append({"address": dest_addr, "amount": Decimal('1')})
        myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[2], myopid)

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

        # Verify balances
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
    def run_test(self):
        # add zaddr to node 0
        myzaddr0 = self.nodes[0].z_getnewaddress('sprout')

        # send node 0 taddr to zaddr to get out of coinbase
        # Tests using the default cached chain have one address per coinbase output
        mytaddr = get_coinbase_address(self.nodes[0])
        recipients = []
        recipients.append({
            "address": myzaddr0,
            "amount": Decimal('10.0') - Decimal('0.0001')
        })  # utxo amount less fee

        wait_and_assert_operationid_status(self.nodes[0],
                                           self.nodes[0].z_sendmany(
                                               mytaddr, recipients),
                                           timeout=120)

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

        # add zaddr to node 2
        myzaddr = self.nodes[2].z_getnewaddress('sprout')

        # import node 2 zaddr into node 1
        myzkey = self.nodes[2].z_exportkey(myzaddr)
        self.nodes[1].z_importkey(myzkey)

        # encrypt node 1 wallet and wait to terminate
        self.nodes[1].encryptwallet("test")
        bitcoind_processes[1].wait()

        # restart node 1
        self.nodes[1] = start_node(1, self.options.tmpdir)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        self.sync_all()

        # send node 0 zaddr to note 2 zaddr
        recipients = []
        recipients.append({"address": myzaddr, "amount": 7.0})

        wait_and_assert_operationid_status(self.nodes[0],
                                           self.nodes[0].z_sendmany(
                                               myzaddr0, recipients),
                                           timeout=120)

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

        # check zaddr balance
        zsendmanynotevalue = Decimal('8750.0')
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue)
        assert_equal(self.nodes[1].z_getbalance(myzaddr), zsendmanynotevalue)

        # add zaddr to node 3
        myzaddr3 = self.nodes[3].z_getnewaddress('sprout')

        # send node 2 zaddr to note 3 zaddr
        recipients = []
        recipients.append({"address": myzaddr3, "amount": 2500.0})

        wait_and_assert_operationid_status(self.nodes[2],
                                           self.nodes[2].z_sendmany(
                                               myzaddr, recipients),
                                           timeout=120)

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

        # check zaddr balance
        zsendmany2notevalue = Decimal('2500.0')
        zsendmanyfee = Decimal('0.0001')
        zaddrremaining = zsendmanynotevalue - zsendmany2notevalue - zsendmanyfee
        assert_equal(self.nodes[3].z_getbalance(myzaddr3), zsendmany2notevalue)
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining)

        # Parallel encrypted wallet can't cache nullifiers for received notes,
        # and therefore can't detect spends. So it sees a balance corresponding
        # to the sum of both notes it received (one as change).
        # TODO: Devise a way to avoid this issue (#1528)
        assert_equal(self.nodes[1].z_getbalance(myzaddr),
                     zsendmanynotevalue + zaddrremaining)

        # send node 2 zaddr on node 1 to taddr
        # This requires that node 1 be unlocked, which triggers caching of
        # uncached nullifiers.
        self.nodes[1].walletpassphrase("test", 600)
        mytaddr1 = self.nodes[1].getnewaddress()
        recipients = []
        recipients.append({"address": mytaddr1, "amount": 1250.0})

        wait_and_assert_operationid_status(self.nodes[1],
                                           self.nodes[1].z_sendmany(
                                               myzaddr, recipients),
                                           timeout=120)

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

        # check zaddr balance
        # Now that the encrypted wallet has been unlocked, the note nullifiers
        # have been cached and spent notes can be detected. Thus the two wallets
        # are in agreement once more.
        zsendmany3notevalue = Decimal('1250.0')
        zaddrremaining2 = zaddrremaining - zsendmany3notevalue - zsendmanyfee
        assert_equal(self.nodes[1].z_getbalance(myzaddr), zaddrremaining2)
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining2)

        # Test viewing keys

        node3mined = Decimal('312500.0')
        assert_equal(
            {
                k: Decimal(v)
                for k, v in self.nodes[3].z_gettotalbalance().items()
            }, {
                'transparent': node3mined,
                'private': zsendmany2notevalue,
                'total': node3mined + zsendmany2notevalue,
            })

        # add node 1 address and node 2 viewing key to node 3
        myzvkey = self.nodes[2].z_exportviewingkey(myzaddr)
        self.nodes[3].importaddress(mytaddr1)
        self.nodes[3].z_importviewingkey(myzvkey, 'whenkeyisnew', 1)

        # Check the address has been imported
        assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False)
        assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True)

        # Node 3 should see the same received notes as node 2; however,
        # some of the notes were change for node 2 but not for node 3.
        # Aside from that the recieved notes should be the same. So,
        # group by txid and then check that all properties aside from
        # change are equal.
        node2Received = dict(
            [r['txid'], r]
            for r in self.nodes[2].z_listreceivedbyaddress(myzaddr))
        node3Received = dict(
            [r['txid'], r]
            for r in self.nodes[3].z_listreceivedbyaddress(myzaddr))
        assert_equal(len(node2Received), len(node2Received))
        for txid in node2Received:
            received2 = node2Received[txid]
            received3 = node3Received[txid]
            # the change field will be omitted for received3, but all other fields should be shared
            assert_true(len(received2) >= len(received3))
            for key in received2:
                # check all the properties except for change
                if key != 'change':
                    assert_equal(received2[key], received3[key])

        # Node 3's balances should be unchanged without explicitly requesting
        # to include watch-only balances
        assert_equal(
            {
                k: Decimal(v)
                for k, v in self.nodes[3].z_gettotalbalance().items()
            }, {
                'transparent': node3mined,
                'private': zsendmany2notevalue,
                'total': node3mined + zsendmany2notevalue,
            })

        # Wallet can't cache nullifiers for notes received by addresses it only has a
        # viewing key for, and therefore can't detect spends. So it sees a balance
        # corresponding to the sum of all notes the address received.
        # TODO: Fix this during the Sapling upgrade (via #2277)
        assert_equal(
            {
                k: Decimal(v)
                for k, v in self.nodes[3].z_gettotalbalance(1, True).items()
            }, {
                'transparent':
                node3mined + Decimal('1250.0'),
                'private':
                zsendmany2notevalue + zsendmanynotevalue + zaddrremaining +
                zaddrremaining2,
                'total':
                node3mined + Decimal('1250.0') + zsendmany2notevalue +
                zsendmanynotevalue + zaddrremaining + zaddrremaining2,
            })

        # Check individual balances reflect the above
        assert_equal(self.nodes[3].z_getbalance(mytaddr1), Decimal('1250.0'))
        assert_equal(self.nodes[3].z_getbalance(myzaddr),
                     zsendmanynotevalue + zaddrremaining + zaddrremaining2)
Exemple #45
0
            newzaddr = self.nodes[2].z_getnewaddress('sprout')
            recipients.append({"address":newzaddr, "amount":amount_per_recipient})
        try:
            self.nodes[0].z_sendmany(myzaddr, recipients)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert("Invalid parameter, too many zaddr outputs" in errorString)

        # add zaddr to node 2
        myzaddr = self.nodes[2].z_getnewaddress('sprout')

        # send node 2 taddr to zaddr
        recipients = []
        recipients.append({"address":myzaddr, "amount":7})

        mytxid = wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(mytaddr, recipients))

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

        # check balances
        zsendmanynotevalue = Decimal('7.0')
        zsendmanyfee = Decimal('0.0001')
        node2utxobalance = Decimal('23.998') - zsendmanynotevalue - zsendmanyfee

        assert_equal(self.nodes[2].getbalance(), node2utxobalance)
        assert_equal(self.nodes[2].getbalance("*"), node2utxobalance)

        # check zaddr balance
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue)
        def nu_activation_checks():
            # Mine block H - 2. After this, the mempool expects
            # block H - 1, which is the last X block.
            self.nodes[0].generate(1)
            self.sync_all()

            # Mempool should be empty.
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Check node 0 shielded balance
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))

            # Fill the mempool with twice as many transactions as can fit into blocks
            node0_taddr = self.nodes[0].getnewaddress()
            x_txids = []
            while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000:
                x_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')))
            self.sync_all()

            # Spends should be in the mempool
            x_mempool = set(self.nodes[0].getrawmempool())
            assert_equal(x_mempool, set(x_txids))

            # Mine block H - 1. After this, the mempool expects
            # block H, which is the first Y block.
            self.nodes[0].generate(1)
            self.sync_all()

            # mempool should be empty.
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Block H - 1 should contain a subset of the original mempool
            # (with all other transactions having been dropped)
            block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx']
            assert(len(block_txids) < len(x_txids))
            for txid in block_txids[1:]: # Exclude coinbase
                assert(txid in x_txids)

            # Create some transparent Y transactions
            y_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)]
            self.sync_all()

            # Create a shielded Y transaction
            recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}]
            myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0'))
            shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)
            assert(shielded != None)
            y_txids.append(shielded)
            self.sync_all()

            # Spends should be in the mempool
            assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids))

            # Node 0 note should be unspendable
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0'))

            # Invalidate block H - 1.
            block_hm1 = self.nodes[0].getbestblockhash()
            self.nodes[0].invalidateblock(block_hm1)

            # BUG: Ideally, the mempool should now only contain the transactions
            # that were in block H - 1, the Y transactions having been dropped.
            # However, because chainActive is not updated until after the transactions
            # in the disconnected block have been re-added to the mempool, the height
            # seen by AcceptToMemoryPool is one greater than it should be. This causes
            # the block H - 1 transactions to be validated against the Y rules,
            # and rejected because they (obviously) fail.
            #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:]))
            assert_equal(set(self.nodes[0].getrawmempool()), set())

            # Node 0 note should be spendable again
            assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))

            # Reconsider block H - 1.
            self.nodes[0].reconsiderblock(block_hm1)

            # Mine blocks on node 1, so that the Y transactions in its mempool
            # will be cleared.
            self.nodes[1].generate(6)
            self.sync_all()
    def run_test(self):
        [alice, bob, charlie, david, miner] = self.nodes

        # the sender loses 'amount' plus fee; to_addr receives exactly 'amount'
        def z_send(from_node, from_addr, to_addr, amount):
            global fee
            opid = from_node.z_sendmany(from_addr, [{
                "address": to_addr,
                "amount": Decimal(amount)
            }], 1, fee)
            wait_and_assert_operationid_status(from_node, opid)
            self.sync_all()
            miner.generate(1)
            self.sync_all()

        def verify_utxos(node, amts, zaddr):
            amts.sort(reverse=True)
            txs = node.z_listreceivedbyaddress(zaddr)

            def cmp_confirmations_high_to_low(a, b):
                return cmp(b["amount"], a["amount"])

            txs.sort(cmp_confirmations_high_to_low)
            #print("Sorted txs", txs)
            #print("amts", amts)

            try:
                assert_equal(amts, [tx["amount"] for tx in txs])
                for tx in txs:
                    # make sure JoinSplit keys exist and have valid values
                    assert_equal("jsindex" in tx, True)
                    assert_equal("jsoutindex" in tx, True)
                    assert_greater_than(tx["jsindex"], -1)
                    assert_greater_than(tx["jsoutindex"], -1)
            except AssertionError:
                logging.error('Expected amounts: %r; txs: %r', amts, txs)
                raise

        def get_private_balance(node):
            balance = node.z_gettotalbalance()
            return balance['private']

        def find_imported_key(node, import_zaddr):
            zaddrs = node.z_listaddresses()
            assert (import_zaddr in zaddrs)
            return import_zaddr

        # Seed Alice with some funds
        alice.generate(10)
        self.sync_all()
        miner.generate(100)
        self.sync_all()
        # Shield Alice's coinbase funds to her zaddr
        alice_zaddr = alice.z_getnewaddress('sprout')
        res = alice.z_shieldcoinbase("*", alice_zaddr)
        wait_and_assert_operationid_status(alice, res['opid'])
        self.sync_all()
        miner.generate(1)
        self.sync_all()

        # Now get a pristine z-address for receiving transfers:
        bob_zaddr = bob.z_getnewaddress('sprout')
        verify_utxos(bob, [], bob_zaddr)
        # TODO: Verify that charlie doesn't have funds in addr
        # verify_utxos(charlie, [])

        # the amounts of each txn embodied which generates a single UTXO:
        amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19'])

        # Internal test consistency assertion:
        assert_greater_than(get_private_balance(alice),
                            reduce(Decimal.__add__, amounts))

        logging.info("Sending pre-export txns...")
        for amount in amounts[0:2]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        logging.info("Exporting privkey from bob...")
        bob_privkey = bob.z_exportkey(bob_zaddr)

        logging.info("Sending post-export txns...")
        for amount in amounts[2:4]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        verify_utxos(bob, amounts[:4], bob_zaddr)
        # verify_utxos(charlie, [])

        logging.info("Importing bob_privkey into charlie...")
        # z_importkey rescan defaults to "whenkeyisnew", so should rescan here
        charlie.z_importkey(bob_privkey)
        ipk_zaddr = find_imported_key(charlie, bob_zaddr)

        # z_importkey should have rescanned for new key, so this should pass:
        verify_utxos(charlie, amounts[:4], ipk_zaddr)

        # Verify idempotent behavior:
        charlie.z_importkey(bob_privkey)
        ipk_zaddr2 = find_imported_key(charlie, bob_zaddr)
        assert_equal(ipk_zaddr, ipk_zaddr2)

        # amounts should be unchanged
        verify_utxos(charlie, amounts[:4], ipk_zaddr2)

        logging.info("Sending post-import txns...")
        for amount in amounts[4:]:
            z_send(alice, alice_zaddr, bob_zaddr, amount)

        verify_utxos(bob, amounts, bob_zaddr)
        verify_utxos(charlie, amounts, ipk_zaddr)
        verify_utxos(charlie, amounts, ipk_zaddr2)

        # keep track of the fees incurred by bob (his sends)
        bob_fee = Decimal(0)

        # Try to reproduce zombie balance reported in #1936
        # At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice
        for amount in amounts[:2]:
            print("Sending amount from bob to alice: ", amount)
            z_send(bob, bob_zaddr, alice_zaddr, amount)
            bob_fee += fee

        bob_balance = sum(amounts[2:]) - bob_fee
        assert_equal(bob.z_getbalance(bob_zaddr), bob_balance)

        # z_import onto new node "david" (blockchain rescan, default or True?)
        david.z_importkey(bob_privkey)
        d_ipk_zaddr = find_imported_key(david, bob_zaddr)

        # Check if amt bob spent is deducted for charlie and david
        assert_equal(charlie.z_getbalance(ipk_zaddr), bob_balance)
        assert_equal(david.z_getbalance(d_ipk_zaddr), bob_balance)
 def call_z_sendmany(self, from_addr, to_addr, amount):
     recipients = []
     recipients.append({"address": to_addr, "amount": amount})
     myopid = self.nodes[0].z_sendmany(from_addr, recipients)
     return wait_and_assert_operationid_status(self.nodes[0], myopid)
Exemple #49
0
    def run_test_release(self, release, height):
        self.generate_and_sync(height + 1)
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress(release)

        self.nodes[0].sendtoaddress(taddr, 2.0)
        self.generate_and_sync(height + 2)

        # Send 1 ZEC to zaddr1
        opid = self.nodes[1].z_sendmany(taddr, [{
            'address': zaddr2,
            'amount': 0.6
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")

        # No confirmation required, one note should be present
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(1, len(r), "Should have received one (unconfirmed) note")
        assert_equal(txid, r[0]['txid'])
        assert_equal(1, r[0]['amount'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(my_memo, r[0]['memo'])

        # Confirm transaction (1 ZEC from taddr to zaddr1)
        self.generate_and_sync(height + 3)

        # Require one confirmation, note should be present
        assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1))

        # Generate some change by sending part of zaddr1 to zaddr2
        zaddr2 = self.nodes[1].z_getnewaddress(release)
        opid = self.nodes[1].z_sendmany(zaddr1, [{
            'address': zaddr2,
            'amount': 0.6,
            'memo': my_memo
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        self.generate_and_sync(height + 4)

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")

        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.4') - fee, r[0]['amount'])
        assert_true(r[0]['change'],
                    "Note valued at (0.4-fee) should be change")
        assert_equal(no_memo, r[0]['memo'])

        # The old note still exists (it's immutable), even though it is spent
        assert_equal(Decimal('1.0'), r[1]['amount'])
        assert_false(r[1]['change'], "Note valued at 1.0 should not be change")
        assert_equal(my_memo, r[0]['memo'])

        # zaddr2 should not have change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0)
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(1, len(r), "zaddr2 Should have received 1 notes")
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.6'), r[0]['amount'])
        assert_false(r[0]['change'], "Note valued at 0.6 should not be change")
        assert_equal(no_memo, r[0]['memo'])
Exemple #50
0
    def run_test(self):
        alice = self.nodes[0].getnewaddress()
        z_alice = self.nodes[0].z_getnewaddress()
        bob = self.nodes[2].getnewaddress()
        z_bob = self.nodes[2].z_getnewaddress()

        # When Overwinter not yet activated, no expiryheight in tx
        sapling_tx = self.nodes[0].sendtoaddress(bob, 0.01)
        rawtx = self.nodes[0].getrawtransaction(sapling_tx, 1)
        assert_equal(rawtx["overwintered"], False)
        assert("expiryheight" not in rawtx)

        self.nodes[0].generate(6)
        self.sync_all()

        print "Splitting network..."
        self.split_network()

        # When Overwinter is activated, test dependent txs
        firstTx = self.nodes[0].sendtoaddress(alice, 0.1)
        firstTxInfo = self.nodes[0].getrawtransaction(firstTx, 1)
        print "First tx expiry height:", firstTxInfo['expiryheight']
        # Mine first transaction
        self.nodes[0].generate(1)
        for outpoint in firstTxInfo['vout']:
            if outpoint['value'] == Decimal('0.10000000'):
                vout = outpoint
                break
        inputs = [{'txid': firstTx, 'vout': vout['n'], 'scriptPubKey': vout['scriptPubKey']['hex']}]
        outputs = {alice: 0.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        rawTxSigned = self.nodes[0].signrawtransaction(rawTx)
        assert(rawTxSigned['complete'])
        secondTx = self.nodes[0].sendrawtransaction(rawTxSigned['hex'])
        secondTxInfo = self.nodes[0].getrawtransaction(secondTx, 1)
        print "Second tx expiry height:", secondTxInfo['expiryheight']
        # Mine second, dependent transaction
        self.nodes[0].generate(1)
        print "Mine 6 competing blocks on Node 2..."
        blocks = self.nodes[2].generate(6)
        print "Connect nodes to force a reorg"
        connect_nodes_bi(self.nodes,0,2)
        self.is_network_split = False
        print "Syncing blocks"
        sync_blocks(self.nodes)
        print "Ensure that both txs are dropped from mempool of node 0"
        print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks']
        print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks']
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        assert_equal(set(self.nodes[2].getrawmempool()), set())

        ## Shield one of Alice's coinbase funds to her zaddr
        res = self.nodes[0].z_shieldcoinbase("*", z_alice, 0.0001, 1)
        wait_and_assert_operationid_status(self.nodes[0], res['opid'])
        self.nodes[0].generate(1)
        self.sync_all()

        # Get balance on node 0
        bal = self.nodes[0].z_gettotalbalance()
        print "Balance before zsend, after shielding 10: ", bal
        assert_equal(Decimal(bal["private"]), Decimal("9.9999"))

        print "Splitting network..."
        self.split_network()

        # Create transactions
        blockheight = self.nodes[0].getblockchaininfo()['blocks']
        zsendamount = Decimal('1.0') - Decimal('0.0001')
        recipients = []
        recipients.append({"address": z_bob, "amount": zsendamount})
        myopid = self.nodes[0].z_sendmany(z_alice, recipients)
        persist_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)
        persist_transparent = self.nodes[0].sendtoaddress(bob, 0.01)
        # Verify transparent transaction is version 3 intended for Overwinter branch
        rawtx = self.nodes[0].getrawtransaction(persist_transparent, 1)
        assert_equal(rawtx["version"], 3)
        assert_equal(rawtx["overwintered"], True)
        assert_equal(rawtx["expiryheight"], blockheight + 5)
        print "Blockheight at persist_transparent & persist_shielded creation:", self.nodes[0].getblockchaininfo()['blocks']
        print "Expiryheight of persist_transparent:", rawtx['expiryheight']
        # Verify shielded transaction is version 3 intended for Overwinter branch
        rawtx = self.nodes[0].getrawtransaction(persist_shielded, 1)
        print "Expiryheight of persist_shielded", rawtx['expiryheight']
        assert_equal(rawtx["version"], 3)
        assert_equal(rawtx["overwintered"], True)
        assert_equal(rawtx["expiryheight"], blockheight + 5)

        print "\n Blockheight advances to less than expiry block height. After reorg, txs should persist in mempool"
        assert(persist_transparent in self.nodes[0].getrawmempool())
        assert(persist_shielded in self.nodes[0].getrawmempool())
        assert_equal(set(self.nodes[2].getrawmempool()), set())
        print "mempool node 0:", self.nodes[0].getrawmempool()
        print "mempool node 2:", self.nodes[2].getrawmempool()
        bal = self.nodes[0].z_gettotalbalance()
        print "Printing balance before persist_shielded & persist_transparent are initially mined from mempool", bal
        # Txs are mined on node 0; will later be rolled back
        self.nodes[0].generate(1)
        print "Node 0 generated 1 block"
        print "Node 0 height:", self.nodes[0].getblockchaininfo()['blocks']
        print "Node 2 height:", self.nodes[2].getblockchaininfo()['blocks']
        bal = self.nodes[0].z_gettotalbalance()
        print "Printing balance after persist_shielded & persist_transparent are mined:", bal
        assert_equal(set(self.nodes[0].getrawmempool()), set())

        print "Mine 2 competing blocks on Node 2..."
        blocks = self.nodes[2].generate(2)
        for block in blocks:
            blk = self.nodes[2].getblock(block)
            print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"])
        print "Connect nodes to force a reorg"
        connect_nodes_bi(self.nodes,0,2)
        self.is_network_split = False

        print "Syncing blocks"
        sync_blocks(self.nodes)

        print "Ensure that txs are back in mempool of node 0"
        print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks']
        print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks']
        print "mempool node 0: ", self.nodes[0].getrawmempool()
        print "mempool node 2: ", self.nodes[2].getrawmempool()
        assert(persist_transparent in self.nodes[0].getrawmempool())
        assert(persist_shielded in self.nodes[0].getrawmempool())
        bal = self.nodes[0].z_gettotalbalance()
        # Mine txs to get them out of the way of mempool sync in split_network()
        print "Generating another block on node 0 to clear txs from mempool"
        self.nodes[0].generate(1)
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        sync_blocks(self.nodes)

        print "Splitting network..."
        self.split_network()

        print "\n Blockheight advances to equal expiry block height. After reorg, txs should persist in mempool"
        myopid = self.nodes[0].z_sendmany(z_alice, recipients)
        persist_shielded_2 = wait_and_assert_operationid_status(self.nodes[0], myopid)
        persist_transparent_2 = self.nodes[0].sendtoaddress(bob, 0.01)
        rawtx_trans = self.nodes[0].getrawtransaction(persist_transparent_2, 1)
        rawtx_shield = self.nodes[0].getrawtransaction(persist_shielded_2, 1)
        print "Blockheight node 0 at persist_transparent_2 creation:", self.nodes[0].getblockchaininfo()['blocks']
        print "Blockheight node 2 at persist_transparent_2 creation:", self.nodes[2].getblockchaininfo()['blocks']
        print "Expiryheight of persist_transparent_2:", rawtx_trans['expiryheight']
        print "Expiryheight of persist_shielded_2:", rawtx_shield['expiryheight']
        blocks = self.nodes[2].generate(4)
        for block in blocks:
            blk = self.nodes[2].getblock(block)
            print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"])
        print "Connect nodes to force a reorg"
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False
        sync_blocks(self.nodes)
        print "Ensure that persist_transparent_2 & persist_shielded_2 are in mempool at expiry block height"
        print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks']
        print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks']
        print "mempool node 0: ", self.nodes[0].getrawmempool()
        print "mempool node 2: ", self.nodes[2].getrawmempool()
        assert(persist_transparent_2 in self.nodes[0].getrawmempool())
        assert(persist_shielded_2 in self.nodes[0].getrawmempool())
        # Mine persist txs to get them out of the way of mempool sync in split_network()
        self.nodes[0].generate(1)
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        sync_blocks(self.nodes)
        print "Balance after persist_shielded_2 is mined to remove from mempool: ", self.nodes[0].z_gettotalbalance()

        print "Splitting network..."
        self.split_network()

        print "\n Blockheight advances to greater than expiry block height. After reorg, txs should expire from mempool"
        print "Balance before expire_shielded is sent: ", self.nodes[0].z_gettotalbalance()
        myopid = self.nodes[0].z_sendmany(z_alice, recipients)
        expire_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)
        expire_transparent = self.nodes[0].sendtoaddress(bob, 0.01)
        print "Blockheight node 0 at expire_transparent creation:", self.nodes[0].getblockchaininfo()['blocks']
        print "Blockheight node 2 at expire_shielded creation:", self.nodes[2].getblockchaininfo()['blocks']
        print "Expiryheight of expire_transparent:", self.nodes[0].getrawtransaction(expire_transparent, 1)['expiryheight']
        print "Expiryheight of expire_shielded:", self.nodes[0].getrawtransaction(expire_shielded, 1)['expiryheight']
        assert(expire_transparent in self.nodes[0].getrawmempool())
        assert(expire_shielded in self.nodes[0].getrawmempool())
        blocks = self.nodes[2].generate(6)
        for block in blocks:
            blk = self.nodes[2].getblock(block)
            print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"])
        print "Connect nodes to force a reorg"
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False
        sync_blocks(self.nodes)
        print "Ensure that expire_transparent & expire_shielded are in mempool at expiry block height"
        print "mempool node 0: ", self.nodes[0].getrawmempool()
        print "mempool node 2: ", self.nodes[2].getrawmempool()
        assert_equal(set(self.nodes[0].getrawmempool()), set())
        print "Ensure balance of node 0 is correct"
        bal = self.nodes[0].z_gettotalbalance()
        print "Balance after expire_shielded has expired: ", bal
        assert_equal(Decimal(bal["private"]), Decimal("7.9999"))
Exemple #51
0
        try:
            self.nodes[0].createrawtransaction([], {}, 0, 200)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert_equal("Invalid parameter, expiryheight should be at least 203 to avoid transaction expiring soon" in errorString, True)

        # Node 0 sends transparent funds to Node 3
        tsendamount = Decimal('1.0')
        txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount)
        self.sync_all()

        # Node 3 sends the zero-confirmation transparent funds to Node 1 using z_sendmany
        recipients = []
        recipients.append({"address":taddr1, "amount": Decimal('0.5')})
        myopid = self.nodes[3].z_sendmany(taddr3, recipients, 0)
        txid_zsendmany = wait_and_assert_operationid_status(self.nodes[3], myopid)

        # Node 0 shields to Node 3, a coinbase utxo of value 10.0 less fee 0.00010000
        zsendamount = Decimal('10.0') - Decimal('0.0001')
        recipients = []
        recipients.append({"address":zaddr3, "amount": zsendamount})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients)
        txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Mine the first Overwinter block
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        bci = self.nodes[0].getblockchaininfo()

        # size_on_disk should be > 0
Exemple #52
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())

        mining_addr = self.nodes[0].listunspent()[0]['address']

        # Shield coinbase funds (must be a multiple of 10, no change allowed pre-sapling)
        receive_amount_10 = Decimal('10.0') - Decimal('0.0001')
        recipients = [{"address":sproutzaddr, "amount":receive_amount_10}]
        myopid = self.nodes[0].z_sendmany(mining_addr, recipients)
        txid_1 = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        
        # No funds (with (default) one or more confirmations) in sproutzaddr yet
        assert_equal(0, len(self.nodes[0].z_listunspent()))
        assert_equal(0, len(self.nodes[0].z_listunspent(1)))
        
        # no private balance because no confirmations yet
        assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private']))
        
        # list private unspent, this time allowing 0 confirmations
        unspent_cb = self.nodes[0].z_listunspent(0)
        assert_equal(1, len(unspent_cb))
        assert_equal(False,             unspent_cb[0]['change'])
        assert_equal(txid_1,            unspent_cb[0]['txid'])
        assert_equal(True,              unspent_cb[0]['spendable'])
        assert_equal(sproutzaddr,       unspent_cb[0]['address'])
        assert_equal(receive_amount_10, unspent_cb[0]['amount'])

        # list unspent, filtering by address, should produce same result
        unspent_cb_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr])
        assert_equal(unspent_cb, unspent_cb_filter)
        
        # Generate a block to confirm shield coinbase tx
        self.nodes[0].generate(1)
        self.sync_all()
        
        # Current height = 202 -> Overwinter. Default address type remains Sprout
        assert_equal(202, self.nodes[0].getblockcount())

        # Send 1.0 (actually 0.9999) from sproutzaddr to a new zaddr
        sproutzaddr2 = self.nodes[0].z_getnewaddress()
        receive_amount_1 = Decimal('1.0') - Decimal('0.0001')
        change_amount_9 = receive_amount_10 - Decimal('1.0')
        assert_equal('sprout', self.nodes[0].z_validateaddress(sproutzaddr2)['type'])
        recipients = [{"address": sproutzaddr2, "amount":receive_amount_1}]
        myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients)
        txid_2 = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        
        # list unspent, allowing 0conf txs
        unspent_tx = self.nodes[0].z_listunspent(0)
        assert_equal(len(unspent_tx), 2)
        # sort low-to-high by amount (order of returned entries is not guaranteed)
        unspent_tx = sorted(unspent_tx, key=lambda k: k['amount'])
        assert_equal(False,             unspent_tx[0]['change'])
        assert_equal(txid_2,            unspent_tx[0]['txid'])
        assert_equal(True,              unspent_tx[0]['spendable'])
        assert_equal(sproutzaddr2,      unspent_tx[0]['address'])
        assert_equal(receive_amount_1,  unspent_tx[0]['amount'])

        assert_equal(True,              unspent_tx[1]['change'])
        assert_equal(txid_2,            unspent_tx[1]['txid'])
        assert_equal(True,              unspent_tx[1]['spendable'])
        assert_equal(sproutzaddr,       unspent_tx[1]['address'])
        assert_equal(change_amount_9,   unspent_tx[1]['amount'])

        unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr2])
        assert_equal(1, len(unspent_tx_filter))
        assert_equal(unspent_tx[0], unspent_tx_filter[0])

        unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr])
        assert_equal(1, len(unspent_tx_filter))
        assert_equal(unspent_tx[1], unspent_tx_filter[0])
        
        # Set current height to 204 -> Sapling
        self.nodes[0].generate(2)
        self.sync_all()
        assert_equal(204, self.nodes[0].getblockcount())
        
        # No funds in saplingzaddr yet
        assert_equal(0, len(self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr])))

        # Send 0.9999 to our sapling zaddr
        # (sending from a sprout zaddr to a sapling zaddr is disallowed,
        # so send from coin base)
        receive_amount_2 = Decimal('2.0') - Decimal('0.0001')
        recipients = [{"address": saplingzaddr, "amount":receive_amount_2}]
        myopid = self.nodes[0].z_sendmany(mining_addr, recipients)
        txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid)
        self.sync_all()
        unspent_tx = self.nodes[0].z_listunspent(0)
        assert_equal(3, len(unspent_tx))

        # low-to-high in amount
        unspent_tx = sorted(unspent_tx, key=lambda k: k['amount'])

        assert_equal(False,             unspent_tx[0]['change'])
        assert_equal(txid_2,            unspent_tx[0]['txid'])
        assert_equal(True,              unspent_tx[0]['spendable'])
        assert_equal(sproutzaddr2,      unspent_tx[0]['address'])
        assert_equal(receive_amount_1,  unspent_tx[0]['amount'])

        assert_equal(False,             unspent_tx[1]['change'])
        assert_equal(txid_3,            unspent_tx[1]['txid'])
        assert_equal(True,              unspent_tx[1]['spendable'])
        assert_equal(saplingzaddr,      unspent_tx[1]['address'])
        assert_equal(receive_amount_2,  unspent_tx[1]['amount'])

        assert_equal(True,              unspent_tx[2]['change'])
        assert_equal(txid_2,            unspent_tx[2]['txid'])
        assert_equal(True,              unspent_tx[2]['spendable'])
        assert_equal(sproutzaddr,       unspent_tx[2]['address'])
        assert_equal(change_amount_9,   unspent_tx[2]['amount'])

        unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr])
        assert_equal(1, len(unspent_tx_filter))
        assert_equal(unspent_tx[1], unspent_tx_filter[0])

        # test that pre- and post-sapling can be filtered in a single call
        unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False,
            [sproutzaddr, saplingzaddr])
        assert_equal(2, len(unspent_tx_filter))
        unspent_tx_filter = sorted(unspent_tx_filter, key=lambda k: k['amount'])
        assert_equal(unspent_tx[1], unspent_tx_filter[0])
        assert_equal(unspent_tx[2], unspent_tx_filter[1])

        # so far, this node has no watchonly addresses, so results are the same
        unspent_tx_watchonly = self.nodes[0].z_listunspent(0, 9999, True)
        unspent_tx_watchonly = sorted(unspent_tx_watchonly, key=lambda k: k['amount'])
        assert_equal(unspent_tx, unspent_tx_watchonly)
Exemple #53
0
class WalletOverwinterTxTest (BitcoinTestFramework):

    def setup_chain(self):
        print("Initializing test directory "+self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, 4)

    def setup_network(self, split=False):
        self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[["-nuparams=5ba81b19:200", "-debug=zrpcunsafe", "-txindex"]] * 4 )
        connect_nodes_bi(self.nodes,0,1)
        connect_nodes_bi(self.nodes,1,2)
        connect_nodes_bi(self.nodes,0,2)
        connect_nodes_bi(self.nodes,0,3)
        self.is_network_split=False
        self.sync_all()

    def run_test (self):
        self.nodes[0].generate(100)
        self.sync_all()
        self.nodes[1].generate(98)
        self.sync_all()
        # Node 0 has reward from blocks 1 to 98 which are spendable.

        taddr0 = self.nodes[0].getnewaddress()
        taddr1 = self.nodes[1].getnewaddress()
        taddr2 = self.nodes[2].getnewaddress()
        zaddr2 = self.nodes[2].z_getnewaddress('sprout')
        taddr3 = self.nodes[3].getnewaddress()
        zaddr3 = self.nodes[3].z_getnewaddress('sprout')

        #
        # Currently at block 198. The next block to be mined 199 is a Sprout block
        #
        bci = self.nodes[0].getblockchaininfo()
        assert_equal(bci['consensus']['chaintip'], '00000000')
        assert_equal(bci['consensus']['nextblock'], '00000000')
        assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending')

        # Cannot use the expiryheight parameter of createrawtransaction if Overwinter is not active in the next block
        try:
            self.nodes[0].createrawtransaction([], {}, 0, 99)
        except JSONRPCException,e:
            errorString = e.error['message']
        assert_equal("Invalid parameter, expiryheight can only be used if Overwinter is active when the transaction is mined" in errorString, True)

        # Node 0 sends transparent funds to Node 2
        tsendamount = Decimal('1.0')
        txid_transparent = self.nodes[0].sendtoaddress(taddr2, tsendamount)
        self.sync_all()

        # Node 2 sends the zero-confirmation transparent funds to Node 1 using z_sendmany
        recipients = []
        recipients.append({"address":taddr1, "amount": Decimal('0.5')})
        myopid = self.nodes[2].z_sendmany(taddr2, recipients, 0)
        txid_zsendmany = wait_and_assert_operationid_status(self.nodes[2], myopid)

        # Node 0 shields to Node 2, a coinbase utxo of value 10.0 less fee 0.00010000
        zsendamount = Decimal('10.0') - Decimal('0.0001')
        recipients = []
        recipients.append({"address":zaddr2, "amount": zsendamount})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients)
        txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Verify balance
        assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0.5'))
        assert_equal(self.nodes[2].getbalance(), Decimal('0.4999'))
        assert_equal(self.nodes[2].z_getbalance(zaddr2), zsendamount)

        # Verify transaction versions are 1 or 2 (intended for Sprout)
        result = self.nodes[0].getrawtransaction(txid_transparent, 1)
        assert_equal(result["version"], 1)
        assert_equal(result["overwintered"], False)
        result = self.nodes[0].getrawtransaction(txid_zsendmany, 1)
        assert_equal(result["version"], 1)
        assert_equal(result["overwintered"], False)
        result = self.nodes[0].getrawtransaction(txid_shielded, 1)
        assert_equal(result["version"], 2)
        assert_equal(result["overwintered"], False)

        #
        # Currently at block 199. The next block to be mined 200 is an Overwinter block
        #
        bci = self.nodes[0].getblockchaininfo()
        assert_equal(bci['consensus']['chaintip'], '00000000')
        assert_equal(bci['consensus']['nextblock'], '5ba81b19')
        assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending')

        # Test using expiryheight parameter of createrawtransaction when Overwinter is active in the next block
        errorString = ""
        try:
            self.nodes[0].createrawtransaction([], {}, 0, 499999999)
        except JSONRPCException,e:
            errorString = e.error['message']
Exemple #54
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"])
    def run_test (self):
        self.nodes[0].generate(100)
        self.sync_all()
        self.nodes[1].generate(98)
        self.sync_all()
        # Node 0 has reward from blocks 1 to 98 which are spendable.

        taddr0 = self.nodes[0].getnewaddress()
        taddr1 = self.nodes[1].getnewaddress()
        taddr2 = self.nodes[2].getnewaddress()
        zaddr2 = self.nodes[2].z_getnewaddress()
        taddr3 = self.nodes[3].getnewaddress()
        zaddr3 = self.nodes[3].z_getnewaddress()

        #
        # Currently at block 198. The next block to be mined 199 is a Sprout block
        #
        bci = self.nodes[0].getblockchaininfo()
        assert_equal(bci['consensus']['chaintip'], '00000000')
        assert_equal(bci['consensus']['nextblock'], '00000000')
        assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending')

        # Node 0 sends transparent funds to Node 2
        tsendamount = Decimal('1.0')
        txid_transparent = self.nodes[0].sendtoaddress(taddr2, tsendamount)
        self.sync_all()

        # Node 2 sends the zero-confirmation transparent funds to Node 1 using z_sendmany
        recipients = []
        recipients.append({"address":taddr1, "amount": Decimal('0.5')})
        myopid = self.nodes[2].z_sendmany(taddr2, recipients, 0)
        txid_zsendmany = wait_and_assert_operationid_status(self.nodes[2], myopid)

        # Node 0 shields to Node 2, a coinbase utxo of value 10.0 less fee 0.00010000
        zsendamount = Decimal('10.0') - Decimal('0.0001')
        recipients = []
        recipients.append({"address":zaddr2, "amount": zsendamount})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients)
        txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Verify balance
        assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0.5'))
        assert_equal(self.nodes[2].getbalance(), Decimal('0.4999'))
        assert_equal(self.nodes[2].z_getbalance(zaddr2), zsendamount)

        # Verify transaction versions are 1 or 2 (intended for Sprout)
        result = self.nodes[0].getrawtransaction(txid_transparent, 1)
        assert_equal(result["version"], 1)
        assert_equal(result["overwintered"], False)
        result = self.nodes[0].getrawtransaction(txid_zsendmany, 1)
        assert_equal(result["version"], 1)
        assert_equal(result["overwintered"], False)
        result = self.nodes[0].getrawtransaction(txid_shielded, 1)
        assert_equal(result["version"], 2)
        assert_equal(result["overwintered"], False)

        #
        # Currently at block 199. The next block to be mined 200 is an Overwinter block
        #
        bci = self.nodes[0].getblockchaininfo()
        assert_equal(bci['consensus']['chaintip'], '00000000')
        assert_equal(bci['consensus']['nextblock'], '5ba81b19')
        assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending')

        # Node 0 sends transparent funds to Node 3
        tsendamount = Decimal('1.0')
        txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount)
        self.sync_all()

        # Node 3 sends the zero-confirmation transparent funds to Node 1 using z_sendmany
        recipients = []
        recipients.append({"address":taddr1, "amount": Decimal('0.5')})
        myopid = self.nodes[3].z_sendmany(taddr3, recipients, 0)
        txid_zsendmany = wait_and_assert_operationid_status(self.nodes[3], myopid)

        # Node 0 shields to Node 3, a coinbase utxo of value 10.0 less fee 0.00010000
        zsendamount = Decimal('10.0') - Decimal('0.0001')
        recipients = []
        recipients.append({"address":zaddr3, "amount": zsendamount})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients)
        txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Mine the first Overwinter block
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        bci = self.nodes[0].getblockchaininfo()
        assert_equal(bci['consensus']['chaintip'], '5ba81b19')
        assert_equal(bci['consensus']['nextblock'], '5ba81b19')
        assert_equal(bci['upgrades']['5ba81b19']['status'], 'active')

        # Verify balance
        assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('1.0'))
        assert_equal(self.nodes[3].getbalance(), Decimal('0.4999'))
        assert_equal(self.nodes[3].z_getbalance(zaddr3), zsendamount)

        # Verify transaction version is 3 (intended for Overwinter)
        result = self.nodes[0].getrawtransaction(txid_transparent, 1)
        assert_equal(result["version"], 3)
        assert_equal(result["overwintered"], True)
        assert_equal(result["versiongroupid"], "03c48270")
        result = self.nodes[0].getrawtransaction(txid_zsendmany, 1)
        assert_equal(result["version"], 3)
        assert_equal(result["overwintered"], True)
        assert_equal(result["versiongroupid"], "03c48270")
        result = self.nodes[0].getrawtransaction(txid_shielded, 1)
        assert_equal(result["version"], 3)
        assert_equal(result["overwintered"], True)
        assert_equal(result["versiongroupid"], "03c48270")