Auto merge of #3156 - Eirik0:2935-change-indicator, r=bitcartel

Add change indicator

This adds to the json returned when calling z_listreceivedbyaddress and z_listuspent an additional field entitiled 'change' which will be either true or false depending on whether or not the note was change from another transaction.
This commit is contained in:
Homu
2018-07-17 11:41:03 -07:00
7 changed files with 141 additions and 13 deletions

View File

@@ -15,6 +15,7 @@ testScripts=(
'prioritisetransaction.py'
'wallet_treestate.py'
'wallet_anchorfork.py'
'wallet_changeindicator.py'
'wallet_protectcoinbase.py'
'wallet_shieldcoinbase.py'
'wallet_mergetoaddress.py'

View File

@@ -355,9 +355,18 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
return (txid, signresult["hex"], fee)
def assert_equal(thing1, thing2):
if thing1 != thing2:
raise AssertionError("%s != %s"%(str(thing1),str(thing2)))
def assert_equal(expected, actual, message = ""):
if expected != actual:
if message:
message = "%s; " % message
raise AssertionError("%sexpected: <%s> but was: <%s>" % (message, str(expected), str(actual)))
def assert_true(condition, message = ""):
if not condition:
raise AssertionError(message)
def assert_false(condition, message = ""):
assert_true(not condition, message)
def assert_greater_than(thing1, thing2):
if thing1 <= thing2:

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_true, assert_false, wait_and_assert_operationid_status
from decimal import Decimal
class WalletChangeIndicatorTest (BitcoinTestFramework):
# Helper Methods
def generate_and_sync(self):
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
# Tests
def run_test(self):
taddr = self.nodes[1].getnewaddress()
zaddr1 = self.nodes[1].z_getnewaddress()
zaddr2 = self.nodes[1].z_getnewaddress()
self.nodes[0].sendtoaddress(taddr, Decimal('1.0'))
self.generate_and_sync()
# Send 1 ZEC to a zaddr
wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1.0, 'memo': 'c0ffee01'}], 1, 0))
self.generate_and_sync()
# Check that we have received 1 note which is not change
receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
listunspent = self.nodes[1].z_listunspent()
assert_equal(1, len(receivedbyaddress), "Should have received 1 note")
assert_false(receivedbyaddress[0]['change'], "Note should not be change")
assert_equal(1, len(listunspent), "Should have 1 unspent note")
assert_false(listunspent[0]['change'], "Unspent note should not be change")
# Generate some change
wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{'address': zaddr2, 'amount': 0.6, 'memo': 'c0ffee02'}], 1, 0))
self.generate_and_sync()
# Check zaddr1 received
sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr1, 0), key = lambda received: received['amount'])
assert_equal(2, len(sortedreceived1), "zaddr1 Should have received 2 notes")
assert_equal(Decimal('0.4'), sortedreceived1[0]['amount'])
assert_true(sortedreceived1[0]['change'], "Note valued at 0.4 should be change")
assert_equal(Decimal('1.0'), sortedreceived1[1]['amount'])
assert_false(sortedreceived1[1]['change'], "Note valued at 1.0 should not be change")
# Check zaddr2 received
sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr2, 0), key = lambda received: received['amount'])
assert_equal(1, len(sortedreceived2), "zaddr2 Should have received 1 notes")
assert_equal(Decimal('0.6'), sortedreceived2[0]['amount'])
assert_false(sortedreceived2[0]['change'], "Note valued at 0.6 should not be change")
# Check unspent
sortedunspent = sorted(self.nodes[1].z_listunspent(), key = lambda received: received['amount'])
assert_equal(2, len(sortedunspent), "Should have 2 unspent notes")
assert_equal(Decimal('0.4'), sortedunspent[0]['amount'])
assert_true(sortedunspent[0]['change'], "Unspent note valued at 0.4 should be change")
assert_equal(Decimal('0.6'), sortedunspent[1]['amount'])
assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change")
if __name__ == '__main__':
WalletChangeIndicatorTest().main()

View File

@@ -188,10 +188,23 @@ class WalletNullifiersTest (BitcoinTestFramework):
assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False)
assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True)
# Node 3 should see the same received notes as node 2
assert_equal(
self.nodes[2].z_listreceivedbyaddress(myzaddr),
self.nodes[3].z_listreceivedbyaddress(myzaddr))
# Node 3 should see the same received notes as node 2; however,
# some of the notes were change for note 2 but not for note 3.
# Aside from that the recieved notes should be the same. So,
# group by txid and then check that all properties aside from
# change are equal.
node2Received = dict([r['txid'], r] for r in self.nodes[2].z_listreceivedbyaddress(myzaddr))
node3Received = dict([r['txid'], r] for r in self.nodes[3].z_listreceivedbyaddress(myzaddr))
assert_equal(len(node2Received), len(node2Received))
for txid in node2Received:
received2 = node2Received[txid]
received3 = node3Received[txid]
assert_equal(len(received2), len(received3))
for key in received2:
# check all the properties except for change
if key != 'change':
assert_equal(received2[key], received3[key])
# Node 3's balances should be unchanged without explicitly requesting
# to include watch-only balances