Fix z_mergetoaddress sending from ANY_SPROUT/ANY_SAPLING when the wallet contains both note types

This commit is contained in:
Eirik0 2019-03-21 18:12:50 -06:00
parent 4c7b44bbdb
commit a8055cfe10
4 changed files with 98 additions and 2 deletions

View File

@ -31,6 +31,7 @@ testScripts=(
'wallet_listnotes.py' 'wallet_listnotes.py'
'mergetoaddress_sprout.py' 'mergetoaddress_sprout.py'
'mergetoaddress_sapling.py' 'mergetoaddress_sapling.py'
'mergetoaddress_mixednotes.py'
'listtransactions.py' 'listtransactions.py'
'mempool_resurrect_test.py' 'mempool_resurrect_test.py'
'txn_doublespend.py' 'txn_doublespend.py'

View File

@ -17,11 +17,12 @@ from decimal import Decimal
def assert_mergetoaddress_exception(expected_error_msg, merge_to_address_lambda): def assert_mergetoaddress_exception(expected_error_msg, merge_to_address_lambda):
try: try:
merge_to_address_lambda() merge_to_address_lambda()
fail("Expected exception: %s" % expected_error_msg)
except JSONRPCException as e: except JSONRPCException as e:
assert_equal(expected_error_msg, e.error['message']) assert_equal(expected_error_msg, e.error['message'])
except Exception as e: except Exception as e:
fail("Expected JSONRPCException. Found %s" % repr(e)) fail("Expected JSONRPCException. Found %s" % repr(e))
else:
fail("Expected exception: %s" % expected_error_msg)
class MergeToAddressHelper: class MergeToAddressHelper:
@ -152,6 +153,11 @@ class MergeToAddressHelper:
"Destination address is also the only source address, and all its funds are already merged.", "Destination address is also the only source address, and all its funds are already merged.",
lambda: test.nodes[0].z_mergetoaddress([mytaddr], mytaddr)) lambda: test.nodes[0].z_mergetoaddress([mytaddr], mytaddr))
# Merging will fail for this specific case where it would spend a fee and do nothing
assert_mergetoaddress_exception(
"Cannot send from both Sprout and Sapling addresses using z_mergetoaddress",
lambda: test.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], mytaddr))
# Merge UTXOs from node 0 of value 30, standard fee of 0.00010000 # Merge UTXOs from node 0 of value 30, standard fee of 0.00010000
result = test.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr) result = test.nodes[0].z_mergetoaddress([mytaddr, mytaddr2, mytaddr3], myzaddr)
wait_and_assert_operationid_status(test.nodes[0], result['opid']) wait_and_assert_operationid_status(test.nodes[0], result['opid'])

View File

@ -0,0 +1,82 @@
#!/usr/bin/env python
# Copyright (c) 2019 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x."
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, get_coinbase_address, \
initialize_chain_clean, start_nodes, wait_and_assert_operationid_status
from mergetoaddress_helper import assert_mergetoaddress_exception
class MergeToAddressMixedNotes(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, [[
'-nuparams=5ba81b19:100', # Overwinter
'-nuparams=76b809bb:100', # Sapling
'-experimentalfeatures', '-zmergetoaddress'
]] * 4)
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def run_test(self):
print "Mining blocks..."
self.nodes[0].generate(102)
self.sync_all()
# Send some ZEC to Sprout/Sapling addresses
coinbase_addr = get_coinbase_address(self.nodes[0])
sproutAddr = self.nodes[0].z_getnewaddress('sprout')
saplingAddr = self.nodes[0].z_getnewaddress('sapling')
t_addr = self.nodes[1].getnewaddress()
opid = self.nodes[0].z_sendmany(coinbase_addr, [{"address": sproutAddr, "amount": Decimal('10')}], 1, 0)
wait_and_assert_operationid_status(self.nodes[0], opid)
self.nodes[0].generate(1)
self.sync_all()
assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10'))
assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0'))
assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('0'))
# Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sprout Notes
assert_mergetoaddress_exception(
"Cannot send from both Sprout and Sapling addresses using z_mergetoaddress",
lambda: self.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], t_addr))
opid = self.nodes[0].z_sendmany(coinbase_addr, [{"address": saplingAddr, "amount": Decimal('10')}], 1, 0)
wait_and_assert_operationid_status(self.nodes[0], opid)
self.nodes[0].generate(1)
self.sync_all()
assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('0'))
# Merge Sprout -> taddr
result = self.nodes[0].z_mergetoaddress(["ANY_SPROUT"], t_addr, 0)
wait_and_assert_operationid_status(self.nodes[0], result['opid'])
self.nodes[0].generate(1)
self.sync_all()
assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0'))
assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('10'))
assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('10'))
# Make sure we cannot use "ANY_SPROUT" and "ANY_SAPLING" even if we only have Sapling Notes
assert_mergetoaddress_exception(
"Cannot send from both Sprout and Sapling addresses using z_mergetoaddress",
lambda: self.nodes[0].z_mergetoaddress(["ANY_SPROUT", "ANY_SAPLING"], t_addr))
# Merge Sapling -> taddr
result = self.nodes[0].z_mergetoaddress(["ANY_SAPLING"], t_addr, 0)
wait_and_assert_operationid_status(self.nodes[0], result['opid'])
self.nodes[0].generate(1)
self.sync_all()
assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0'))
assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0'))
assert_equal(Decimal(self.nodes[1].z_gettotalbalance()["transparent"]), Decimal('20'))
if __name__ == '__main__':
MergeToAddressMixedNotes().main()

View File

@ -4532,8 +4532,15 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
if (!saplingActive && saplingEntries.size() > 0) { if (!saplingActive && saplingEntries.size() > 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
} }
// Do not include Sprout/Sapling notes if using "ANY_SAPLING"/"ANY_SPROUT" respectively
if (useAnySprout) {
saplingEntries.clear();
}
if (useAnySapling) {
sproutEntries.clear();
}
// Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress // Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress
if (sproutEntries.size() > 0 && saplingEntries.size() > 0) { if ((sproutEntries.size() > 0 && saplingEntries.size() > 0) || (useAnySprout && useAnySapling)) {
throw JSONRPCError( throw JSONRPCError(
RPC_INVALID_PARAMETER, RPC_INVALID_PARAMETER,
"Cannot send from both Sprout and Sapling addresses using z_mergetoaddress"); "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");