Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/misc.cpp
Show All 27 Lines | |||||
#include <univalue.h> | #include <univalue.h> | ||||
#include <cstdint> | #include <cstdint> | ||||
#ifdef HAVE_MALLOC_INFO | #ifdef HAVE_MALLOC_INFO | ||||
#include <malloc.h> | #include <malloc.h> | ||||
#endif | #endif | ||||
#ifdef ENABLE_WALLET | |||||
class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue> { | |||||
public: | |||||
CWallet *const pwallet; | |||||
void ProcessSubScript(const CScript &subscript, UniValue &obj, | |||||
bool include_addresses = false) const { | |||||
// Always present: script type and redeemscript | |||||
txnouttype which_type; | |||||
std::vector<std::vector<uint8_t>> solutions_data; | |||||
Solver(subscript, which_type, solutions_data); | |||||
obj.pushKV("script", GetTxnOutputType(which_type)); | |||||
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end())); | |||||
CTxDestination embedded; | |||||
UniValue a(UniValue::VARR); | |||||
if (ExtractDestination(subscript, embedded)) { | |||||
// Only when the script corresponds to an address. | |||||
UniValue subobj(UniValue::VOBJ); | |||||
UniValue detail = DescribeAddress(embedded); | |||||
subobj.pushKVs(detail); | |||||
UniValue wallet_detail = boost::apply_visitor(*this, embedded); | |||||
subobj.pushKVs(wallet_detail); | |||||
subobj.pushKV("address", EncodeDestination(embedded)); | |||||
subobj.pushKV("scriptPubKey", | |||||
HexStr(subscript.begin(), subscript.end())); | |||||
// Always report the pubkey at the top level, so that | |||||
// `getnewaddress()['pubkey']` always works. | |||||
if (subobj.exists("pubkey")) { | |||||
obj.pushKV("pubkey", subobj["pubkey"]); | |||||
} | |||||
obj.pushKV("embedded", std::move(subobj)); | |||||
if (include_addresses) { | |||||
a.push_back(EncodeDestination(embedded)); | |||||
} | |||||
} else if (which_type == TX_MULTISIG) { | |||||
// Also report some information on multisig scripts (which do not | |||||
// have a corresponding address). | |||||
// TODO: abstract out the common functionality between this logic | |||||
// and ExtractDestinations. | |||||
obj.pushKV("sigsrequired", solutions_data[0][0]); | |||||
UniValue pubkeys(UniValue::VARR); | |||||
for (size_t i = 1; i < solutions_data.size() - 1; ++i) { | |||||
CPubKey key(solutions_data[i].begin(), solutions_data[i].end()); | |||||
if (include_addresses) { | |||||
a.push_back(EncodeDestination(key.GetID())); | |||||
} | |||||
pubkeys.push_back(HexStr(key.begin(), key.end())); | |||||
} | |||||
obj.pushKV("pubkeys", std::move(pubkeys)); | |||||
} | |||||
// The "addresses" field is confusing because it refers to public keys | |||||
// using their P2PKH address. For that reason, only add the 'addresses' | |||||
// field when needed for backward compatibility. New applications can | |||||
// use the 'pubkeys' field for inspecting multisig participants. | |||||
if (include_addresses) { | |||||
obj.pushKV("addresses", std::move(a)); | |||||
} | |||||
} | |||||
explicit DescribeWalletAddressVisitor(CWallet *_pwallet) | |||||
: pwallet(_pwallet) {} | |||||
UniValue operator()(const CNoDestination &dest) const { | |||||
return UniValue(UniValue::VOBJ); | |||||
} | |||||
UniValue operator()(const CKeyID &keyID) const { | |||||
UniValue obj(UniValue::VOBJ); | |||||
CPubKey vchPubKey; | |||||
if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) { | |||||
obj.pushKV("pubkey", HexStr(vchPubKey)); | |||||
obj.pushKV("iscompressed", vchPubKey.IsCompressed()); | |||||
} | |||||
return obj; | |||||
} | |||||
UniValue operator()(const CScriptID &scriptID) const { | |||||
UniValue obj(UniValue::VOBJ); | |||||
CScript subscript; | |||||
if (pwallet && pwallet->GetCScript(scriptID, subscript)) { | |||||
ProcessSubScript(subscript, obj, true); | |||||
} | |||||
return obj; | |||||
} | |||||
}; | |||||
UniValue DescribeWalletAddress(CWallet *pwallet, const CTxDestination &dest) { | |||||
UniValue ret(UniValue::VOBJ); | |||||
UniValue detail = DescribeAddress(dest); | |||||
ret.pushKVs(detail); | |||||
ret.pushKVs( | |||||
boost::apply_visitor(DescribeWalletAddressVisitor(pwallet), dest)); | |||||
return ret; | |||||
} | |||||
#endif | |||||
static UniValue validateaddress(const Config &config, | static UniValue validateaddress(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | if (request.fHelp || request.params.size() != 1) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"validateaddress \"address\"\n" | "validateaddress \"address\"\n" | ||||
"\nReturn information about the given bitcoin address.\n" | "\nReturn information about the given bitcoin address.\n" | ||||
"DEPRECATION WARNING: Parts of this command have been deprecated " | |||||
"and moved to getaddressinfo. Clients must\n" | |||||
"transition to using getaddressinfo to access this information " | |||||
"before upgrading to v0.20. The following deprecated\n" | |||||
"fields have moved to getaddressinfo and will only be shown here " | |||||
"with -deprecatedrpc=validateaddress: ismine, iswatchonly,\n" | |||||
"script, hex, pubkeys, sigsrequired, pubkey, addresses, embedded, " | |||||
"iscompressed, account, timestamp, hdkeypath, kdmasterkeyid.\n" | |||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"address\" (string, required) The bitcoin address to " | "1. \"address\" (string, required) The bitcoin " | ||||
"validate\n" | "address to validate\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"{\n" | "{\n" | ||||
" \"isvalid\" : true|false, (boolean) If the address is " | " \"isvalid\" : true|false, (boolean) If the address is " | ||||
"valid or not. If not, this is the only property returned.\n" | "valid or not. If not, this is the only property returned.\n" | ||||
" \"address\" : \"address\", (string) The bitcoin address " | " \"address\" : \"address\", (string) The bitcoin address " | ||||
"validated\n" | "validated\n" | ||||
" \"scriptPubKey\" : \"hex\", (string) The hex encoded " | " \"scriptPubKey\" : \"hex\", (string) The hex encoded " | ||||
"scriptPubKey generated by the address\n" | "scriptPubKey generated by the address\n" | ||||
" \"ismine\" : true|false, (boolean) If the address is " | " \"isscript\" : true|false, (boolean) If the key is a " | ||||
"yours or not\n" | "script\n" | ||||
" \"iswatchonly\" : true|false, (boolean) If the address is " | |||||
"watchonly\n" | |||||
" \"isscript\" : true|false, (boolean, optional) If the key " | |||||
"is a script.\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" | |||||
" [\n" | |||||
" \"pubkey\"\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 validateaddress output fields for the embedded " | |||||
"address, excluding \"isvalid\", metadata (\"timestamp\", " | |||||
"\"hdkeypath\", \"hdmasterkeyid\") and relation to the wallet " | |||||
"(\"ismine\", \"iswatchonly\", \"account\").\n" | |||||
" \"iscompressed\" : true|false, (boolean) If the address is " | |||||
"compressed\n" | |||||
" \"account\" : \"account\" (string) DEPRECATED. The " | |||||
"account associated with the address, \"\" is the default account\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" | |||||
" \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The " | |||||
"Hash160 of the HD master pubkey\n" | |||||
"}\n" | "}\n" | ||||
"\nExamples:\n" + | "\nExamples:\n" + | ||||
HelpExampleCli("validateaddress", | HelpExampleCli("validateaddress", | ||||
"\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + | "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + | ||||
HelpExampleRpc("validateaddress", | HelpExampleRpc("validateaddress", | ||||
"\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")); | "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")); | ||||
} | } | ||||
#ifdef ENABLE_WALLET | |||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | |||||
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr); | |||||
#else | |||||
LOCK(cs_main); | |||||
#endif | |||||
CTxDestination dest = | CTxDestination dest = | ||||
DecodeDestination(request.params[0].get_str(), config.GetChainParams()); | DecodeDestination(request.params[0].get_str(), config.GetChainParams()); | ||||
bool isValid = IsValidDestination(dest); | bool isValid = IsValidDestination(dest); | ||||
UniValue ret(UniValue::VOBJ); | UniValue ret(UniValue::VOBJ); | ||||
ret.pushKV("isvalid", isValid); | ret.pushKV("isvalid", isValid); | ||||
if (isValid) { | if (isValid) { | ||||
#ifdef ENABLE_WALLET | |||||
if (!::vpwallets.empty() && | |||||
IsDeprecatedRPCEnabled(gArgs, "validateaddress")) { | |||||
ret.pushKVs(getaddressinfo(config, request)); | |||||
} | |||||
#endif | |||||
if (ret["address"].isNull()) { | |||||
std::string currentAddress = EncodeDestination(dest); | std::string currentAddress = EncodeDestination(dest); | ||||
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())); | ||||
#ifdef ENABLE_WALLET | UniValue detail = DescribeAddress(dest); | ||||
isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO; | |||||
ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); | |||||
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)); | |||||
UniValue detail = DescribeWalletAddress(pwallet, dest); | |||||
ret.pushKVs(detail); | ret.pushKVs(detail); | ||||
if (pwallet && pwallet->mapAddressBook.count(dest)) { | |||||
ret.pushKV("account", pwallet->mapAddressBook[dest].name); | |||||
} | } | ||||
if (pwallet) { | |||||
const CKeyMetadata *meta = nullptr; | |||||
CKeyID key_id = GetKeyForDestination(*pwallet, dest); | |||||
if (!key_id.IsNull()) { | |||||
auto it = pwallet->mapKeyMetadata.find(key_id); | |||||
if (it != pwallet->mapKeyMetadata.end()) { | |||||
meta = &it->second; | |||||
} | |||||
} | |||||
if (!meta) { | |||||
auto it = | |||||
pwallet->m_script_metadata.find(CScriptID(scriptPubKey)); | |||||
if (it != pwallet->m_script_metadata.end()) { | |||||
meta = &it->second; | |||||
} | |||||
} | |||||
if (meta) { | |||||
ret.pushKV("timestamp", meta->nCreateTime); | |||||
if (!meta->hdKeypath.empty()) { | |||||
ret.pushKV("hdkeypath", meta->hdKeypath); | |||||
ret.pushKV("hdmasterkeyid", meta->hdMasterKeyID.GetHex()); | |||||
} | |||||
} | |||||
} | |||||
#else | |||||
ret.pushKvs = DescribeAddress(dest); | |||||
#endif | |||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around | // Needed even with !ENABLE_WALLET, to pass (ignored) pointers around | ||||
class CWallet; | class CWallet; | ||||
static UniValue createmultisig(const Config &config, | static UniValue createmultisig(const Config &config, | ||||
▲ Show 20 Lines • Show All 388 Lines • Show Last 20 Lines |