Page MenuHomePhabricator

D7718.diff
No OneTemporary

D7718.diff

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

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)

Event Timeline