Exemple #1
0
    def run_test(self):
        activation_block = 400

        assert_raises_message(JSONRPCException,
                              "Lelantus is not activated yet",
                              self.nodes[0].mintlelantus, 1)

        self.nodes[0].generate(activation_block -
                               self.nodes[0].getblockcount())

        # generate coins
        amounts = [1, 1.1, 2, 10]

        # 10 confirmations
        self.nodes[0].mintlelantus(amounts[0])
        self.nodes[0].mintlelantus(amounts[1])
        self.nodes[0].generate(5)

        # 5 confirmations
        self.nodes[0].mintlelantus(amounts[2])
        self.nodes[0].mintlelantus(amounts[3])
        self.nodes[0].generate(5)

        # get all mints and utxos
        mints = self.verify_listlelantusmints(amounts)
        self.verify_listunspentlelantusmints(amounts)
        self.verify_listunspentlelantusmints([], 1000)  # [1000, 9999999]
        self.verify_listunspentlelantusmints([2, 10], 1, 5)  # [1, 5]
        self.verify_listunspentlelantusmints([1, 1.1], 6, 10)
        self.verify_listunspentlelantusmints([1, 1.1, 2, 10], 5, 10)
        assert_equal([False, False, False, False],
                     list(map(lambda m: m["isUsed"], mints)))

        # state modification test
        # mark two coins as used
        self.nodes[0].setlelantusmintstatus(mints[2]["serialNumber"], True)
        self.nodes[0].setlelantusmintstatus(mints[3]["serialNumber"], True)

        mints = self.verify_listlelantusmints(amounts)
        self.verify_listunspentlelantusmints([1, 1.1])
        self.verify_listunspentlelantusmints([], 1000)
        self.verify_listunspentlelantusmints([], 1, 5)
        self.verify_listunspentlelantusmints([1, 1.1], 6, 10)
        self.verify_listunspentlelantusmints([1, 1.1], 5, 10)
        assert_equal([False, False, True, True],
                     list(map(lambda m: m["isUsed"], mints)))

        # set a coin as unused
        self.nodes[0].setlelantusmintstatus(mints[3]["serialNumber"], False)
        mints = self.verify_listlelantusmints(amounts)
        self.verify_listunspentlelantusmints([1, 1.1, 10])
        assert_equal([False, False, True, False],
                     list(map(lambda m: m["isUsed"], mints)))

        # reset coins state
        self.nodes[0].resetlelantusmint()
        mints = self.verify_listlelantusmints(amounts)
        self.verify_listunspentlelantusmints(amounts)
        assert_equal([False, False, False, False],
                     list(map(lambda m: m["isUsed"], mints)))
    def test(self, balance=1, ecosystem=1, amount=None, expected_error=None):
        addr = self.get_new_address(balance)

        operator = self.nodes[0].elysium_sendissuancemanaged
        options = [addr, ecosystem, 1, 0, "", "", "Foo", "", ""]

        if amount is not None:
            operator = self.nodes[0].elysium_sendissuancefixed
            options.append(amount)

        if expected_error is None:
            operator(*options)
            self.nodes[0].generate(1)
            self.sync_all()
        else:
            assert_raises_message(JSONRPCException, expected_error, operator,
                                  *options)
    def run_test(self):
        super().run_test()

        sigma_start_block = 500

        self.nodes[0].generatetoaddress(100, self.addrs[0])
        self.nodes[0].generate(sigma_start_block - self.nodes[0].getblockcount())

        self.nodes[0].elysium_sendissuancefixed(
            self.addrs[0], 1, 1, 0, '', '', 'Sigma', '', '', '1000000', 1
        )
        self.nodes[0].generate(1)
        sigmaProperty = 3

        self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], sigmaProperty, '1')
        self.nodes[0].generate(10)

        passphase = 'test'
        self.nodes[0].encryptwallet(passphase)
        bitcoind_processes[0].wait()
        self.nodes[0] = start_node(0, self.options.tmpdir, ['-elysium'])

        # try to mint using encrypted wallet
        assert_raises_message(
            JSONRPCException,
            'Wallet locked',
            self.nodes[0].elysium_sendmint, self.addrs[0], sigmaProperty, {"0":1}
        )

        self.nodes[0].walletpassphrase(passphase, 3)

        self.nodes[0].elysium_sendmint(self.addrs[0], sigmaProperty, {"0":1})

        sleep(3)

        assert_raises_message(
            JSONRPCException,
            'Wallet locked',
            self.nodes[0].elysium_sendmint, self.addrs[0], sigmaProperty, {"0":1}
        )
    def run_test(self):

        # Generate blocks up to Heartwood activation
        logging.info(
            "Generating initial blocks. Current height is 200, advance to 210 (activate Heartwood but not Canopy)"
        )
        self.nodes[0].generate(10)
        self.sync_all()

        # Shield coinbase to Sprout on node 0. Should pass
        sprout_addr = self.nodes[0].z_getnewaddress('sprout')
        sprout_addr_node2 = self.nodes[2].z_getnewaddress('sprout')
        myopid = self.nodes[0].z_shieldcoinbase(
            get_coinbase_address(self.nodes[0]), sprout_addr, 0)['opid']
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        print(
            "taddr -> Sprout z_shieldcoinbase tx accepted before Canopy on node 0"
        )

        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].z_getbalance(sprout_addr), Decimal('10'))

        # Fund taddr_0 from shielded coinbase on node 0
        taddr_0 = self.nodes[0].getnewaddress()
        for _ in range(3):
            recipients = [{"address": taddr_0, "amount": Decimal('1')}]
            myopid = self.nodes[0].z_sendmany(sprout_addr, recipients, 1, 0)
            wait_and_assert_operationid_status(self.nodes[0], myopid)
            self.sync_all()
            self.nodes[0].generate(1)
            self.sync_all()

        # Create mergetoaddress taddr -> Sprout transaction and mine on node 0 before it is Canopy-aware. Should pass
        merge_tx_0 = self.nodes[0].z_mergetoaddress(
            ["ANY_TADDR"], self.nodes[1].z_getnewaddress('sprout'))
        wait_and_assert_operationid_status(self.nodes[0], merge_tx_0['opid'])
        print(
            "taddr -> Sprout z_mergetoaddress tx accepted before Canopy on node 0"
        )

        # Mine to one block before Canopy activation on node 0; adding value
        # to the Sprout pool will fail now since the transaction must be
        # included in the next (or later) block, after Canopy has activated.
        self.nodes[0].generate(5)
        self.sync_all()
        assert_equal(
            self.nodes[0].getblockchaininfo()['upgrades']['e9ff75a6']
            ['status'], 'pending')

        # Shield coinbase to Sprout on node 0. Should fail
        sprout_addr = self.nodes[0].z_getnewaddress('sprout')
        assert_raises_message(
            JSONRPCException, "Sprout shielding is not supported after Canopy",
            self.nodes[0].z_shieldcoinbase,
            get_coinbase_address(self.nodes[0]), sprout_addr, 0)
        print(
            "taddr -> Sprout z_shieldcoinbase tx rejected at Canopy activation on node 0"
        )

        # Create taddr -> Sprout z_sendmany transaction on node 0. Should fail
        sprout_addr = self.nodes[1].z_getnewaddress('sprout')
        assert_raises_message(
            JSONRPCException,
            "Sending funds into the Sprout pool is not supported by z_sendmany",
            self.nodes[0].z_sendmany, taddr_0, [{
                "address": sprout_addr,
                "amount": 1
            }])
        print(
            "taddr -> Sprout z_sendmany tx rejected at Canopy activation on node 0"
        )

        # Create z_mergetoaddress [taddr, Sprout] -> Sprout transaction on node 0. Should fail
        assert_raises_message(
            JSONRPCException, "Sprout shielding is not supported after Canopy",
            self.nodes[0].z_mergetoaddress, ["ANY_TADDR", "ANY_SPROUT"],
            self.nodes[1].z_getnewaddress('sprout'))
        print(
            "[taddr, Sprout] -> Sprout z_mergetoaddress tx rejected at Canopy activation on node 0"
        )

        # Create z_mergetoaddress Sprout -> Sprout transaction on node 0. Should pass
        merge_tx_1 = self.nodes[0].z_mergetoaddress(
            ["ANY_SPROUT"], self.nodes[1].z_getnewaddress('sprout'))
        wait_and_assert_operationid_status(self.nodes[0], merge_tx_1['opid'])
        print(
            "Sprout -> Sprout z_mergetoaddress tx accepted at Canopy activation on node 0"
        )

        # Activate Canopy
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(
            self.nodes[0].getblockchaininfo()['upgrades']['e9ff75a6']
            ['status'], 'active')

        # Generating a Sprout address should fail after Canopy.
        assert_raises_message(
            JSONRPCException,
            "Invalid address type, \"sprout\" is not allowed after Canopy",
            self.nodes[0].z_getnewaddress, 'sprout')
        print("Sprout z_getnewaddress rejected at Canopy activation on node 0")

        # Shield coinbase to Sapling on node 0. Should pass
        sapling_addr = self.nodes[0].z_getnewaddress('sapling')
        myopid = self.nodes[0].z_shieldcoinbase(
            get_coinbase_address(self.nodes[0]), sapling_addr, 0)['opid']
        wait_and_assert_operationid_status(self.nodes[0], myopid)
        print(
            "taddr -> Sapling z_shieldcoinbase tx accepted after Canopy on node 0"
        )

        # Mine to one block before NU5 activation.
        self.nodes[0].generate(4)
        self.sync_all()

        # Create z_mergetoaddress Sprout -> Sprout transaction on node 1. Should pass
        merge_tx_2 = self.nodes[1].z_mergetoaddress(["ANY_SPROUT"],
                                                    sprout_addr_node2)
        wait_and_assert_operationid_status(self.nodes[1], merge_tx_2['opid'])
        print(
            "Sprout -> Sprout z_mergetoaddress tx accepted at NU5 activation on node 1"
        )

        self.nodes[1].generate(1)
        self.sync_all()
Exemple #5
0
    def run_test(self):
        super().run_test()

        sigma_start_block = 550
        passphase = "1234"

        owner = self.addrs[0]

        self.nodes[0].generatetoaddress(
            sigma_start_block - self.nodes[0].getblockcount(), owner)
        self.sync_all()

        # create sigma
        for _ in range(0, 10):
            self.nodes[0].mint(1)

        self.nodes[0].generate(10)

        # create property
        self.nodes[0].elysium_sendissuancefixed(owner, 1, 1, 0, '', '',
                                                'Sigma', '', '', '1000000', 1)

        self.nodes[0].generate(1)
        sigmaProperty = 3

        self.nodes[0].elysium_sendcreatedenomination(owner, sigmaProperty, '1')
        self.nodes[0].generate(10)

        # mint 2 coins
        self.nodes[0].elysium_sendmint(owner, sigmaProperty, {"0": 2})
        self.nodes[0].generate(10)

        # spend a coin
        self.nodes[0].elysium_sendspend(owner, sigmaProperty, 0)
        self.nodes[0].generate(1)

        blockcount = self.nodes[0].getblockcount()

        # encrypt wallet && restart node
        self.nodes[0].encryptwallet(passphase)
        bitcoind_processes[0].wait()
        self.nodes[0] = start_node(0, self.options.tmpdir,
                                   ['-elysium', '-reindex'])
        while self.nodes[0].getblockcount() < blockcount:
            time.sleep(0.1)

        connect_nodes(self.nodes[0], 1)

        # try to spend using encrypted wallet
        assert_raises_message(JSONRPCException, 'wallet locked',
                              self.nodes[0].elysium_sendspend, owner,
                              sigmaProperty, 0)

        # Unlock
        self.nodes[0].walletpassphrase(passphase, 10)

        # One coin remaining
        unspends = self.nodes[0].elysium_listmints()
        assert_equal(1, len(unspends))

        # Spend another coin
        self.nodes[0].elysium_sendspend(owner, sigmaProperty, 0)

        # No remaining coin
        unspends = self.nodes[0].elysium_listmints()
        assert_equal(0, len(unspends))
Exemple #6
0
    def run_test(self):
        super().run_test()

        sigma_start_block = 500

        self.nodes[0].generatetoaddress(100, self.addrs[0])
        self.nodes[0].generate(sigma_start_block -
                               self.nodes[0].getblockcount())

        assert_equal(sigma_start_block, self.nodes[0].getblockcount())

        # create non-sigma
        self.nodes[0].exodus_sendissuancefixed(self.addrs[0], 1, 1, 0, '', '',
                                               'Non-Sigma', '', '', '1000000')
        self.nodes[0].generate(1)
        nonSigmaProperty = 3

        # create sigma with denominations (1, 2)
        self.nodes[0].exodus_sendissuancefixed(self.addrs[0], 1, 1, 0, '', '',
                                               'Sigma', '', '', '1000000', 1)

        self.nodes[0].generate(1)
        sigmaProperty = 4

        self.nodes[0].exodus_sendcreatedenomination(self.addrs[0],
                                                    sigmaProperty, '1')
        self.nodes[0].generate(1)

        self.nodes[0].exodus_sendcreatedenomination(self.addrs[0],
                                                    sigmaProperty, '2')
        self.nodes[0].generate(10)

        # non-sigma
        addr = self.nodes[0].getnewaddress()
        self.nodes[0].exodus_send(self.addrs[0], addr, nonSigmaProperty, "100")
        self.nodes[0].sendtoaddress(addr, 100)
        self.nodes[0].generate(10)

        assert_raises_message(JSONRPCException,
                              'Property has not enabled Sigma',
                              self.nodes[0].exodus_sendmint, addr,
                              nonSigmaProperty, {"0": 1})

        assert_equal(
            "100",
            self.nodes[0].exodus_getbalance(addr, nonSigmaProperty)['balance'])

        # sigma
        # mint without idx and token
        addr = self.nodes[0].getnewaddress()
        assert_raises_message(JSONRPCException,
                              'Sender has insufficient balance',
                              self.nodes[0].exodus_sendmint, addr,
                              sigmaProperty, {"0": 1})

        # mint without idx then fail
        addr = self.nodes[0].getnewaddress()
        self.nodes[0].exodus_send(self.addrs[0], addr, sigmaProperty, "100")
        self.nodes[0].generate(10)

        assert_raises_message(
            JSONRPCException, 'Error choosing inputs for the send transaction',
            self.nodes[0].exodus_sendmint, addr, sigmaProperty, {"0": 1})

        assert_equal(
            "100", self.nodes[0].exodus_getbalance(addr,
                                                   sigmaProperty)['balance'])
        assert_equal(0, len(self.nodes[0].exodus_listpendingmints()))

        # mint without token then fail
        addr = self.nodes[0].getnewaddress()
        self.nodes[0].sendtoaddress(addr, 100)
        self.nodes[0].generate(10)

        assert_raises_message(JSONRPCException,
                              'Sender has insufficient balance',
                              self.nodes[0].exodus_sendmint, addr,
                              sigmaProperty, {"0": 1})

        assert_equal(
            "0", self.nodes[0].exodus_getbalance(addr,
                                                 sigmaProperty)['balance'])
        assert_equal(0, len(self.nodes[0].exodus_listpendingmints()))

        # success to mint should be shown on pending
        addr = self.nodes[0].getnewaddress()

        self.nodes[0].exodus_send(self.addrs[0], addr, sigmaProperty, "100")
        self.nodes[0].sendtoaddress(addr, 100)
        self.nodes[0].generate(10)
        self.nodes[0].exodus_sendmint(addr, sigmaProperty, {"0": 1})

        assert_equal(1, len(self.nodes[0].exodus_listpendingmints()))
        assert_equal(
            "99", self.nodes[0].exodus_getbalance(addr,
                                                  sigmaProperty)['balance'])

        self.nodes[0].generate(1)
        assert_equal(0, len(self.nodes[0].exodus_listpendingmints()))
        assert_equal(1, len(self.nodes[0].exodus_listmints()))
Exemple #7
0
    def run_test(self):
        super().run_test()

        # check parameter value validation
        assert_raises_message(JSONRPCException, 'Invalid address',
                              self.nodes[0].elysium_sendissuancemanaged, 'abc',
                              1, 1, 0, 'category1', 'subcategory1', 'token1',
                              'http://foo.com', 'data1')

        assert_raises_message(JSONRPCException,
                              'Invalid ecosystem (1 = main, 2 = test only)',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 0, 1, 0, 'category1',
                              'subcategory1', 'token1', 'http://foo.com',
                              'data1')

        assert_raises_message(JSONRPCException,
                              'Invalid ecosystem (1 = main, 2 = test only)',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 3, 1, 0, 'category1',
                              'subcategory1', 'token1', 'http://foo.com',
                              'data1')

        assert_raises_message(
            JSONRPCException,
            'Invalid property type (1 = indivisible, 2 = divisible only)',
            self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 0, 0,
            'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1')

        assert_raises_message(
            JSONRPCException,
            'Invalid property type (1 = indivisible, 2 = divisible only)',
            self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 3, 0,
            'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1')

        assert_raises_message(
            JSONRPCException,
            'Property appends/replaces are not yet supported',
            self.nodes[0].elysium_sendissuancemanaged, self.addrs[0], 1, 1, 1,
            'category1', 'subcategory1', 'token1', 'http://foo.com', 'data1')

        assert_raises_message(JSONRPCException,
                              'Text must not be longer than 255 characters',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'c' * 256,
                              'subcategory1', 'token1', 'http://foo.com',
                              'data1')

        assert_raises_message(JSONRPCException,
                              'Text must not be longer than 255 characters',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'category1', 's' * 256,
                              'token1', 'http://foo.com', 'data1')

        assert_raises_message(JSONRPCException,
                              'Text must not be longer than 255 characters',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'category1',
                              'subcategory1', 't' * 256, 'http://foo.com',
                              'data1')

        assert_raises_message(JSONRPCException,
                              'Text must not be longer than 255 characters',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'category1',
                              'subcategory1', 'token1', 'h' * 256, 'data1')

        assert_raises_message(JSONRPCException,
                              'Text must not be longer than 255 characters',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'category1',
                              'subcategory1', 'token1', 'http://foo.com',
                              'd' * 256)

        assert_raises_message(JSONRPCException,
                              'Property name must not be empty',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'category1',
                              'subcategory1', '', 'http://foo.com', 'data1')

        assert_raises_message(JSONRPCException, 'Sigma status is not valid',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'category1',
                              'subcategory1', 'token1', 'http://foo.com',
                              'data1', 4)

        assert_raises_message(JSONRPCException,
                              'Sigma feature is not activated yet',
                              self.nodes[0].elysium_sendissuancemanaged,
                              self.addrs[0], 1, 1, 0, 'category1',
                              'subcategory1', 'token1', 'http://foo.com',
                              'data1', 1)

        # create properties
        tx1 = self.nodes[0].elysium_sendissuancemanaged(
            self.addrs[0], 1, 1, 0, 'main', 'indivisible', 'token1',
            'http://token1.com', 'data1')
        self.nodes[0].generate(
            150)  # we need 100 blocks in order to specify sigma flag
        self.sync_all()

        tx2 = self.nodes[1].elysium_sendissuancemanaged(
            self.addrs[1], 1, 2, 0, 'main', 'divisible', 'token2',
            'http://token2.com', 'data2', 0)
        self.nodes[1].generate(1)
        self.sync_all()

        tx3 = self.nodes[2].elysium_sendissuancemanaged(
            self.addrs[2], 2, 1, 0, 'test', 'indivisible', 'token3',
            'http://token3.com', 'data3', 1)
        self.nodes[2].generate(1)
        self.sync_all()

        tx4 = self.nodes[3].elysium_sendissuancemanaged(
            self.addrs[3], 2, 2, 0, 'test', 'divisible', 'token4',
            'http://token4.com', 'data4', 2)
        self.nodes[3].generate(1)
        self.sync_all()

        tx5 = self.nodes[0].elysium_sendissuancemanaged(
            self.addrs[0], 1, 1, 0, 'main', 'indivisible', 'token5',
            'http://token5.com', 'data5', 3)
        self.nodes[0].generate(1)
        self.sync_all()

        # check property creation
        props = self.nodes[0].elysium_listproperties()

        assert_equal(len(props),
                     2 + 5)  # 2 pre-defined properties + 5 new created

        self.assert_property_summary(props[2], 3, False, 'main', 'indivisible',
                                     'token1', 'http://token1.com', 'data1')
        self.assert_property_summary(props[3], 4, True, 'main', 'divisible',
                                     'token2', 'http://token2.com', 'data2')
        self.assert_property_summary(
            props[4], 5, False, 'main', 'indivisible', 'token5',
            'http://token5.com', 'data5')  # main eco tokens will come first
        self.assert_property_summary(props[5], 2147483651, False, 'test',
                                     'indivisible', 'token3',
                                     'http://token3.com', 'data3')
        self.assert_property_summary(props[6], 2147483652, True, 'test',
                                     'divisible', 'token4',
                                     'http://token4.com', 'data4')

        self.assert_property_info(self.nodes[1].elysium_getproperty(3), 3,
                                  False, self.addrs[0], False, 'main',
                                  'indivisible', 'token1', 'http://token1.com',
                                  'data1', '0', 'SoftDisabled', tx1, [])
        self.assert_property_info(self.nodes[2].elysium_getproperty(4), 4,
                                  False, self.addrs[1], True, 'main',
                                  'divisible', 'token2', 'http://token2.com',
                                  'data2', '0.00000000', 'SoftDisabled', tx2,
                                  [])
        self.assert_property_info(self.nodes[1].elysium_getproperty(5), 5,
                                  False, self.addrs[0], False, 'main',
                                  'indivisible', 'token5', 'http://token5.com',
                                  'data5', '0', 'HardEnabled', tx5, [])
        self.assert_property_info(
            self.nodes[3].elysium_getproperty(2147483651), 2147483651, False,
            self.addrs[2], False, 'test', 'indivisible', 'token3',
            'http://token3.com', 'data3', '0', 'SoftEnabled', tx3, [])
        self.assert_property_info(
            self.nodes[0].elysium_getproperty(2147483652), 2147483652, False,
            self.addrs[3], True, 'test', 'divisible', 'token4',
            'http://token4.com', 'data4', '0.00000000', 'HardDisabled', tx4,
            [])
Exemple #8
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(10)
        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(10)
        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 #9
0
    def run_test(self):
        super().run_test()

        sigma_starting_block = 550

        self.nodes[0].generatetoaddress(
            sigma_starting_block - self.nodes[0].getblockcount(),
            self.addrs[0])
        self.sync_all()

        assert_equal(sigma_starting_block, self.nodes[0].getblockcount())

        # non-sigma
        self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, 'main', \
            'indivisible', 'non-sigma', '', '', '1000000')
        self.nodes[0].generate(1)

        nonSigmaProperty = 3

        addr = self.nodes[1].getnewaddress()
        self.nodes[0].elysium_send(self.addrs[0], addr, nonSigmaProperty,
                                   '100')
        self.nodes[0].generate(1)

        self.sync_all()

        assert_raises_message(JSONRPCException, 'Denomination is not valid',
                              self.nodes[1].elysium_sendspend, self.addrs[1],
                              nonSigmaProperty, 0)

        # sigma
        self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, 'main', \
            'indivisible', 'sigma', '', '', '1000000', 1)
        self.nodes[0].generate(1)

        sigmaProperty = 4

        addr = self.nodes[1].getnewaddress()
        self.nodes[0].elysium_send(self.addrs[0], addr, sigmaProperty, '100')

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

        assert_raises_message(JSONRPCException, 'Denomination is not valid',
                              self.nodes[1].elysium_sendspend, self.addrs[1],
                              sigmaProperty, 0)

        # generate some denominations and mint
        self.nodes[0].elysium_sendcreatedenomination(self.addrs[0],
                                                     sigmaProperty, '1')
        self.nodes[0].generate(1)
        self.nodes[0].elysium_sendcreatedenomination(self.addrs[0],
                                                     sigmaProperty, '2')
        self.nodes[0].generate(10)
        self.sync_all()

        # spend without any mint
        assert_raises_message(JSONRPCException, 'No available mint to spend',
                              self.nodes[1].elysium_sendspend, self.addrs[1],
                              sigmaProperty, 0)

        # have sigma mint but have no elysium mint
        testing_node = self.nodes[1]  # fresh node
        addr = testing_node.getnewaddress()
        self.nodes[0].sendtoaddress(addr, '100')
        self.nodes[0].generate(1)
        self.sync_all()

        testing_node.mint(2)
        self.nodes[0].generate(10)
        self.sync_all()

        assert_raises_message(JSONRPCException, 'No available mint to spend',
                              testing_node.elysium_sendspend, self.addrs[1],
                              sigmaProperty, 0)

        # have elysium mint have no sigma mint to spend
        testing_node = self.nodes[2]  # fresh node
        addr = testing_node.getnewaddress()
        self.nodes[0].sendtoaddress(addr, '100')
        self.nodes[0].elysium_send(self.addrs[0], addr, sigmaProperty, '100')
        self.nodes[0].generate(1)
        self.sync_all()

        testing_node.elysium_sendmint(addr, sigmaProperty, {"0": 2})
        testing_node.generate(1)
        self.sync_all()
        time.sleep(1)

        assert_raises_message(
            JSONRPCException, 'Error no sigma mints to pay as transaction fee',
            self.nodes[2].elysium_sendspend, self.addrs[0], sigmaProperty, 0)

        # met all requirements
        testing_node.mint(2)
        testing_node.generate(10)
        self.sync_all()

        receiver = self.nodes[0].getnewaddress()

        testing_node.elysium_sendspend(receiver, sigmaProperty, 0)
        testing_node.elysium_sendspend(receiver, sigmaProperty, 0)

        testing_node.generate(1)
        self.sync_all()

        assert_equal(
            '2', self.nodes[0].elysium_getbalance(receiver,
                                                  sigmaProperty)['balance'])
Exemple #10
0
    def test_received_sprout(self, height):
        self.generate_and_sync(height+2)

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

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

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

        self.sync_all()

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

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

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

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

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

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

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

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

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

        taddr = self.nodes[1].getnewaddress()
        # Generate some change by sending part of zaddr1 back to taddr
        opid = self.nodes[1].z_sendmany(zaddr1, [{'address': taddr, 'amount': 0.6}], 1)
        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 #11
0
    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},
        ], 1)
        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}], 1)
        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}], 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]
Exemple #12
0
    def run_test(self):
        # With a new wallet, the first account will be 0.
        account0 = self.nodes[0].z_getnewaccount()
        assert_equal(account0['account'], 0)

        # Verify that just creating the account does not generate any visible addresses
        addresses = self.nodes[0].z_listaddresses()
        assert_equal([], addresses)
        accounts = self.nodes[0].z_listaccounts()
        assert_equal(len(accounts), 1)
        assert_equal(accounts[0]['account'], 0)

        # The next account will be 1.
        account1 = self.nodes[0].z_getnewaccount()
        assert_equal(account1['account'], 1)
        accounts = self.nodes[0].z_listaccounts()
        assert_equal(len(accounts), 2)
        assert_equal(accounts[1]['account'], 1)

        # Generate the first address for account 0.
        addr0 = self.nodes[0].z_getaddressforaccount(0)
        assert_equal(addr0['account'], 0)
        assert_equal(set(addr0['receiver_types']), set(['p2pkh', 'sapling', 'orchard']))
        ua0 = addr0['address']
        self.check_z_listaccounts(0, 0, 0, addr0)

        # We pick mnemonic phrases to ensure that we can always generate the default
        # address in account 0; this is however not necessarily at diversifier index 0.
        # We should be able to generate it directly and get the exact same data.
        j = addr0['diversifier_index']
        assert_equal(self.nodes[0].z_getaddressforaccount(0, [], j), addr0)
        if j > 0:
            # We should get an error if we generate the address at diversifier index 0.
            assert_raises_message(
                JSONRPCException,
                'no address at diversifier index 0',
                self.nodes[0].z_getaddressforaccount, 0, [], 0)

        # The second address for account 0 is different to the first address.
        addr0_2 = self.nodes[0].z_getaddressforaccount(0)
        assert_equal(addr0_2['account'], 0)
        assert_equal(set(addr0_2['receiver_types']), set(['p2pkh', 'sapling', 'orchard']))
        ua0_2 = addr0_2['address']
        assert(ua0 != ua0_2)
        self.check_z_listaccounts(0, 0, 1, addr0_2)

        # We can generate a fully-shielded address.
        addr0_3 = self.nodes[0].z_getaddressforaccount(0, ['sapling', 'orchard'])
        assert_equal(addr0_3['account'], 0)
        assert_equal(set(addr0_3['receiver_types']), set(['sapling', 'orchard']))
        ua0_3 = addr0_3['address']
        self.check_z_listaccounts(0, 0, 2, addr0_3)

        # We can generate an address without a Sapling receiver.
        addr0_4 = self.nodes[0].z_getaddressforaccount(0, ['p2pkh', 'orchard'])
        assert_equal(addr0_4['account'], 0)
        assert_equal(set(addr0_4['receiver_types']), set(['p2pkh', 'orchard']))
        ua0_4 = addr0_4['address']
        self.check_z_listaccounts(0, 0, 3, addr0_4)

        # The first address for account 1 is different to account 0.
        addr1 = self.nodes[0].z_getaddressforaccount(1)
        assert_equal(addr1['account'], 1)
        assert_equal(set(addr1['receiver_types']), set(['p2pkh', 'sapling', 'orchard']))
        ua1 = addr1['address']
        assert(ua0 != ua1)
        self.check_z_listaccounts(0, 1, 0, addr1)

        # The UA contains the expected receiver kinds.
        self.check_receiver_types(ua0,   ['p2pkh', 'sapling', 'orchard'])
        self.check_receiver_types(ua0_2, ['p2pkh', 'sapling', 'orchard'])
        self.check_receiver_types(ua0_3, [               'sapling', 'orchard'])
        self.check_receiver_types(ua0_4, ['p2pkh',            'orchard'])
        self.check_receiver_types(ua1,   ['p2pkh', 'sapling', 'orchard'])

        # The balances of the accounts are all zero.
        self.check_balance(0, 0, ua0, {})
        self.check_balance(0, 1, ua1, {})

        # Send coinbase funds to the UA.
        print('Sending coinbase funds to account')
        recipients = [{'address': ua0, 'amount': Decimal('10')}]
        opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
        txid = wait_and_assert_operationid_status(self.nodes[0], opid)

        # The wallet should detect the new note as belonging to the UA.
        tx_details = self.nodes[0].z_viewtransaction(txid)
        assert_equal(len(tx_details['outputs']), 1)
        assert_equal(tx_details['outputs'][0]['type'], 'sapling')
        assert_equal(tx_details['outputs'][0]['address'], ua0)

        # The new balance should not be visible with the default minconf, but should be
        # visible with minconf=0.
        self.sync_all()
        self.check_balance(0, 0, ua0, {})
        self.check_balance(0, 0, ua0, {'sapling': 10}, 0)

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

        # The default minconf should now detect the balance.
        self.check_balance(0, 0, ua0, {'sapling': 10})

        # Send Sapling funds from the UA.
        print('Sending account funds to Sapling address')
        node1sapling = self.nodes[1].z_getnewaddress('sapling')

        recipients = [{'address': node1sapling, 'amount': Decimal('1')}]
        opid = self.nodes[0].z_sendmany(ua0, recipients, 1, 0)
        txid = wait_and_assert_operationid_status(self.nodes[0], opid)

        # The wallet should detect the spent note as belonging to the UA.
        tx_details = self.nodes[0].z_viewtransaction(txid)
        assert_equal(len(tx_details['spends']), 1)
        assert_equal(tx_details['spends'][0]['type'], 'sapling')
        assert_equal(tx_details['spends'][0]['address'], ua0)

        # The balances of the account should reflect whether zero-conf transactions are
        # being considered. We will show either 0 (because the spent 10-ZEC note is never
        # shown, as that transaction has been created and broadcast, and _might_ get mined
        # up until the transaction expires), or 9 (if we include the unmined transaction).
        self.sync_all()
        self.check_balance(0, 0, ua0, {})
        self.check_balance(0, 0, ua0, {'sapling': 9}, 0)

        # Activate NU5
        print('Activating NU5')
        self.nodes[2].generate(9)
        self.sync_all()
        assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 210)

        # Send more coinbase funds to the UA.
        print('Sending coinbase funds to account')
        recipients = [{'address': ua0, 'amount': Decimal('10')}]
        opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
        txid = wait_and_assert_operationid_status(self.nodes[0], opid)

        # The wallet should detect the new note as belonging to the UA.
        tx_details = self.nodes[0].z_viewtransaction(txid)
        assert_equal(len(tx_details['outputs']), 1)
        assert_equal(tx_details['outputs'][0]['type'], 'orchard')
        assert_equal(tx_details['outputs'][0]['address'], ua0)

        # The new balance should not be visible with the default minconf, but should be
        # visible with minconf=0.
        self.sync_all()
        self.check_balance(0, 0, ua0, {'sapling': 9})
        self.check_balance(0, 0, ua0, {'sapling': 9, 'orchard': 10}, 0)

        # The total balance with the default minconf should be just the Sapling balance
        assert_equal('9.00', self.nodes[0].z_gettotalbalance()['private'])
        assert_equal('19.00', self.nodes[0].z_gettotalbalance(0)['private'])

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

        # Send Orchard funds from the UA.
        print('Sending account funds to Orchard-only UA')
        node1account = self.nodes[1].z_getnewaccount()['account']
        node1orchard = self.nodes[1].z_getaddressforaccount(node1account, ['orchard'])
        self.check_z_listaccounts(1, 0, 0, node1orchard)
        node1orchard = node1orchard['address']

        recipients = [{'address': node1orchard, 'amount': Decimal('1')}]
        opid = self.nodes[0].z_sendmany(ua0, recipients, 1, 0)
        txid = wait_and_assert_operationid_status(self.nodes[0], opid)

        # The wallet should detect the spent note as belonging to the UA.
        tx_details = self.nodes[0].z_viewtransaction(txid)
        assert_equal(len(tx_details['spends']), 1)
        assert_equal(tx_details['spends'][0]['type'], 'orchard')
        assert_equal(tx_details['spends'][0]['address'], ua0)

        assert_equal(len(tx_details['outputs']), 2)
        outputs = sorted(tx_details['outputs'], key=lambda x: x['valueZat'])
        assert_equal(outputs[0]['type'], 'orchard')
        assert_equal(outputs[0]['address'], node1orchard)
        assert_equal(outputs[0]['valueZat'], 100000000)
        # outputs[1] is change
        assert_equal(outputs[1]['type'], 'orchard')
        assert_true('address' not in outputs[1]) #

        # The balances of the account should reflect whether zero-conf transactions are
        # being considered. The Sapling balance should remain at 9, while the Orchard
        # balance will show either 0 (because the spent 10-ZEC note is never shown, as
        # that transaction has been created and broadcast, and _might_ get mined up until
        # the transaction expires), or 9 (if we include the unmined transaction).
        self.sync_all()
        self.check_balance(0, 0, ua0, {'sapling': 9})
        self.check_balance(0, 0, ua0, {'sapling': 9, 'orchard': 9}, 0)
Exemple #13
0
    def run_test(self):
        tmpdir = self.options.tmpdir

        # Make sure we use hd, keep masterkeyid
        masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid']
        assert_equal(len(masterkeyid), 40)

        # Check that the exported master private key begins with tprv
        xprv = self.nodes[1].dumpmasterprivkey()
        assert_equal(xprv[0:4], "tprv")

        # Exporting the master private key should fail on a non-HD wallet
        assert_raises_message(JSONRPCException, "Wallet is not a HD wallet.",
                              self.nodes[0].dumpmasterprivkey)

        # Import a non-HD private key in the HD wallet
        non_hd_add = self.nodes[0].getnewaddress()
        self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))

        # This should be enough to keep the master key and the non-HD key
        self.nodes[1].backupwallet(tmpdir + "/hd.bak")
        #self.nodes[1].dumpwallet(tmpdir + "/hd.dump")

        # Derive some HD addresses and remember the last
        # Also send funds to each add
        self.nodes[0].generate(101)
        hd_add = None
        num_hd_adds = 300
        for i in range(num_hd_adds):
            hd_add = self.nodes[1].getnewaddress()
            hd_info = self.nodes[1].validateaddress(hd_add)
            assert_equal(hd_info["hdkeypath"], "m/0'/0'/" + str(i + 1) + "'")
            assert_equal(hd_info["hdmasterkeyid"], masterkeyid)
            self.nodes[0].sendtoaddress(hd_add, 1)
            self.nodes[0].generate(1)
        self.nodes[0].sendtoaddress(non_hd_add, 1)
        self.nodes[0].generate(1)

        self.sync_all()
        assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)

        print("Restore backup ...")
        self.stop_node(1)
        os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
        shutil.copyfile(tmpdir + "/hd.bak",
                        tmpdir + "/node1/regtest/wallet.dat")
        self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1])
        #connect_nodes_bi(self.nodes, 0, 1)

        # Assert that derivation is deterministic
        hd_add_2 = None
        for _ in range(num_hd_adds):
            hd_add_2 = self.nodes[1].getnewaddress()
            hd_info_2 = self.nodes[1].validateaddress(hd_add_2)
            assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/" + str(_ + 1) + "'")
            assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid)
        assert_equal(hd_add, hd_add_2)

        # Needs rescan
        self.stop_node(1)
        self.nodes[1] = start_node(1, self.options.tmpdir,
                                   self.node_args[1] + ['-rescan'])
        #connect_nodes_bi(self.nodes, 0, 1)
        assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
Exemple #14
0
    def run_test(self):
        # With a new wallet, the first account will be 0.
        account0 = self.nodes[0].z_getnewaccount()
        assert_equal(account0['account'], 0)

        # The next account will be 1.
        account1 = self.nodes[0].z_getnewaccount()
        assert_equal(account1['account'], 1)

        # Generate the first address for account 0.
        addr0 = self.nodes[0].z_getaddressforaccount(0)
        assert_equal(addr0['account'], 0)
        assert_equal(set(addr0['pools']), set(['transparent', 'sapling']))
        ua0 = addr0['unifiedaddress']

        # We pick mnemonic phrases to ensure that we can always generate the default
        # address in account 0; this is however not necessarily at diversifier index 0.
        # We should be able to generate it directly and get the exact same data.
        j = addr0['diversifier_index']
        assert_equal(self.nodes[0].z_getaddressforaccount(0, [], j), addr0)
        if j > 0:
            # We should get an error if we generate the address at diversifier index 0.
            assert_raises_message(JSONRPCException,
                                  'no address at diversifier index 0',
                                  self.nodes[0].z_getaddressforaccount, 0, [],
                                  0)

        # The first address for account 1 is different to account 0.
        addr1 = self.nodes[0].z_getaddressforaccount(1)
        assert_equal(addr1['account'], 1)
        assert_equal(set(addr1['pools']), set(['transparent', 'sapling']))
        ua1 = addr1['unifiedaddress']
        assert (ua0 != ua1)

        # The UA contains the expected receiver kinds.
        self.check_receiver_types(ua0, ['transparent', 'sapling'])
        self.check_receiver_types(ua1, ['transparent', 'sapling'])

        # The balances of the accounts are all zero.
        self.check_balance(0, 0, ua0, {})
        self.check_balance(0, 1, ua1, {})

        # Manually send funds to one of the receivers in the UA.
        recipients = [{'address': ua0, 'amount': Decimal('10')}]
        opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]),
                                        recipients, 1, 0)
        txid = wait_and_assert_operationid_status(self.nodes[0], opid)

        # The wallet should detect the new note as belonging to the UA.
        tx_details = self.nodes[0].z_viewtransaction(txid)
        assert_equal(len(tx_details['outputs']), 1)
        assert_equal(tx_details['outputs'][0]['type'], 'sapling')
        assert_equal(tx_details['outputs'][0]['address'], ua0)

        # The new balance should not be visible with the default minconf, but should be
        # visible with minconf=0.
        self.sync_all()
        self.check_balance(0, 0, ua0, {})
        self.check_balance(0, 0, ua0, {'sapling': 10}, 0)

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

        # The default minconf should now detect the balance.
        self.check_balance(0, 0, ua0, {'sapling': 10})

        # Manually send funds from the UA receiver.
        node1sapling = self.nodes[1].z_getnewaddress('sapling')
        recipients = [{'address': node1sapling, 'amount': Decimal('1')}]
        opid = self.nodes[0].z_sendmany(ua0, recipients, 1, 0)
        txid = wait_and_assert_operationid_status(self.nodes[0], opid)

        # The wallet should detect the spent note as belonging to the UA.
        tx_details = self.nodes[0].z_viewtransaction(txid)
        assert_equal(len(tx_details['spends']), 1)
        assert_equal(tx_details['spends'][0]['type'], 'sapling')
        assert_equal(tx_details['spends'][0]['address'], ua0)

        # The balances of the account should reflect whether zero-conf transactions are
        # being considered. We will show either 0 (because the spent 10-ZEC note is never
        # shown, as that transaction has been created and broadcast, and _might_ get mined
        # up until the transaction expires), or 9 (if we include the unmined transaction).
        self.sync_all()
        self.check_balance(0, 0, ua0, {})
        self.check_balance(0, 0, ua0, {'sapling': 9}, 0)
    def run_test(self):
        print("---- Pastel ID tests STARTED ----")
        print(" -pastelid help")
        assert_shows_help(self.nodes[0].pastelid)

        coinbase_addr1 = self.nodes[1].getnewaddress()
        taddr1 = self.nodes[1].getnewaddress()

        print(" -pastelid newkey")
        assert_shows_help(self.nodes[0].pastelid, "newkey")
        self.pastelid1, self.id1_lrkey = self.create_pastelid(0)
        self.pastelid2 = self.create_pastelid()[0]
        self.pastelid3, self.id3_lrkey = self.create_pastelid(1)
        print(f"pastelid1: {self.pastelid1}")
        print(f"pastelid2: {self.pastelid2}")
        print(f"pastelid3: {self.pastelid3}")

        # fail if empty passphrase
        assert_raises_rpc(rpc.RPC_MISC_ERROR, "passphrase for new key cannot be empty", 
            self.nodes[0].pastelid, "newkey", "")

        # List all internally stored PastelID and keys
        print(" -pastelid list")
        # check Pastel IDs on node0
        id_list0 = self.nodes[0].pastelid("list")
        id_list0 = dict((key+str(i), val) for i, k in enumerate(id_list0) for key, val in k.items())
        assert_true(self.pastelid1 in id_list0.values(), f"PastelID {self.pastelid1} not in the list")
        assert_true(self.pastelid2 in id_list0.values(), f"PastelID {self.pastelid2} not in the list")
        # check Pastel IDs on node1
        id_list1 = self.nodes[1].pastelid("list")
        id_list1 = dict((key+str(i), val) for i, k in enumerate(id_list1) for key, val in k.items())
        assert_true(self.pastelid3 in id_list1.values(), f"PastelID {self.pastelid3} not in the list")

        print(" -pastelid sign & verify ed448")
        text_to_sign = "my text to sign"
        # Sign "text" with the internally stored private key associated with the PastelID
        # check that signing with existing passphrase works, default algorithm - EdDSA448
        signature = self.nodes[0].pastelid("sign", text_to_sign, self.pastelid1, self.passphrase)["signature"]
        assert_true(signature, "Cannot sign text using existing passphrase. No ed448 signature was created")
        assert_equal(len(base64.b64decode(signature)), 114)
        # Verify text"'s "signature" (EdDSA448) with the PastelID
        result = self.nodes[0].pastelid("verify", text_to_sign, signature, self.pastelid1)["verification"]
        assert_equal(result, "OK")
        # Fail to verify EdDSA448 signature with the different key (PastelID2)
        result = self.nodes[0].pastelid("verify", text_to_sign, signature, self.pastelid2)["verification"]
        assert_equal(result, "Failed")
        # Fail to verify modified text (ed448 signature)
        text_to_sign_modified = 'X' + text_to_sign[1:]
        result = self.nodes[0].pastelid("verify", text_to_sign_modified, signature, self.pastelid1)["verification"]
        assert_equal(result, "Failed")
        # try to sign using PastelID with invalid passphrase
        assert_raises_rpc(rpc.RPC_MISC_ERROR, self.ERR_READ_PASTELID_FILE,
            self.nodes[1].pastelid, "sign", text_to_sign, self.pastelid1, self.new_passphrase)

        print(" -pastelid sign & verify legroast")
        # Sign with no errors using encoded LegRoast public key
        # returns base64 encoded signature
        lr_signature = self.nodes[0].pastelid("sign", text_to_sign, self.pastelid1, self.passphrase, "legroast")["signature"]
        assert_true(lr_signature, "Cannot sign text using existing passphrase. No LegRoast signature was created")
        assert_equal(len(base64.b64decode(lr_signature)), 14272)
        # Verify text"'s "signature" (LegRoast) with the PastelID
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid1, "legroast")["verification"]
        assert_equal(result, "OK")
        # Fail to verify LegRoast signature with the different key (PastelID2)
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid2, "legroast")["verification"]
        assert_equal(result, "Failed")
        # Fail to verify modified text (LegRoast signature)
        result = self.nodes[0].pastelid("verify", text_to_sign_modified, lr_signature, self.pastelid1, "legroast")["verification"]
        assert_equal(result, "Failed")
        
        # Sign message on node1 with the LegRoast key associated with pastelid3 
        lr_signature = self.nodes[1].pastelid("sign", text_to_sign, self.pastelid3, self.passphrase, "legroast")["signature"]
        assert_true(lr_signature, "Cannot sign text on node1 with LegRoast key associated with pastelid3. No LegRoast signature was created")
        # ... but verify it on node0 that does not have pastelid3 and we don't have any PastelID reg tickets
        assert_raises_rpc(rpc.RPC_MISC_ERROR, "is not stored locally and PastelID registration ticket was not found in the blockchain",
            self.nodes[0].pastelid, "verify", text_to_sign, lr_signature, self.pastelid3, "legroast")
        # now let's register pastelid3
        self.generate_and_sync_inc(10)
        # send all utxos from node #3 to addr[0] to make empty balance
        self.nodes[0].sendtoaddress(taddr1, self.nodes[0].getbalance(), "empty node0", "test", True)
        self.generate_and_sync_inc(1)
        # register pastelid3
        txid = self.nodes[1].tickets("register", "id", self.pastelid3, self.passphrase, taddr1)
        assert_true(txid, "pastelid3 registration failed")
        self.generate_and_sync_inc(1)

        # now we should be able to retrieve lr pubkey for pastelid3 on node0
        # but first make sure pastelid3 is not stored locally on node0
        assert_true(self.pastelid3 not in id_list0.values(), f"PastelID3 {self.pastelid3} should not be stored on node0")
           # Verify text"'s "signature" (LegRoast) with the PastelID3
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid3, "legroast")["verification"]
        assert_equal(result, "OK")
         # Fail to verify LegRoast signature with the different key (PastelID1)
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid1, "legroast")["verification"]
        assert_equal(result, "Failed")
        # Fail to verify modified text (LegRoast signature)
        result = self.nodes[0].pastelid("verify", text_to_sign_modified, lr_signature, self.pastelid3, "legroast")["verification"]
        assert_equal(result, "Failed")
       

        print(" -pastelid passwd")
        assert_shows_help(self.nodes[0].pastelid, "passwd")
        # missing new passphrase
        assert_raises(JSONRPCException, self.nodes[0].pastelid, "passwd", self.pastelid1, self.passphrase)
        # empty new passphrase
        assert_raises_message(JSONRPCException, "cannot be empty", 
            self.nodes[0].pastelid, "passwd", self.pastelid1, self.passphrase, "")
        # empty Pastel ID
        assert_raises_message(JSONRPCException, "cannot be empty", 
            self.nodes[0].pastelid, "passwd", "", self.passphrase, self.new_passphrase)
        # empty passphrase
        assert_raises_message(JSONRPCException, "cannot be empty", 
            self.nodes[0].pastelid, "passwd", self.pastelid1, "", self.new_passphrase)
        # change passphrase
        result = self.nodes[0].pastelid("passwd", self.pastelid1, self.passphrase, self.new_passphrase)["result"]
        assert_equal(result, "successful")
        # try to sign text using old passphrase
        assert_raises_message(JSONRPCException, "Failed to decrypt", self.nodes[0].pastelid, "sign", text_to_sign, self.pastelid1, self.passphrase)
        # signing using new passphrase should work
        signature = self.nodes[0].pastelid("sign", text_to_sign, self.pastelid1, self.new_passphrase)["signature"]
        assert_true(signature, "Cannot sign text using existing passphrase. No ed448 signature was created")
        # verify signature
        result = self.nodes[0].pastelid("verify", text_to_sign, signature, self.pastelid1)["verification"]
        assert_equal(result, "OK")
        print("----- Pastel ID tests FINISHED -----")
Exemple #16
0
    def run_test (self):
        tmpdir = self.options.tmpdir

        # Make sure can't switch off usehd after wallet creation
        self.stop_node(1)
        self.assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet')
        self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1])
        connect_nodes_bi(self.nodes, 0, 1)

        # Make sure we use hd, keep masterkeyid
        masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid']
        assert_equal(len(masterkeyid), 40)

        # create an internal key
        change_addr = self.nodes[1].getrawchangeaddress()
        change_addrV= self.nodes[1].validateaddress(change_addr)
        assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key

        # Check that the exported master private key begins with tprv
        xprv = self.nodes[1].dumpmasterprivkey()
        assert_equal(xprv[0:4], "tprv")

        # Exporting the master private key should fail on a non-HD wallet
        assert_raises_message(JSONRPCException, "Wallet is not a HD wallet.", self.nodes[0].dumpmasterprivkey)

        # Import a non-HD private key in the HD wallet
        non_hd_add = self.nodes[0].getnewaddress()
        self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))

        # This should be enough to keep the master key and the non-HD key
        self.nodes[1].backupwallet(tmpdir + "/hd.bak")
        #self.nodes[1].dumpwallet(tmpdir + "/hd.dump")

        # Derive some HD addresses and remember the last
        # Also send funds to each add
        self.nodes[0].generate(101)
        hd_add = None
        num_hd_adds = 300
        for i in range(num_hd_adds):
            hd_add = self.nodes[1].getnewaddress()
            hd_info = self.nodes[1].validateaddress(hd_add)
            assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i+1)+"'")
            assert_equal(hd_info["hdmasterkeyid"], masterkeyid)
            self.nodes[0].sendtoaddress(hd_add, 1)
            self.nodes[0].generate(1)
        self.nodes[0].sendtoaddress(non_hd_add, 1)
        self.nodes[0].generate(1)

        # create an internal key (again)
        change_addr = self.nodes[1].getrawchangeaddress()
        change_addrV= self.nodes[1].validateaddress(change_addr)
        assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key

        self.sync_all()
        assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)

        self.log.info("Restore backup ...")
        self.stop_node(1)
        # we need to delete the complete regtest directory
        # otherwise node1 would auto-recover all funds in flag the keypool keys as used
        shutil.rmtree(tmpdir + "/node1/regtest/blocks")
        shutil.rmtree(tmpdir + "/node1/regtest/chainstate")
        shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
        self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1])

        # Assert that derivation is deterministic
        hd_add_2 = None
        for _ in range(num_hd_adds):
            hd_add_2 = self.nodes[1].getnewaddress()
            hd_info_2 = self.nodes[1].validateaddress(hd_add_2)
            assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_+1)+"'")
            assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid)
        assert_equal(hd_add, hd_add_2)
        connect_nodes_bi(self.nodes, 0, 1)
        self.sync_all()

        # Needs rescan
        self.stop_node(1)
        self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1] + ['-rescan'])
        assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)

        # Try a RPC based rescan
        self.stop_node(1)
        shutil.rmtree(tmpdir + "/node1/regtest/blocks")
        shutil.rmtree(tmpdir + "/node1/regtest/chainstate")
        shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
        self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1])
        connect_nodes_bi(self.nodes, 0, 1)
        self.sync_all()
        out = self.nodes[1].rescanblockchain(0,1)
        assert_equal(out['startheight'], 0)
        assert_equal(out['stopheight'], 1)
        out = self.nodes[1].rescanblockchain()
        assert_equal(out['startheight'], 0)
        assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)

        # send a tx and make sure its using the internal chain for the changeoutput
        txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']
        keypath = ""
        for out in outs:
            if out['value'] != 1:
                keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath']

        assert_equal(keypath[0:7], "m/0'/1'")
Exemple #17
0
 def assert_disable_nonhd(self, fn, *args):
     assert_raises_message(JSONRPCException, "sigma mint/spend is not allowed for legacy wallet", \
         fn, *args)
Exemple #18
0
 def _test_getdifficulty(self):
     assert_raises_message(
         JSONRPCException,
         "getdifficulty is DEPRECATED for elements (which lacks pow), always returns this error",
         self.nodes[0].getdifficulty)
Exemple #19
0
    def run_test(self):
        super().run_test()

        # create non-sigma token
        self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 1, 0, '', '',
                                                'Normal Token', '', '',
                                                '1000000')
        self.nodes[0].generate(1)
        self.sync_all()

        # create sigma token
        self.nodes[0].elysium_sendissuancefixed(self.addrs[0], 1, 2, 0, '', '',
                                                'Sigma Token', '', '',
                                                '1000000', 1)
        self.nodes[0].generate(1)

        self.sync_all()

        # test parameter value validation
        assert_raises_message(JSONRPCException, 'Invalid address',
                              self.nodes[0].elysium_sendcreatedenomination,
                              'abc', 4, '1')

        assert_raises_message(JSONRPCException,
                              'Property identifier is out of range',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], -1, '1')

        assert_raises_message(JSONRPCException,
                              'Property identifier is out of range',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], 0, '1')

        assert_raises_message(JSONRPCException,
                              'Property identifier is out of range',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], 4294967296, '1')

        assert_raises_message(
            JSONRPCException,
            'Invalid amount',
            self.nodes[0].elysium_sendcreatedenomination,
            self.addrs[0],
            3,
            '0.1'  # fixed property will discard all fractional, so it will become 0
        )

        assert_raises_message(JSONRPCException, 'Invalid amount',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], 4, '0')

        assert_raises_message(JSONRPCException, 'Invalid amount',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], 4, '-1')

        # test parameter validation
        assert_raises_message(JSONRPCException,
                              'Property identifier does not exist',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], 5, '1')

        assert_raises_message(
            JSONRPCException,
            'Sender is not authorized to manage the property',
            self.nodes[0].elysium_sendcreatedenomination, self.addrs[1], 4,
            '1')

        assert_raises_message(JSONRPCException,
                              'Property has not enabled Sigma',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], 3, '1')

        # test valid denomination creation
        self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], 4, '0.5')
        self.nodes[0].generate(1)
        self.nodes[0].elysium_sendcreatedenomination(self.addrs[0], 4, '1')
        self.nodes[0].generate(1)

        self.sync_all()

        info = self.nodes[1].elysium_getproperty(4)

        assert_equal(info['denominations'][0]['id'], 0)
        assert_equal(info['denominations'][0]['value'], '0.50000000')
        assert_equal(info['denominations'][1]['id'], 1)
        assert_equal(info['denominations'][1]['value'], '1.00000000')

        # test duplicate denomination check
        assert_raises_message(
            JSONRPCException,
            'Denomination with value 0.50000000 already exists',
            self.nodes[0].elysium_sendcreatedenomination, self.addrs[0], 4,
            '0.5')

        # test full denominations check
        for i in range(255 - 2):
            self.nodes[0].elysium_sendcreatedenomination(
                self.addrs[0], 4, str(i + 2))
            self.nodes[0].generate(
                1
            )  # we need to mine here otherwise the input chaining will be too long

        assert_raises_message(JSONRPCException,
                              'No more room for new denomination',
                              self.nodes[0].elysium_sendcreatedenomination,
                              self.addrs[0], 4, '1000')