diff options
Diffstat (limited to 'src/rpc/misc.cpp')
-rw-r--r-- | src/rpc/misc.cpp | 252 |
1 files changed, 37 insertions, 215 deletions
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index c11dda22c4..49e865a64a 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -3,12 +3,12 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <base58.h> #include <chain.h> #include <clientversion.h> #include <core_io.h> #include <crypto/ripemd160.h> #include <init.h> +#include <key_io.h> #include <validation.h> #include <httpserver.h> #include <net.h> @@ -33,221 +33,56 @@ #include <univalue.h> -#ifdef ENABLE_WALLET -class DescribeAddressVisitor : public boost::static_visitor<UniValue> -{ -public: - CWallet * const pwallet; - - explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_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<unsigned char>> 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 = boost::apply_visitor(*this, embedded); - 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 'embedded'->'address' field for P2SH or P2WSH wrapped addresses, and 'pubkeys' for - // inspecting multisig participants. - if (include_addresses) obj.pushKV("addresses", std::move(a)); - } - - UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); } - - UniValue operator()(const CKeyID &keyID) const { - UniValue obj(UniValue::VOBJ); - CPubKey vchPubKey; - obj.push_back(Pair("isscript", false)); - obj.push_back(Pair("iswitness", false)); - if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) { - obj.push_back(Pair("pubkey", HexStr(vchPubKey))); - obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); - } - return obj; - } - - UniValue operator()(const CScriptID &scriptID) const { - UniValue obj(UniValue::VOBJ); - CScript subscript; - obj.push_back(Pair("isscript", true)); - obj.push_back(Pair("iswitness", false)); - if (pwallet && pwallet->GetCScript(scriptID, subscript)) { - ProcessSubScript(subscript, obj, true); - } - return obj; - } - - UniValue operator()(const WitnessV0KeyHash& id) const - { - UniValue obj(UniValue::VOBJ); - CPubKey pubkey; - obj.push_back(Pair("isscript", false)); - obj.push_back(Pair("iswitness", true)); - obj.push_back(Pair("witness_version", 0)); - obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end()))); - if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) { - obj.push_back(Pair("pubkey", HexStr(pubkey))); - } - return obj; - } - - UniValue operator()(const WitnessV0ScriptHash& id) const - { - UniValue obj(UniValue::VOBJ); - CScript subscript; - obj.push_back(Pair("isscript", true)); - obj.push_back(Pair("iswitness", true)); - obj.push_back(Pair("witness_version", 0)); - obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end()))); - CRIPEMD160 hasher; - uint160 hash; - hasher.Write(id.begin(), 32).Finalize(hash.begin()); - if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) { - ProcessSubScript(subscript, obj); - } - return obj; - } - - UniValue operator()(const WitnessUnknown& id) const - { - UniValue obj(UniValue::VOBJ); - CScript subscript; - obj.push_back(Pair("iswitness", true)); - obj.push_back(Pair("witness_version", (int)id.version)); - obj.push_back(Pair("witness_program", HexStr(id.program, id.program + id.length))); - return obj; - } -}; -#endif - UniValue validateaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "validateaddress \"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.18. 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" - "1. \"address\" (string, required) The bitcoin address to validate\n" + "1. \"address\" (string, required) The bitcoin address to validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\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" - " \"isscript\" : true|false, (boolean, optional) If the address is P2SH or P2WSH. Not included for unknown witness types.\n" - " \"iswitness\" : true|false, (boolean) If the address is P2WPKH, P2WSH, or an unknown witness version\n" - " \"witness_version\" : version (number, optional) For all witness output types, gives the version number.\n" - " \"witness_program\" : \"hex\" (string, optional) For all witness output types, gives the script or key hash present in the address.\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, witness_v0_keyhash, witness_v0_scripthash, witness_unknown\n" - " \"hex\" : \"hex\", (string, optional) The redeemscript for the P2SH or P2WSH address\n" - " \"addresses\" (string, optional) Array of addresses associated with the known redeemscript (only if \"iswitness\" is false). This field is superseded by the \"pubkeys\" field and the address inside \"embedded\".\n" - " [\n" - " \"address\"\n" - " ,...\n" - " ]\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 or P2WSH)\n" - " \"embedded\" : {...}, (object, optional) information about the address embedded in P2SH or P2WSH, 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" + " \"isscript\" : true|false, (boolean) If the key is a script\n" + " \"iswitness\" : true|false, (boolean) If the address is a witness address\n" + " \"witness_version\" : version (numeric, optional) The version number of the witness program\n" + " \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n" "}\n" "\nExamples:\n" + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") ); -#ifdef ENABLE_WALLET - CWallet * const pwallet = GetWalletForJSONRPCRequest(request); - - LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr); -#else - LOCK(cs_main); -#endif - CTxDestination dest = DecodeDestination(request.params[0].get_str()); bool isValid = IsValidDestination(dest); UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("isvalid", isValid)); + ret.pushKV("isvalid", isValid); if (isValid) { - std::string currentAddress = EncodeDestination(dest); - ret.push_back(Pair("address", currentAddress)); - - CScript scriptPubKey = GetScriptForDestination(dest); - ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); #ifdef ENABLE_WALLET - isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO; - ret.push_back(Pair("ismine", bool(mine & ISMINE_SPENDABLE))); - ret.push_back(Pair("iswatchonly", bool(mine & ISMINE_WATCH_ONLY))); - UniValue detail = boost::apply_visitor(DescribeAddressVisitor(pwallet), dest); - ret.pushKVs(detail); - if (pwallet && pwallet->mapAddressBook.count(dest)) { - ret.push_back(Pair("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.push_back(Pair("timestamp", meta->nCreateTime)); - if (!meta->hdKeypath.empty()) { - ret.push_back(Pair("hdkeypath", meta->hdKeypath)); - ret.push_back(Pair("hdmasterkeyid", meta->hdMasterKeyID.GetHex())); - } - } + if (!::vpwallets.empty() && IsDeprecatedRPCEnabled("validateaddress")) { + ret.pushKVs(getaddressinfo(request)); } #endif + if (ret["address"].isNull()) { + std::string currentAddress = EncodeDestination(dest); + ret.pushKV("address", currentAddress); + + CScript scriptPubKey = GetScriptForDestination(dest); + ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));; + + UniValue detail = DescribeAddress(dest); + ret.pushKVs(detail); + } } return ret; } @@ -262,11 +97,8 @@ UniValue createmultisig(const JSONRPCRequest& request) std::string msg = "createmultisig nrequired [\"key\",...]\n" "\nCreates a multi-signature address with n signature of m keys required.\n" "It returns a json object with the address and redeemScript.\n" - "DEPRECATION WARNING: Using addresses with createmultisig is deprecated. Clients must\n" - "transition to using addmultisigaddress to create multisig addresses with addresses known\n" - "to the wallet before upgrading to v0.17. To use the deprecated functionality, start bitcoind with -deprecatedrpc=createmultisig\n" "\nArguments:\n" - "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" + "1. nrequired (numeric, required) The number of required signatures out of the n keys.\n" "2. \"keys\" (string, required) A json array of hex-encoded public keys\n" " [\n" " \"key\" (string) The hex-encoded public key\n" @@ -297,15 +129,8 @@ UniValue createmultisig(const JSONRPCRequest& request) if (IsHex(keys[i].get_str()) && (keys[i].get_str().length() == 66 || keys[i].get_str().length() == 130)) { pubkeys.push_back(HexToPubKey(keys[i].get_str())); } else { -#ifdef ENABLE_WALLET - CWallet* const pwallet = GetWalletForJSONRPCRequest(request); - if (IsDeprecatedRPCEnabled("createmultisig") && EnsureWalletIsAvailable(pwallet, false)) { - pubkeys.push_back(AddrToPubKey(pwallet, keys[i].get_str())); - } else -#endif throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid public key: %s\nNote that from v0.16, createmultisig no longer accepts addresses." - " Clients must transition to using addmultisigaddress to create multisig addresses with addresses known to the wallet before upgrading to v0.17." - " To use the deprecated functionality, start bitcoind with -deprecatedrpc=createmultisig", keys[i].get_str())); + " Users must use addmultisigaddress to create multisig addresses with addresses known to the wallet.", keys[i].get_str())); } } @@ -314,8 +139,8 @@ UniValue createmultisig(const JSONRPCRequest& request) CScriptID innerID(inner); UniValue result(UniValue::VOBJ); - result.push_back(Pair("address", EncodeDestination(innerID))); - result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); + result.pushKV("address", EncodeDestination(innerID)); + result.pushKV("redeemScript", HexStr(inner.begin(), inner.end())); return result; } @@ -399,13 +224,10 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request) std::string strPrivkey = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strPrivkey); - if (!fGood) + CKey key = DecodeSecret(strPrivkey); + if (!key.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); - CKey key = vchSecret.GetKey(); - if (!key.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range"); + } CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; @@ -449,12 +271,12 @@ static UniValue RPCLockedMemoryInfo() { LockedPool::Stats stats = LockedPoolManager::Instance().stats(); UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("used", uint64_t(stats.used))); - obj.push_back(Pair("free", uint64_t(stats.free))); - obj.push_back(Pair("total", uint64_t(stats.total))); - obj.push_back(Pair("locked", uint64_t(stats.locked))); - obj.push_back(Pair("chunks_used", uint64_t(stats.chunks_used))); - obj.push_back(Pair("chunks_free", uint64_t(stats.chunks_free))); + obj.pushKV("used", uint64_t(stats.used)); + obj.pushKV("free", uint64_t(stats.free)); + obj.pushKV("total", uint64_t(stats.total)); + obj.pushKV("locked", uint64_t(stats.locked)); + obj.pushKV("chunks_used", uint64_t(stats.chunks_used)); + obj.pushKV("chunks_free", uint64_t(stats.chunks_free)); return obj; } @@ -511,7 +333,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request) std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str(); if (mode == "stats") { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("locked", RPCLockedMemoryInfo())); + obj.pushKV("locked", RPCLockedMemoryInfo()); return obj; } else if (mode == "mallocinfo") { #ifdef HAVE_MALLOC_INFO |