Skip to content

Commit b740788

Browse files
author
MarcoFalke
committed
Merge #14410: rpcwallet: 'ischange' field for 'getaddressinfo' RPC
14a0652 tests: add test for 'getaddressinfo' RPC result 'ischange' field (whythat) 93d1aa9 rpcwallet: add 'ischange' field to 'getaddressinfo' response (whythat) Pull request description: Implementation of proposal in #14396. This introduces `CWallet::IsChange(CScript&)` method and replaces original `CWallet::IsChange(CTxOut&)` method with overloaded version that delegates to the new method with *txout*'s `scriptPubKey`. In this way `TODO` note from the original method can still be addressed in a single place. Tree-SHA512: ef5dbc82d76b4b9b2fa6a70abc3385a677c55021f79e187ee2f392ee32bc6b406191f4129acae5c17b0206e72b6712e7e0cad574a4bbd966871c2e656c45e041
2 parents 742ee21 + 14a0652 commit b740788

File tree

5 files changed

+30
-3
lines changed

5 files changed

+30
-3
lines changed

doc/release-notes-14282.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ Low-level RPC changes
44
`-usehd` was removed in version 0.16. From that version onwards, all new
55
wallets created are hierarchical deterministic wallets. Version 0.18 makes
66
specifying `-usehd` invalid config.
7+
8+
`ischange` field of boolean type that shows if an address was used for change
9+
output was added to `getaddressinfo` method response.

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3458,6 +3458,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
34583458
" \"solvable\" : true|false, (boolean) If the address is solvable by the wallet\n"
34593459
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
34603460
" \"isscript\" : true|false, (boolean) If the key is a script\n"
3461+
" \"ischange\" : true|false, (boolean) If the address was used for change output\n"
34613462
" \"iswitness\" : true|false, (boolean) If the address is a witness address\n"
34623463
" \"witness_version\" : version (numeric, optional) The version number of the witness program\n"
34633464
" \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n"
@@ -3516,6 +3517,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
35163517
if (pwallet->mapAddressBook.count(dest)) {
35173518
ret.pushKV("label", pwallet->mapAddressBook[dest].name);
35183519
}
3520+
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
35193521
const CKeyMetadata* meta = nullptr;
35203522
CKeyID key_id = GetKeyForDestination(*pwallet, dest);
35213523
if (!key_id.IsNull()) {

src/wallet/wallet.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,11 @@ CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) cons
12611261
}
12621262

12631263
bool CWallet::IsChange(const CTxOut& txout) const
1264+
{
1265+
return IsChange(txout.scriptPubKey);
1266+
}
1267+
1268+
bool CWallet::IsChange(const CScript& script) const
12641269
{
12651270
// TODO: fix handling of 'change' outputs. The assumption is that any
12661271
// payment to a script that is ours, but is not in the address book
@@ -1269,10 +1274,10 @@ bool CWallet::IsChange(const CTxOut& txout) const
12691274
// a better way of identifying which outputs are 'the send' and which are
12701275
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
12711276
// which output, if any, was change).
1272-
if (::IsMine(*this, txout.scriptPubKey))
1277+
if (::IsMine(*this, script))
12731278
{
12741279
CTxDestination address;
1275-
if (!ExtractDestination(txout.scriptPubKey, address))
1280+
if (!ExtractDestination(script, address))
12761281
return true;
12771282

12781283
LOCK(cs_wallet);

src/wallet/wallet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
971971
isminetype IsMine(const CTxOut& txout) const;
972972
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
973973
bool IsChange(const CTxOut& txout) const;
974+
bool IsChange(const CScript& script) const;
974975
CAmount GetChange(const CTxOut& txout) const;
975976
bool IsMine(const CTransaction& tx) const;
976977
/** should probably be renamed to IsRelevantToMe */

test/functional/wallet_basic.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,14 +479,30 @@ def run_test(self):
479479
# Verify nothing new in wallet
480480
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
481481

482-
# Test getaddressinfo. Note that these addresses are taken from disablewallet.py
482+
# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
483483
assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
484484
address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
485485
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
486486
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
487487
assert not address_info["ismine"]
488488
assert not address_info["iswatchonly"]
489489
assert not address_info["isscript"]
490+
assert not address_info["ischange"]
491+
492+
# Test getaddressinfo 'ischange' field on change address.
493+
self.nodes[0].generate(1)
494+
destination = self.nodes[1].getnewaddress()
495+
txid = self.nodes[0].sendtoaddress(destination, 0.123)
496+
tx = self.nodes[0].decoderawtransaction(self.nodes[0].getrawtransaction(txid))
497+
output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]]
498+
assert len(output_addresses) > 1
499+
for address in output_addresses:
500+
ischange = self.nodes[0].getaddressinfo(address)['ischange']
501+
assert_equal(ischange, address != destination)
502+
if ischange:
503+
change = address
504+
self.nodes[0].setlabel(change, 'foobar')
505+
assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
490506

491507
if __name__ == '__main__':
492508
WalletTest().main()

0 commit comments

Comments
 (0)