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()
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))
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()))
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, [])
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))
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'])
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'])
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]
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)
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)
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 -----")
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'")
def assert_disable_nonhd(self, fn, *args): assert_raises_message(JSONRPCException, "sigma mint/spend is not allowed for legacy wallet", \ fn, *args)
def _test_getdifficulty(self): assert_raises_message( JSONRPCException, "getdifficulty is DEPRECATED for elements (which lacks pow), always returns this error", self.nodes[0].getdifficulty)
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')