Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/rpcwallet.cpp
Show First 20 Lines • Show All 1,084 Lines • ▼ Show 20 Lines | static UniValue addmultisigaddress(const Config &config, | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
RPCHelpMan{ | RPCHelpMan{ | ||||
"addmultisigaddress", | "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" | "Requires a new wallet backup.\n" | ||||
"Each key is a Bitcoin address or hex-encoded public key.\n" | "Each key is a Bitcoin address or hex-encoded public key.\n" | ||||
"If 'label' is specified (DEPRECATED), assign address to that label.\n", | "If 'label' is specified (DEPRECATED), assign address to that label.\n", | ||||
{ | { | ||||
{"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, | {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, | ||||
"The number of required signatures out of the n keys or " | "The number of required signatures out of the n keys or " | ||||
"addresses."}, | "addresses."}, | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 3,042 Lines • ▼ Show 20 Lines | UniValue getaddressinfo(const Config &config, const JSONRPCRequest &request) { | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
RPCHelpMan{ | RPCHelpMan{ | ||||
"getaddressinfo", | "getaddressinfo", | ||||
"Return information about the given bitcoin address. Some " | "\nReturn information about the given bitcoin address.\n" | ||||
"information requires the address\n" | "Some of the information will only be present if the address is in the " | ||||
"to be in the wallet.\n", | "active wallet.\n", | ||||
{ | { | ||||
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, | {"address", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"The bitcoin address to get the information of."}, | "The bitcoin address for which to get information."}, | ||||
}, | }, | ||||
RPCResult{ | RPCResult{ | ||||
"{\n" | "{\n" | ||||
" \"address\" : \"address\", (string) The bitcoin address " | " \"address\" : \"address\", (string) The bitcoin " | ||||
"validated\n" | "address validated.\n" | ||||
" \"scriptPubKey\" : \"hex\", (string) The hex-encoded " | " \"scriptPubKey\" : \"hex\", (string) The " | ||||
"scriptPubKey generated by the address\n" | "hex-encoded scriptPubKey generated by the address.\n" | ||||
" \"ismine\" : true|false, (boolean) If the address is " | " \"ismine\" : true|false, (boolean) If the address " | ||||
"yours or not\n" | "is yours.\n" | ||||
" \"iswatchonly\" : true|false, (boolean) If the address is " | " \"iswatchonly\" : true|false, (boolean) If the address " | ||||
"watchonly\n" | "is watchonly.\n" | ||||
" \"solvable\" : true|false, (boolean) Whether we know how " | " \"solvable\" : true|false, (boolean) If we know how " | ||||
"to spend coins sent to this address, ignoring the possible lack " | "to spend coins sent to this address, ignoring the possible lack " | ||||
"of private keys\n" | "of private keys.\n" | ||||
" \"desc\" : \"desc\", (string, optional) A descriptor " | " \"desc\" : \"desc\", (string, optional) A " | ||||
"for spending coins sent to this address (only when solvable)\n" | "descriptor for spending coins sent to this address (only when " | ||||
"solvable).\n" | |||||
" \"isscript\" : true|false, (boolean) If the key is a " | " \"isscript\" : true|false, (boolean) If the key is a " | ||||
"script\n" | "script.\n" | ||||
" \"ischange\" : true|false, (boolean) If the address was " | " \"ischange\" : true|false, (boolean) If the address " | ||||
"used for change output\n" | "was used for change output.\n" | ||||
" \"script\" : \"type\" (string, optional) The output " | " \"script\" : \"type\" (string, optional) The " | ||||
"script type. Only if \"isscript\" is true and the redeemscript is " | "output script type. Only if isscript is true and the redeemscript " | ||||
"known. Possible types: nonstandard, pubkey, pubkeyhash, " | "is known. Possible\n" | ||||
"scripthash, multisig, nulldata\n" | " types: " | ||||
"nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata\n" | |||||
" \"hex\" : \"hex\", (string, optional) The " | " \"hex\" : \"hex\", (string, optional) The " | ||||
"redeemscript for the p2sh address\n" | "redeemscript for the p2sh address.\n" | ||||
" \"pubkeys\" (string, optional) Array of " | " \"pubkeys\" (array, optional) Array " | ||||
"pubkeys associated with the known redeemscript (only if " | "of pubkeys associated with the known redeemscript (only if script " | ||||
"\"script\" is \"multisig\")\n" | "is multisig).\n" | ||||
" [\n" | " [\n" | ||||
" \"pubkey\"\n" | " \"pubkey\" (string)\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
" \"sigsrequired\" : xxxxx (numeric, optional) Number of " | " \"sigsrequired\" : xxxxx (numeric, optional) The " | ||||
"signatures required to spend multisig output (only if \"script\" " | "number of signatures required to spend multisig output (only if " | ||||
"is \"multisig\")\n" | "script is multisig).\n" | ||||
" \"pubkey\" : \"publickeyhex\", (string, optional) The hex " | " \"pubkey\" : \"publickeyhex\", (string, optional) The " | ||||
"value of the raw public key, for single-key addresses (possibly " | "hex value of the raw public key for single-key addresses " | ||||
"embedded in P2SH)\n" | "(possibly embedded in P2SH or P2WSH).\n" | ||||
" \"embedded\" : {...}, (object, optional) Information " | " \"embedded\" : {...}, (object, optional) " | ||||
"about the address embedded in P2SH, if relevant and known. It " | "Information about the address embedded in P2SH or P2WSH, if " | ||||
"includes all getaddressinfo output fields for the embedded " | "relevant and known. Includes all\n" | ||||
"address, excluding metadata (\"timestamp\", \"hdkeypath\", " | " " | ||||
"\"hdseedid\") and relation to the wallet (\"ismine\", " | "getaddressinfo output fields for the embedded address, excluding " | ||||
"\"iswatchonly\").\n" | "metadata (timestamp, hdkeypath,\n" | ||||
" \"iscompressed\" : true|false, (boolean) If the address is " | " " | ||||
"compressed\n" | "hdseedid) and relation to the wallet (ismine, iswatchonly).\n" | ||||
" \"label\" : \"label\" (string) The label associated " | " \"iscompressed\" : true|false, (boolean, optional) If " | ||||
"with the address, \"\" is the default label\n" | "the pubkey is compressed.\n" | ||||
" \"timestamp\" : timestamp, (number, optional) The creation " | " \"label\" : \"label\" (string) The label " | ||||
"time of the key if available in seconds since epoch (Jan 1 1970 " | "associated with the address. Defaults to \"\". Equivalent to the " | ||||
"GMT)\n" | "name field in the labels array.\n" | ||||
" \"hdkeypath\" : \"keypath\" (string, optional) The HD " | " \"timestamp\" : timestamp, (number, optional) The " | ||||
"keypath if the key is HD and available\n" | "creation time of the key if available, expressed in seconds since " | ||||
" \"hdseedid\" : \"<hash160>\" (string, optional) The Hash160 " | "Epoch Time (Jan 1 1970 GMT).\n" | ||||
"of the HD seed\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 " | " \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) The " | ||||
"fingperint of the master key.\n" | "fingerprint of the master key.\n" | ||||
" \"labels\" (object) Array of labels " | " \"labels\" (object) An array of " | ||||
"associated with the address.\n" | "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" | " [\n" | ||||
" { (json object of label data)\n" | " { (json object of label data)\n" | ||||
" \"name\": \"labelname\" (string) The label\n" | " \"name\": \"label name\" (string) The label name. " | ||||
" \"purpose\": \"string\" (string) Purpose of address " | "Defaults to \"\". Equivalent to the label field above.\n" | ||||
"(\"send\" for sending address, \"receive\" for receiving " | " \"purpose\": \"purpose\" (string) The purpose of the " | ||||
"address)\n" | "associated address (send or receive).\n" | ||||
" },...\n" | " },...\n" | ||||
" ]\n" | " ]\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{HelpExampleCli("getaddressinfo", | RPCExamples{ | ||||
"\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + | HelpExampleCli("getaddressinfo", | ||||
"\"qrmzys48glkpevp2l4t24jtcltc9hyzx9cep2qffm4\"") + | |||||
HelpExampleRpc("getaddressinfo", | HelpExampleRpc("getaddressinfo", | ||||
"\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")}, | "\"qrmzys48glkpevp2l4t24jtcltc9hyzx9cep2qffm4\"")}, | ||||
} | } | ||||
.Check(request); | .Check(request); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
UniValue ret(UniValue::VOBJ); | UniValue ret(UniValue::VOBJ); | ||||
CTxDestination dest = | CTxDestination dest = | ||||
DecodeDestination(request.params[0].get_str(), config.GetChainParams()); | DecodeDestination(request.params[0].get_str(), config.GetChainParams()); | ||||
// 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"); | ||||
} | } | ||||
std::string currentAddress = EncodeDestination(dest, config); | std::string currentAddress = EncodeDestination(dest, config); | ||||
ret.pushKV("address", currentAddress); | ret.pushKV("address", currentAddress); | ||||
CScript scriptPubKey = GetScriptForDestination(dest); | CScript scriptPubKey = GetScriptForDestination(dest); | ||||
ret.pushKV("scriptPubKey", | ret.pushKV("scriptPubKey", | ||||
HexStr(scriptPubKey.begin(), scriptPubKey.end())); | HexStr(scriptPubKey.begin(), scriptPubKey.end())); | ||||
const SigningProvider *provider = pwallet->GetSigningProvider(scriptPubKey); | const SigningProvider *provider = pwallet->GetSigningProvider(scriptPubKey); | ||||
isminetype mine = pwallet->IsMine(dest); | isminetype mine = pwallet->IsMine(dest); | ||||
ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); | ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); | ||||
bool solvable = provider && IsSolvable(*provider, scriptPubKey); | bool solvable = provider && IsSolvable(*provider, scriptPubKey); | ||||
ret.pushKV("solvable", solvable); | ret.pushKV("solvable", solvable); | ||||
if (solvable) { | if (solvable) { | ||||
ret.pushKV("desc", | ret.pushKV("desc", | ||||
InferDescriptor(scriptPubKey, *provider)->ToString()); | InferDescriptor(scriptPubKey, *provider)->ToString()); | ||||
} | } | ||||
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)); | 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); | UniValue detail = DescribeWalletAddress(pwallet, dest); | ||||
ret.pushKVs(detail); | 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)) { | if (pwallet->mapAddressBook.count(dest)) { | ||||
ret.pushKV("label", pwallet->mapAddressBook[dest].name); | ret.pushKV("label", pwallet->mapAddressBook[dest].name); | ||||
} | } | ||||
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey)); | ret.pushKV("ischange", pwallet->IsChange(scriptPubKey)); | ||||
// Fetch KeyMetadata, if present, for the timestamp, hdkeypath, hdseedid, | |||||
// and hdmasterfingerprint fields. | |||||
ScriptPubKeyMan *spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey); | ScriptPubKeyMan *spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey); | ||||
if (spk_man) { | if (spk_man) { | ||||
if (const CKeyMetadata *meta = spk_man->GetMetadata(dest)) { | if (const CKeyMetadata *meta = spk_man->GetMetadata(dest)) { | ||||
ret.pushKV("timestamp", meta->nCreateTime); | ret.pushKV("timestamp", meta->nCreateTime); | ||||
if (meta->has_key_origin) { | if (meta->has_key_origin) { | ||||
ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path)); | ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path)); | ||||
ret.pushKV("hdseedid", meta->hd_seed_id.GetHex()); | ret.pushKV("hdseedid", meta->hd_seed_id.GetHex()); | ||||
ret.pushKV("hdmasterfingerprint", | ret.pushKV("hdmasterfingerprint", | ||||
HexStr(meta->key_origin.fingerprint, | HexStr(meta->key_origin.fingerprint, | ||||
meta->key_origin.fingerprint + 4)); | meta->key_origin.fingerprint + 4)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Currently only one label can be associated with an address, return an | // Return a labels array containing a hash of key/value pairs for the label | ||||
// array so the API remains stable if we allow multiple labels to be | // name and address purpose. The name value is equivalent to the label field | ||||
// associated with an address. | // 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); | UniValue labels(UniValue::VARR); | ||||
std::map<CTxDestination, CAddressBookData>::iterator mi = | std::map<CTxDestination, CAddressBookData>::iterator mi = | ||||
pwallet->mapAddressBook.find(dest); | pwallet->mapAddressBook.find(dest); | ||||
if (mi != pwallet->mapAddressBook.end()) { | if (mi != pwallet->mapAddressBook.end()) { | ||||
labels.push_back(AddressBookDataToJSON(mi->second, true)); | labels.push_back(AddressBookDataToJSON(mi->second, true)); | ||||
} | } | ||||
ret.pushKV("labels", std::move(labels)); | ret.pushKV("labels", std::move(labels)); | ||||
▲ Show 20 Lines • Show All 541 Lines • Show Last 20 Lines |