Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115766
D7718.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
21 KB
Subscribers
None
D7718.diff
View Options
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1090,7 +1090,7 @@
RPCHelpMan{
"addmultisigaddress",
- "Add a nrequired-to-sign multisignature address to the wallet. "
+ "Add an nrequired-to-sign multisignature address to the wallet. "
"Requires a new wallet backup.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"If 'label' is specified (DEPRECATED), assign address to that label.\n",
@@ -4149,85 +4149,95 @@
RPCHelpMan{
"getaddressinfo",
- "Return information about the given bitcoin address. Some "
- "information requires the address\n"
- "to be in the wallet.\n",
+ "\nReturn information about the given bitcoin address.\n"
+ "Some of the information will only be present if the address is in the "
+ "active wallet.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO,
- "The bitcoin address to get the information of."},
+ "The bitcoin address for which to get information."},
},
RPCResult{
"{\n"
- " \"address\" : \"address\", (string) The bitcoin address "
- "validated\n"
- " \"scriptPubKey\" : \"hex\", (string) The hex-encoded "
- "scriptPubKey generated by the address\n"
- " \"ismine\" : true|false, (boolean) If the address is "
- "yours or not\n"
- " \"iswatchonly\" : true|false, (boolean) If the address is "
- "watchonly\n"
- " \"solvable\" : true|false, (boolean) Whether we know how "
+ " \"address\" : \"address\", (string) The bitcoin "
+ "address validated.\n"
+ " \"scriptPubKey\" : \"hex\", (string) The "
+ "hex-encoded scriptPubKey generated by the address.\n"
+ " \"ismine\" : true|false, (boolean) If the address "
+ "is yours.\n"
+ " \"iswatchonly\" : true|false, (boolean) If the address "
+ "is watchonly.\n"
+ " \"solvable\" : true|false, (boolean) If we know how "
"to spend coins sent to this address, ignoring the possible lack "
- "of private keys\n"
- " \"desc\" : \"desc\", (string, optional) A descriptor "
- "for spending coins sent to this address (only when solvable)\n"
- " \"isscript\" : true|false, (boolean) If the key is a "
- "script\n"
- " \"ischange\" : true|false, (boolean) If the address was "
- "used for change output\n"
- " \"script\" : \"type\" (string, optional) The output "
- "script type. Only if \"isscript\" is true and the redeemscript is "
- "known. Possible types: nonstandard, pubkey, pubkeyhash, "
- "scripthash, multisig, nulldata\n"
- " \"hex\" : \"hex\", (string, optional) The "
- "redeemscript for the p2sh address\n"
- " \"pubkeys\" (string, optional) Array of "
- "pubkeys associated with the known redeemscript (only if "
- "\"script\" is \"multisig\")\n"
+ "of private keys.\n"
+ " \"desc\" : \"desc\", (string, optional) A "
+ "descriptor for spending coins sent to this address (only when "
+ "solvable).\n"
+ " \"isscript\" : true|false, (boolean) If the key is a "
+ "script.\n"
+ " \"ischange\" : true|false, (boolean) If the address "
+ "was used for change output.\n"
+ " \"script\" : \"type\" (string, optional) The "
+ "output script type. Only if isscript is true and the redeemscript "
+ "is known. Possible\n"
+ " types: "
+ "nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata\n"
+ " \"hex\" : \"hex\", (string, optional) The "
+ "redeemscript for the p2sh address.\n"
+ " \"pubkeys\" (array, optional) Array "
+ "of pubkeys associated with the known redeemscript (only if script "
+ "is multisig).\n"
" [\n"
- " \"pubkey\"\n"
+ " \"pubkey\" (string)\n"
" ,...\n"
" ]\n"
- " \"sigsrequired\" : xxxxx (numeric, optional) Number of "
- "signatures required to spend multisig output (only if \"script\" "
- "is \"multisig\")\n"
- " \"pubkey\" : \"publickeyhex\", (string, optional) The hex "
- "value of the raw public key, for single-key addresses (possibly "
- "embedded in P2SH)\n"
- " \"embedded\" : {...}, (object, optional) Information "
- "about the address embedded in P2SH, if relevant and known. It "
- "includes all getaddressinfo output fields for the embedded "
- "address, excluding metadata (\"timestamp\", \"hdkeypath\", "
- "\"hdseedid\") and relation to the wallet (\"ismine\", "
- "\"iswatchonly\").\n"
- " \"iscompressed\" : true|false, (boolean) If the address is "
- "compressed\n"
- " \"label\" : \"label\" (string) The label associated "
- "with the address, \"\" is the default label\n"
- " \"timestamp\" : timestamp, (number, optional) The creation "
- "time of the key if available in seconds since epoch (Jan 1 1970 "
- "GMT)\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"
+ " \"sigsrequired\" : xxxxx (numeric, optional) The "
+ "number of signatures required to spend multisig output (only if "
+ "script is multisig).\n"
+ " \"pubkey\" : \"publickeyhex\", (string, optional) The "
+ "hex value of the raw public key for single-key addresses "
+ "(possibly embedded in P2SH or P2WSH).\n"
+ " \"embedded\" : {...}, (object, optional) "
+ "Information about the address embedded in P2SH or P2WSH, if "
+ "relevant and known. Includes all\n"
+ " "
+ "getaddressinfo output fields for the embedded address, excluding "
+ "metadata (timestamp, hdkeypath,\n"
+ " "
+ "hdseedid) and relation to the wallet (ismine, iswatchonly).\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"
+ " \"timestamp\" : timestamp, (number, optional) The "
+ "creation time of the key if available, expressed in seconds since "
+ "Epoch Time (Jan 1 1970 GMT).\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"
" \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) The "
- "fingperint of the master key.\n"
- " \"labels\" (object) Array of labels "
- "associated with the address.\n"
+ "fingerprint of the master key.\n"
+ " \"labels\" (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"
" [\n"
" { (json object of label data)\n"
- " \"name\": \"labelname\" (string) The label\n"
- " \"purpose\": \"string\" (string) Purpose of address "
- "(\"send\" for sending address, \"receive\" for receiving "
- "address)\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"
" },...\n"
" ]\n"
"}\n"},
- RPCExamples{HelpExampleCli("getaddressinfo",
- "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") +
- HelpExampleRpc("getaddressinfo",
- "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")},
+ RPCExamples{
+ HelpExampleCli("getaddressinfo",
+ "\"qrmzys48glkpevp2l4t24jtcltc9hyzx9cep2qffm4\"") +
+ HelpExampleRpc("getaddressinfo",
+ "\"qrmzys48glkpevp2l4t24jtcltc9hyzx9cep2qffm4\"")},
}
.Check(request);
@@ -4248,24 +4258,40 @@
CScript scriptPubKey = GetScriptForDestination(dest);
ret.pushKV("scriptPubKey",
HexStr(scriptPubKey.begin(), scriptPubKey.end()));
+
const SigningProvider *provider = pwallet->GetSigningProvider(scriptPubKey);
isminetype mine = pwallet->IsMine(dest);
ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
+
bool solvable = provider && IsSolvable(*provider, scriptPubKey);
ret.pushKV("solvable", solvable);
+
if (solvable) {
ret.pushKV("desc",
InferDescriptor(scriptPubKey, *provider)->ToString());
}
+
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
+
+ // Return DescribeWalletAddress fields.
+ // Always returned: isscript, ischange.
+ // Optional: script, hex, pubkeys (array), sigsrequired, pubkey, embedded,
+ // iscompressed.
UniValue detail = DescribeWalletAddress(pwallet, dest);
ret.pushKVs(detail);
+
+ // Return label field if existing. Currently only one label can be
+ // 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.
if (pwallet->mapAddressBook.count(dest)) {
ret.pushKV("label", pwallet->mapAddressBook[dest].name);
}
+
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
+ // Fetch KeyMetadata, if present, for the timestamp, hdkeypath, hdseedid,
+ // and hdmasterfingerprint fields.
ScriptPubKeyMan *spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
if (spk_man) {
if (const CKeyMetadata *meta = spk_man->GetMetadata(dest)) {
@@ -4280,9 +4306,11 @@
}
}
- // Currently only one label can be associated with an address, return an
- // array so the API remains stable if we allow multiple labels to be
- // associated with an address.
+ // Return a labels array containing a hash of key/value pairs for the label
+ // name and address purpose. The name value is equivalent to the label field
+ // above. Currently only one label can be associated with an address, but we
+ // return an array so the API remains stable if we allow multiple labels to
+ // be associated with an address in the future.
UniValue labels(UniValue::VARR);
std::map<CTxDestination, CAddressBookData>::iterator mi =
pwallet->mapAddressBook.find(dest);
diff --git a/test/functional/test_framework/wallet_util.py b/test/functional/test_framework/wallet_util.py
--- a/test/functional/test_framework/wallet_util.py
+++ b/test/functional/test_framework/wallet_util.py
@@ -69,6 +69,12 @@
redeem_script=script_code.hex())
+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):
"""Get address info for `address` and test whether the returned values are as expected."""
addr_info = node.getaddressinfo(address)
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -17,6 +17,10 @@
count_bytes,
wait_until,
)
+from test_framework.wallet_util import (
+ labels_value,
+ test_address,
+)
class WalletTest(BitcoinTestFramework):
@@ -460,8 +464,12 @@
for label in [u'рыба', u'𝅘𝅥𝅯']:
addr = self.nodes[0].getnewaddress()
self.nodes[0].setlabel(addr, label)
- assert_equal(self.nodes[0].getaddressinfo(
- addr)['label'], label)
+ test_address(
+ self.nodes[0],
+ addr,
+ label=label,
+ labels=labels_value(
+ name=label))
assert label in self.nodes[0].listlabels()
# restore to default
self.nodes[0].rpc.ensure_ascii = True
diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py
--- a/test/functional/wallet_import_with_label.py
+++ b/test/functional/wallet_import_with_label.py
@@ -22,7 +22,10 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import hex_str_to_bytes
-from test_framework.wallet_util import test_address
+from test_framework.wallet_util import (
+ labels_value,
+ test_address,
+)
class ImportWithLabel(BitcoinTestFramework):
@@ -47,7 +50,8 @@
address,
iswatchonly=True,
ismine=False,
- label=label)
+ label=label,
+ labels=labels_value(name=label))
self.log.info(
"Import the watch-only address's private key without a "
@@ -58,7 +62,8 @@
test_address(self.nodes[1],
address,
- label=label)
+ label=label,
+ labels=labels_value(name=label))
self.log.info(
"Test importaddress without label and importprivkey with label."
@@ -70,7 +75,8 @@
address2,
iswatchonly=True,
ismine=False,
- label="")
+ label="",
+ labels=labels_value())
self.log.info(
"Import the watch-only address's private key with a "
@@ -82,7 +88,8 @@
test_address(self.nodes[1],
address2,
- label=label2)
+ label=label2,
+ labels=labels_value(name=label2))
self.log.info(
"Test importaddress with label and importprivkey with label.")
@@ -94,7 +101,8 @@
address3,
iswatchonly=True,
ismine=False,
- label=label3_addr)
+ label=label3_addr,
+ labels=labels_value(name=label3_addr))
self.log.info(
"Import the watch-only address's private key with a "
@@ -106,7 +114,8 @@
test_address(self.nodes[1],
address3,
- label=label3_priv)
+ label=label3_priv,
+ labels=labels_value(name=label3_priv))
self.log.info(
"Test importprivkey won't label new dests with the same "
@@ -121,6 +130,7 @@
iswatchonly=True,
ismine=False,
label=label4_addr,
+ labels=labels_value(name=label4_addr),
embedded=None)
self.log.info(
@@ -147,13 +157,15 @@
test_address(self.nodes[1],
p2shaddr4,
- label="")
+ label="",
+ labels=labels_value())
embedded_addr = self.nodes[1].getaddressinfo(
p2shaddr4)['embedded']['address']
test_address(self.nodes[1],
embedded_addr,
- label=label4_addr)
+ label=label4_addr,
+ labels=labels_value(name=label4_addr))
self.stop_nodes()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -29,6 +29,7 @@
from test_framework.wallet_util import (
get_key,
get_multisig,
+ labels_value,
test_address,
)
@@ -126,7 +127,7 @@
self.test_importmulti({"scriptPubKey": key.p2pkh_script,
"timestamp": "now",
"internal": True,
- "label": "Example label"},
+ "label": "Unsuccessful labelling for internal addresses"},
success=False,
error_code=-8,
error_message='Internal addresses should not have a label')
@@ -502,17 +503,19 @@
# Test importing of a P2PKH address via descriptor
key = get_key(self.nodes[0])
+ p2pkh_label = "P2PKH descriptor import"
self.log.info("Should import a p2pkh address from descriptor")
self.test_importmulti({"desc": descsum_create("pkh(" + key.pubkey + ")"),
"timestamp": "now",
- "label": "Descriptor import test"},
+ "label": p2pkh_label},
success=True,
warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
test_address(self.nodes[1],
key.p2pkh_addr,
solvable=True,
ismine=False,
- label="Descriptor import test")
+ label=p2pkh_label,
+ labels=labels_value(name=p2pkh_label))
# Test import fails if both desc and scriptPubKey are provided
key = get_key(self.nodes[0])
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -13,6 +13,10 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
+from test_framework.wallet_util import (
+ labels_value,
+ test_address,
+)
class WalletLabelsTest(BitcoinTestFramework):
@@ -165,14 +169,15 @@
def verify(self, node):
if self.receive_address is not None:
assert self.receive_address in self.addresses
-
for address in self.addresses:
- assert_equal(
- node.getaddressinfo(address)['labels'][0],
- {"name": self.name,
- "purpose": self.purpose[address]})
- assert_equal(node.getaddressinfo(address)['label'], self.name)
-
+ test_address(
+ node,
+ address,
+ label=self.name,
+ labels=labels_value(
+ name=self.name, purpose=self.purpose[address])
+ )
+ assert self.name in node.listlabels()
assert_equal(
node.getaddressesbylabel(self.name),
{address: {"purpose": self.purpose[address]} for address in self.addresses})
diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -12,6 +12,10 @@
assert_equal,
assert_raises_rpc_error,
)
+from test_framework.wallet_util import (
+ labels_value,
+ test_address,
+)
class ReceivedByTest(BitcoinTestFramework):
@@ -145,7 +149,12 @@
# set pre-state
label = ''
address = self.nodes[1].getnewaddress()
- assert_equal(self.nodes[1].getaddressinfo(address)['label'], label)
+ test_address(
+ self.nodes[1],
+ address,
+ label=label,
+ labels=labels_value(
+ name=label))
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)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 1, 11:59 (3 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5186058
Default Alt Text
D7718.diff (21 KB)
Attached To
D7718: [backport#17283] rpc: improve getaddressinfo test coverage, help, code docs
Event Timeline
Log In to Comment