mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-09 10:43:19 -05:00
rpc: simplify getaddressinfo labels, deprecate previous behavior
- change the value returned in the RPC getaddressinfo `labels` field to an array of label name strings - deprecate the previous behavior of returning a JSON hash structure containing label `name` and address `purpose` key/value pairs - update the relevant tests
This commit is contained in:
parent
7851f14ccf
commit
60aba1f2f1
7 changed files with 40 additions and 70 deletions
|
@ -3744,18 +3744,20 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||||
" getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath,\n"
|
" getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath,\n"
|
||||||
" hdseedid) and relation to the wallet (ismine, iswatchonly).\n"
|
" hdseedid) and relation to the wallet (ismine, iswatchonly).\n"
|
||||||
" \"iscompressed\" : true|false, (boolean, optional) If the pubkey is compressed.\n"
|
" \"iscompressed\" : true|false, (boolean, optional) If the pubkey is compressed.\n"
|
||||||
" \"label\" : \"label\" (string) The label associated with the address. Defaults to \"\". Equivalent to the name field in the labels array.\n"
|
" \"label\" : \"label\" (string) The label associated with the address. Defaults to \"\". Equivalent to the label name in the labels array below.\n"
|
||||||
" \"timestamp\" : timestamp, (number, optional) The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + ".\n"
|
" \"timestamp\" : timestamp, (number, optional) The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + ".\n"
|
||||||
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath, if the key is HD and available.\n"
|
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath, if the key is HD and available.\n"
|
||||||
" \"hdseedid\" : \"<hash160>\" (string, optional) The Hash160 of the HD seed.\n"
|
" \"hdseedid\" : \"<hash160>\" (string, optional) The Hash160 of the HD seed.\n"
|
||||||
" \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) The fingerprint of the master key.\n"
|
" \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) The fingerprint of the master key.\n"
|
||||||
" \"labels\" (object) An array of labels associated with the address. Currently limited to one label but returned\n"
|
" \"labels\" (json object) An array of labels associated with the address. Currently limited to one label but returned\n"
|
||||||
" as an array to keep the API stable if multiple labels are enabled in the future.\n"
|
" as an array to keep the API stable if multiple labels are enabled in the future.\n"
|
||||||
" [\n"
|
" [\n"
|
||||||
|
" \"label name\" (string) The label name. Defaults to \"\". Equivalent to the label field above.\n\n"
|
||||||
|
" DEPRECATED, will be removed in 0.21. To re-enable, launch bitcoind with `-deprecatedrpc=labelspurpose`:\n"
|
||||||
" { (json object of label data)\n"
|
" { (json object of label data)\n"
|
||||||
" \"name\": \"label name\" (string) The label name. Defaults to \"\". Equivalent to the label field above.\n"
|
" \"name\" : \"label name\" (string) The label name. Defaults to \"\". Equivalent to the label field above.\n"
|
||||||
" \"purpose\": \"purpose\" (string) The purpose of the associated address (send or receive).\n"
|
" \"purpose\" : \"purpose\" (string) The purpose of the associated address (send or receive).\n"
|
||||||
" },...\n"
|
" }\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
},
|
},
|
||||||
|
@ -3769,7 +3771,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||||
|
|
||||||
UniValue ret(UniValue::VOBJ);
|
UniValue ret(UniValue::VOBJ);
|
||||||
CTxDestination dest = DecodeDestination(request.params[0].get_str());
|
CTxDestination dest = DecodeDestination(request.params[0].get_str());
|
||||||
|
|
||||||
// Make sure the destination is valid
|
// Make sure the destination is valid
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||||
|
@ -3800,7 +3801,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||||
|
|
||||||
// Return label field if existing. Currently only one label can be
|
// Return label field if existing. Currently only one label can be
|
||||||
// associated with an address, so the label should be equivalent to the
|
// associated with an address, so the label should be equivalent to the
|
||||||
// value of the name key/value pair in the labels hash array below.
|
// value of the name key/value pair in the labels array below.
|
||||||
if (pwallet->mapAddressBook.count(dest)) {
|
if (pwallet->mapAddressBook.count(dest)) {
|
||||||
ret.pushKV("label", pwallet->mapAddressBook[dest].name);
|
ret.pushKV("label", pwallet->mapAddressBook[dest].name);
|
||||||
}
|
}
|
||||||
|
@ -3819,15 +3820,22 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a labels array containing a hash of key/value pairs for the label
|
// Return a `labels` array containing the label associated with the address,
|
||||||
// name and address purpose. The name value is equivalent to the label field
|
// equivalent to the `label` field above. Currently only one label can be
|
||||||
// above. Currently only one label can be associated with an address, but we
|
// associated with an address, but we return an array so the API remains
|
||||||
// return an array so the API remains stable if we allow multiple labels to
|
// stable if we allow multiple labels to be associated with an address in
|
||||||
// be associated with an address in the future.
|
// the future.
|
||||||
|
//
|
||||||
|
// DEPRECATED: The previous behavior of returning an array containing a JSON
|
||||||
|
// object of `name` and `purpose` key/value pairs has been deprecated.
|
||||||
UniValue labels(UniValue::VARR);
|
UniValue labels(UniValue::VARR);
|
||||||
std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
|
std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
|
||||||
if (mi != pwallet->mapAddressBook.end()) {
|
if (mi != pwallet->mapAddressBook.end()) {
|
||||||
labels.push_back(AddressBookDataToJSON(mi->second, true));
|
if (pwallet->chain().rpcEnableDeprecated("labelspurpose")) {
|
||||||
|
labels.push_back(AddressBookDataToJSON(mi->second, true));
|
||||||
|
} else {
|
||||||
|
labels.push_back(mi->second.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret.pushKV("labels", std::move(labels));
|
ret.pushKV("labels", std::move(labels));
|
||||||
|
|
||||||
|
|
|
@ -88,11 +88,6 @@ def get_multisig(node):
|
||||||
p2sh_p2wsh_script=CScript([OP_HASH160, witness_script, OP_EQUAL]).hex(),
|
p2sh_p2wsh_script=CScript([OP_HASH160, witness_script, OP_EQUAL]).hex(),
|
||||||
p2sh_p2wsh_addr=script_to_p2sh_p2wsh(script_code))
|
p2sh_p2wsh_addr=script_to_p2sh_p2wsh(script_code))
|
||||||
|
|
||||||
def labels_value(name="", purpose="receive"):
|
|
||||||
"""Generate a getaddressinfo labels array from a name and purpose.
|
|
||||||
Often used as the value of a labels kwarg for calling test_address below."""
|
|
||||||
return [{"name": name, "purpose": purpose}]
|
|
||||||
|
|
||||||
def test_address(node, address, **kwargs):
|
def test_address(node, address, **kwargs):
|
||||||
"""Get address info for `address` and test whether the returned values are as expected."""
|
"""Get address info for `address` and test whether the returned values are as expected."""
|
||||||
addr_info = node.getaddressinfo(address)
|
addr_info = node.getaddressinfo(address)
|
||||||
|
|
|
@ -15,10 +15,7 @@ from test_framework.util import (
|
||||||
connect_nodes,
|
connect_nodes,
|
||||||
wait_until,
|
wait_until,
|
||||||
)
|
)
|
||||||
from test_framework.wallet_util import (
|
from test_framework.wallet_util import test_address
|
||||||
labels_value,
|
|
||||||
test_address,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class WalletTest(BitcoinTestFramework):
|
class WalletTest(BitcoinTestFramework):
|
||||||
|
@ -395,7 +392,7 @@ class WalletTest(BitcoinTestFramework):
|
||||||
for label in [u'рыба', u'𝅘𝅥𝅯']:
|
for label in [u'рыба', u'𝅘𝅥𝅯']:
|
||||||
addr = self.nodes[0].getnewaddress()
|
addr = self.nodes[0].getnewaddress()
|
||||||
self.nodes[0].setlabel(addr, label)
|
self.nodes[0].setlabel(addr, label)
|
||||||
test_address(self.nodes[0], addr, label=label, labels=labels_value(name=label))
|
test_address(self.nodes[0], addr, label=label, labels=[label])
|
||||||
assert label in self.nodes[0].listlabels()
|
assert label in self.nodes[0].listlabels()
|
||||||
self.nodes[0].rpc.ensure_ascii = True # restore to default
|
self.nodes[0].rpc.ensure_ascii = True # restore to default
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,7 @@ with and without a label.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.wallet_util import (
|
from test_framework.wallet_util import test_address
|
||||||
labels_value,
|
|
||||||
test_address,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ImportWithLabel(BitcoinTestFramework):
|
class ImportWithLabel(BitcoinTestFramework):
|
||||||
|
@ -40,7 +37,7 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
iswatchonly=True,
|
iswatchonly=True,
|
||||||
ismine=False,
|
ismine=False,
|
||||||
label=label,
|
label=label,
|
||||||
labels=labels_value(name=label))
|
labels=[label])
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Import the watch-only address's private key without a "
|
"Import the watch-only address's private key without a "
|
||||||
|
@ -48,11 +45,7 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
)
|
)
|
||||||
priv_key = self.nodes[0].dumpprivkey(address)
|
priv_key = self.nodes[0].dumpprivkey(address)
|
||||||
self.nodes[1].importprivkey(priv_key)
|
self.nodes[1].importprivkey(priv_key)
|
||||||
|
test_address(self.nodes[1], address, label=label, labels=[label])
|
||||||
test_address(self.nodes[1],
|
|
||||||
address,
|
|
||||||
label=label,
|
|
||||||
labels=labels_value(name=label))
|
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Test importaddress without label and importprivkey with label."
|
"Test importaddress without label and importprivkey with label."
|
||||||
|
@ -65,7 +58,7 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
iswatchonly=True,
|
iswatchonly=True,
|
||||||
ismine=False,
|
ismine=False,
|
||||||
label="",
|
label="",
|
||||||
labels=labels_value())
|
labels=[""])
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Import the watch-only address's private key with a "
|
"Import the watch-only address's private key with a "
|
||||||
|
@ -75,10 +68,7 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
label2 = "Test Label 2"
|
label2 = "Test Label 2"
|
||||||
self.nodes[1].importprivkey(priv_key2, label2)
|
self.nodes[1].importprivkey(priv_key2, label2)
|
||||||
|
|
||||||
test_address(self.nodes[1],
|
test_address(self.nodes[1], address2, label=label2, labels=[label2])
|
||||||
address2,
|
|
||||||
label=label2,
|
|
||||||
labels=labels_value(name=label2))
|
|
||||||
|
|
||||||
self.log.info("Test importaddress with label and importprivkey with label.")
|
self.log.info("Test importaddress with label and importprivkey with label.")
|
||||||
self.log.info("Import a watch-only address with a label.")
|
self.log.info("Import a watch-only address with a label.")
|
||||||
|
@ -90,7 +80,7 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
iswatchonly=True,
|
iswatchonly=True,
|
||||||
ismine=False,
|
ismine=False,
|
||||||
label=label3_addr,
|
label=label3_addr,
|
||||||
labels=labels_value(name=label3_addr))
|
labels=[label3_addr])
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Import the watch-only address's private key with a "
|
"Import the watch-only address's private key with a "
|
||||||
|
@ -100,10 +90,7 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
label3_priv = "Test Label 3 for importprivkey"
|
label3_priv = "Test Label 3 for importprivkey"
|
||||||
self.nodes[1].importprivkey(priv_key3, label3_priv)
|
self.nodes[1].importprivkey(priv_key3, label3_priv)
|
||||||
|
|
||||||
test_address(self.nodes[1],
|
test_address(self.nodes[1], address3, label=label3_priv, labels=[label3_priv])
|
||||||
address3,
|
|
||||||
label=label3_priv,
|
|
||||||
labels=labels_value(name=label3_priv))
|
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Test importprivkey won't label new dests with the same "
|
"Test importprivkey won't label new dests with the same "
|
||||||
|
@ -118,7 +105,7 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
iswatchonly=True,
|
iswatchonly=True,
|
||||||
ismine=False,
|
ismine=False,
|
||||||
label=label4_addr,
|
label=label4_addr,
|
||||||
labels=labels_value(name=label4_addr),
|
labels=[label4_addr],
|
||||||
embedded=None)
|
embedded=None)
|
||||||
|
|
||||||
self.log.info(
|
self.log.info(
|
||||||
|
@ -131,15 +118,9 @@ class ImportWithLabel(BitcoinTestFramework):
|
||||||
self.nodes[1].importprivkey(priv_key4)
|
self.nodes[1].importprivkey(priv_key4)
|
||||||
embedded_addr = self.nodes[1].getaddressinfo(address4)['embedded']['address']
|
embedded_addr = self.nodes[1].getaddressinfo(address4)['embedded']['address']
|
||||||
|
|
||||||
test_address(self.nodes[1],
|
test_address(self.nodes[1], embedded_addr, label="", labels=[""])
|
||||||
embedded_addr,
|
|
||||||
label="",
|
|
||||||
labels=labels_value())
|
|
||||||
|
|
||||||
test_address(self.nodes[1],
|
test_address(self.nodes[1], address4, label=label4_addr, labels=[label4_addr])
|
||||||
address4,
|
|
||||||
label=label4_addr,
|
|
||||||
labels=labels_value(name=label4_addr))
|
|
||||||
|
|
||||||
self.stop_nodes()
|
self.stop_nodes()
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ from test_framework.util import (
|
||||||
from test_framework.wallet_util import (
|
from test_framework.wallet_util import (
|
||||||
get_key,
|
get_key,
|
||||||
get_multisig,
|
get_multisig,
|
||||||
labels_value,
|
|
||||||
test_address,
|
test_address,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -571,7 +570,7 @@ class ImportMultiTest(BitcoinTestFramework):
|
||||||
solvable=True,
|
solvable=True,
|
||||||
ismine=True,
|
ismine=True,
|
||||||
label=p2sh_p2wpkh_label,
|
label=p2sh_p2wpkh_label,
|
||||||
labels=labels_value(name=p2sh_p2wpkh_label))
|
labels=[p2sh_p2wpkh_label])
|
||||||
|
|
||||||
# Test ranged descriptor fails if range is not specified
|
# Test ranged descriptor fails if range is not specified
|
||||||
xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg"
|
xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg"
|
||||||
|
@ -643,7 +642,7 @@ class ImportMultiTest(BitcoinTestFramework):
|
||||||
solvable=True,
|
solvable=True,
|
||||||
ismine=False,
|
ismine=False,
|
||||||
label=p2pkh_label,
|
label=p2pkh_label,
|
||||||
labels=labels_value(name=p2pkh_label))
|
labels=[p2pkh_label])
|
||||||
|
|
||||||
# Test import fails if both desc and scriptPubKey are provided
|
# Test import fails if both desc and scriptPubKey are provided
|
||||||
key = get_key(self.nodes[0])
|
key = get_key(self.nodes[0])
|
||||||
|
|
|
@ -13,10 +13,8 @@ from collections import defaultdict
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import assert_equal, assert_raises_rpc_error
|
from test_framework.util import assert_equal, assert_raises_rpc_error
|
||||||
from test_framework.wallet_util import (
|
from test_framework.wallet_util import test_address
|
||||||
labels_value,
|
|
||||||
test_address,
|
|
||||||
)
|
|
||||||
|
|
||||||
class WalletLabelsTest(BitcoinTestFramework):
|
class WalletLabelsTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
|
@ -157,12 +155,7 @@ class Label:
|
||||||
if self.receive_address is not None:
|
if self.receive_address is not None:
|
||||||
assert self.receive_address in self.addresses
|
assert self.receive_address in self.addresses
|
||||||
for address in self.addresses:
|
for address in self.addresses:
|
||||||
test_address(
|
test_address(node, address, label=self.name, labels=[self.name])
|
||||||
node,
|
|
||||||
address,
|
|
||||||
label=self.name,
|
|
||||||
labels=labels_value(name=self.name, purpose=self.purpose[address])
|
|
||||||
)
|
|
||||||
assert self.name in node.listlabels()
|
assert self.name in node.listlabels()
|
||||||
assert_equal(
|
assert_equal(
|
||||||
node.getaddressesbylabel(self.name),
|
node.getaddressesbylabel(self.name),
|
||||||
|
|
|
@ -11,10 +11,7 @@ from test_framework.util import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
assert_raises_rpc_error,
|
assert_raises_rpc_error,
|
||||||
)
|
)
|
||||||
from test_framework.wallet_util import (
|
from test_framework.wallet_util import test_address
|
||||||
labels_value,
|
|
||||||
test_address,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ReceivedByTest(BitcoinTestFramework):
|
class ReceivedByTest(BitcoinTestFramework):
|
||||||
|
@ -131,7 +128,7 @@ class ReceivedByTest(BitcoinTestFramework):
|
||||||
# set pre-state
|
# set pre-state
|
||||||
label = ''
|
label = ''
|
||||||
address = self.nodes[1].getnewaddress()
|
address = self.nodes[1].getnewaddress()
|
||||||
test_address(self.nodes[1], address, label=label, labels=labels_value(name=label))
|
test_address(self.nodes[1], address, label=label, labels=[label])
|
||||||
received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label][0]
|
received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label][0]
|
||||||
balance_by_label = self.nodes[1].getreceivedbylabel(label)
|
balance_by_label = self.nodes[1].getreceivedbylabel(label)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue