Page MenuHomePhabricator

No OneTemporary

diff --git a/doc/release-notes.md b/doc/release-notes.md
index f0c8d8c2ea..05c0af90a6 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,5 +1,6 @@
Bitcoin ABC version 0.19.8 is now available from:
<https://download.bitcoinabc.org/0.19.8/>
This release includes the following features and fixes:
+ - Remove `getinfo` RPC in favor of `getblockchaininfo`, `getnetworkinfo` and `getwalletinfo`.
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index ca09a63c3b..91205e1d08 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -1,730 +1,625 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// 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 <config.h>
#include <dstencode.h>
#include <init.h>
#include <net.h>
#include <netbase.h>
#include <rpc/blockchain.h>
#include <rpc/misc.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <timedata.h>
#include <util.h>
#include <utilstrencodings.h>
#include <validation.h>
#ifdef ENABLE_WALLET
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
#endif
#include <warnings.h>
#include <univalue.h>
#include <cstdint>
#ifdef HAVE_MALLOC_INFO
#include <malloc.h>
#endif
-/**
- * @note Do not add or change anything in the information returned by this
- * method. `getinfo` exists for backwards-compatibility only. It combines
- * information from wildly different sources in the program, which is a mess,
- * and is thus planned to be deprecated eventually.
- *
- * Based on the source of the information, new information should be added to:
- * - `getblockchaininfo`,
- * - `getnetworkinfo` or
- * - `getwalletinfo`
- *
- * Or alternatively, create a specific query method for the information.
- **/
-static UniValue getinfo(const Config &config, const JSONRPCRequest &request) {
- if (request.fHelp || request.params.size() != 0) {
- throw std::runtime_error(
- "getinfo\n"
- "\nDEPRECATED. Returns an object containing various state info.\n"
- "\nResult:\n"
- "{\n"
- " \"version\": xxxxx, (numeric) the server version\n"
- " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
- " \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total bitcoin "
- "balance of the wallet\n"
- " \"blocks\": xxxxxx, (numeric) the current number of "
- "blocks processed in the server\n"
- " \"timeoffset\": xxxxx, (numeric) the time offset\n"
- " \"connections\": xxxxx, (numeric) the number of "
- "connections\n"
- " \"proxy\": \"host:port\", (string, optional) the proxy used "
- "by the server\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"testnet\": true|false, (boolean) if the server is using "
- "testnet or not\n"
- " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds "
- "since Unix epoch) of the oldest pre-generated key in the key "
- "pool\n"
- " \"keypoolsize\": xxxx, (numeric) how many new keys are "
- "pre-generated\n"
- " \"unlocked_until\": ttt, (numeric) the timestamp in "
- "seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is "
- "unlocked for transfers, or 0 if the wallet is locked\n"
- " \"paytxfee\": x.xxxx, (numeric) the transaction fee set "
- "in " +
- CURRENCY_UNIT +
- "/kB\n"
- " \"relayfee\": x.xxxx, (numeric) minimum relay fee for "
- "non-free transactions in " +
- CURRENCY_UNIT +
- "/kB\n"
- " \"errors\": \"...\" (string) any error messages\n"
- "}\n"
- "\nExamples:\n" +
- HelpExampleCli("getinfo", "") + HelpExampleRpc("getinfo", ""));
- }
-
-#ifdef ENABLE_WALLET
- CWallet *const pwallet = GetWalletForJSONRPCRequest(request);
-
- LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
-#else
- LOCK(cs_main);
-#endif
-
- proxyType proxy;
- GetProxy(NET_IPV4, proxy);
-
- UniValue obj(UniValue::VOBJ);
- obj.pushKV("version", CLIENT_VERSION);
- obj.pushKV("protocolversion", PROTOCOL_VERSION);
-#ifdef ENABLE_WALLET
- if (pwallet) {
- obj.pushKV("walletversion", pwallet->GetVersion());
- obj.pushKV("balance", ValueFromAmount(pwallet->GetBalance()));
- }
-#endif
- obj.pushKV("blocks", (int)chainActive.Height());
- obj.pushKV("timeoffset", GetTimeOffset());
- if (g_connman) {
- obj.pushKV("connections",
- (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
- }
- obj.pushKV("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort()
- : std::string()));
- obj.pushKV("difficulty", double(GetDifficulty(chainActive.Tip())));
- obj.pushKV("testnet", config.GetChainParams().NetworkIDString() ==
- CBaseChainParams::TESTNET);
-#ifdef ENABLE_WALLET
- if (pwallet) {
- obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
- obj.pushKV("keypoolsize", (int)pwallet->GetKeyPoolSize());
- }
- if (pwallet && pwallet->IsCrypted()) {
- obj.pushKV("unlocked_until", pwallet->nRelockTime);
- }
- obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()));
-#endif
- obj.pushKV("relayfee",
- ValueFromAmount(config.GetMinFeePerKB().GetFeePerK()));
- obj.pushKV("errors", GetWarnings("statusbar"));
- return obj;
-}
-
#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<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 = 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 'pubkeys' field 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.pushKV("isscript", false);
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;
obj.pushKV("isscript", true);
if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
ProcessSubScript(subscript, obj, true);
}
return obj;
}
};
#endif
static UniValue validateaddress(const Config &config,
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"
"\nArguments:\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 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"
"\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(), config.GetChainParams());
bool isValid = IsValidDestination(dest);
UniValue ret(UniValue::VOBJ);
ret.pushKV("isvalid", isValid);
if (isValid) {
std::string currentAddress = EncodeDestination(dest);
ret.pushKV("address", currentAddress);
CScript scriptPubKey = GetScriptForDestination(dest);
ret.pushKV("scriptPubKey",
HexStr(scriptPubKey.begin(), scriptPubKey.end()));
#ifdef ENABLE_WALLET
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 =
boost::apply_visitor(DescribeAddressVisitor(pwallet), dest);
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());
}
}
}
#endif
}
return ret;
}
// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around
class CWallet;
static UniValue createmultisig(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() < 2 ||
request.params.size() > 2) {
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.20. 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"
"2. \"keys\" (string, required) A json array of hex-encoded "
"public keys\n"
" [\n"
" \"key\" (string) The hex-encoded public key\n"
" ,...\n"
" ]\n"
"\nResult:\n"
"{\n"
" \"address\":\"multisigaddress\", (string) The value of the new "
"multisig address.\n"
" \"redeemScript\":\"script\" (string) The string value of "
"the hex-encoded redemption script.\n"
"}\n"
"\nExamples:\n"
"\nCreate a multisig address from 2 public keys\n" +
HelpExampleCli("createmultisig",
"2 "
"\"["
"\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3"
"42cf11ae157a7ace5fd\\\","
"\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1"
"7e107ef3f6aa5a61626\\\"]\"") +
"\nAs a json rpc call\n" +
HelpExampleRpc("createmultisig",
"2, "
"\"["
"\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3"
"42cf11ae157a7ace5fd\\\","
"\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1"
"7e107ef3f6aa5a61626\\\"]\"");
throw std::runtime_error(msg);
}
int required = request.params[0].get_int();
// Get the public keys
const UniValue &keys = request.params[1].get_array();
std::vector<CPubKey> pubkeys;
for (size_t i = 0; i < keys.size(); ++i) {
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(gArgs, "createmultisig") &&
EnsureWalletIsAvailable(pwallet, false)) {
pubkeys.push_back(AddrToPubKey(config.GetChainParams(), pwallet,
keys[i].get_str()));
} else
#endif
throw JSONRPCError(
RPC_INVALID_ADDRESS_OR_KEY,
strprintf("Invalid public key: %s\nNote that from v0.19.6, "
"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.20."
" To use the deprecated functionality, start "
"bitcoind with -deprecatedrpc=createmultisig",
keys[i].get_str()));
}
}
// Construct using pay-to-script-hash:
CScript inner = CreateMultisigRedeemscript(required, pubkeys);
CScriptID innerID(inner);
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(innerID));
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
return result;
}
static UniValue verifymessage(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 3) {
throw std::runtime_error(
"verifymessage \"address\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
"1. \"address\" (string, required) The bitcoin address to "
"use for the signature.\n"
"2. \"signature\" (string, required) The signature provided "
"by the signer in base 64 encoding (see signmessage).\n"
"3. \"message\" (string, required) The message that was "
"signed.\n"
"\nResult:\n"
"true|false (boolean) If the signature is verified or not.\n"
"\nExamples:\n"
"\nUnlock the wallet for 30 seconds\n" +
HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n" +
HelpExampleCli(
"signmessage",
"\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n" +
HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4"
"XX\" \"signature\" \"my "
"message\"") +
"\nAs json rpc\n" +
HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4"
"XX\", \"signature\", \"my "
"message\""));
}
LOCK(cs_main);
std::string strAddress = request.params[0].get_str();
std::string strSign = request.params[1].get_str();
std::string strMessage = request.params[2].get_str();
CTxDestination destination =
DecodeDestination(strAddress, config.GetChainParams());
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
const CKeyID *keyID = boost::get<CKeyID>(&destination);
if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
bool fInvalid = false;
std::vector<uint8_t> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
if (fInvalid) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
"Malformed base64 encoding");
}
CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << strMessage;
CPubKey pubkey;
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) {
return false;
}
return (pubkey.GetID() == *keyID);
}
static UniValue signmessagewithprivkey(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
"\nArguments:\n"
"1. \"privkey\" (string, required) The private key to sign "
"the message with.\n"
"2. \"message\" (string, required) The message to create a "
"signature of.\n"
"\nResult:\n"
"\"signature\" (string) The signature of the message "
"encoded in base 64\n"
"\nExamples:\n"
"\nCreate the signature\n" +
HelpExampleCli("signmessagewithprivkey",
"\"privkey\" \"my message\"") +
"\nVerify the signature\n" +
HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4"
"XX\" \"signature\" \"my "
"message\"") +
"\nAs json rpc\n" +
HelpExampleRpc("signmessagewithprivkey",
"\"privkey\", \"my message\""));
}
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) {
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;
ss << strMessage;
std::vector<uint8_t> vchSig;
if (!key.SignCompact(ss.GetHash(), vchSig)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
}
return EncodeBase64(&vchSig[0], vchSig.size());
}
static UniValue setmocktime(const Config &config,
const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nArguments:\n"
"1. timestamp (integer, required) Unix seconds-since-epoch "
"timestamp\n"
" Pass 0 to go back to using the system time.");
}
if (!config.GetChainParams().MineBlocksOnDemand()) {
throw std::runtime_error(
"setmocktime for regression testing (-regtest mode) only");
}
// For now, don't change mocktime if we're in the middle of validation, as
// this could have an effect on mempool time-based eviction, as well as
// IsInitialBlockDownload().
// TODO: figure out the right way to synchronize around mocktime, and
// ensure all call sites of GetTime() are accessing this safely.
LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VNUM});
SetMockTime(request.params[0].get_int64());
return NullUniValue;
}
static UniValue RPCLockedMemoryInfo() {
LockedPool::Stats stats = LockedPoolManager::Instance().stats();
UniValue obj(UniValue::VOBJ);
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;
}
#ifdef HAVE_MALLOC_INFO
static std::string RPCMallocInfo() {
char *ptr = nullptr;
size_t size = 0;
FILE *f = open_memstream(&ptr, &size);
if (f) {
malloc_info(0, f);
fclose(f);
if (ptr) {
std::string rv(ptr, size);
free(ptr);
return rv;
}
}
return "";
}
#endif
static UniValue getmemoryinfo(const Config &config,
const JSONRPCRequest &request) {
/* Please, avoid using the word "pool" here in the RPC interface or help,
* as users will undoubtedly confuse it with the other "memory pool"
*/
if (request.fHelp || request.params.size() > 1) {
throw std::runtime_error(
"getmemoryinfo (\"mode\")\n"
"Returns an object containing information about memory usage.\n"
"Arguments:\n"
"1. \"mode\" determines what kind of information is returned. This "
"argument is optional, the default mode is \"stats\".\n"
" - \"stats\" returns general statistics about memory usage in "
"the daemon.\n"
" - \"mallocinfo\" returns an XML string describing low-level "
"heap state (only available if compiled with glibc 2.10+).\n"
"\nResult (mode \"stats\"):\n"
"{\n"
" \"locked\": { (json object) Information about "
"locked memory manager\n"
" \"used\": xxxxx, (numeric) Number of bytes used\n"
" \"free\": xxxxx, (numeric) Number of bytes available "
"in current arenas\n"
" \"total\": xxxxxxx, (numeric) Total number of bytes "
"managed\n"
" \"locked\": xxxxxx, (numeric) Amount of bytes that "
"succeeded locking. If this number is smaller than total, locking "
"pages failed at some point and key data could be swapped to "
"disk.\n"
" \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n"
" \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
" }\n"
"}\n"
"\nResult (mode \"mallocinfo\"):\n"
"\"<malloc version=\"1\">...\"\n"
"\nExamples:\n" +
HelpExampleCli("getmemoryinfo", "") +
HelpExampleRpc("getmemoryinfo", ""));
}
std::string mode = (request.params.size() < 1 || request.params[0].isNull())
? "stats"
: request.params[0].get_str();
if (mode == "stats") {
UniValue obj(UniValue::VOBJ);
obj.pushKV("locked", RPCLockedMemoryInfo());
return obj;
} else if (mode == "mallocinfo") {
#ifdef HAVE_MALLOC_INFO
return RPCMallocInfo();
#else
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"mallocinfo is only available when compiled with glibc 2.10+");
#endif
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode);
}
}
static UniValue echo(const Config &config, const JSONRPCRequest &request) {
if (request.fHelp) {
throw std::runtime_error(
"echo|echojson \"message\" ...\n"
"\nSimply echo back the input arguments. This command is for "
"testing.\n"
"\nThe difference between echo and echojson is that echojson has "
"argument conversion enabled in the client-side table in"
"bitcoin-cli and the GUI. There is no server-side difference.");
}
return request.params;
}
// clang-format off
static const ContextFreeRPCCommand commands[] = {
// category name actor (function) argNames
// ------------------- ------------------------ ---------------------- ----------
- { "control", "getinfo", getinfo, {} }, /* uses wallet if enabled */
{ "control", "getmemoryinfo", getmemoryinfo, {"mode"} },
{ "util", "validateaddress", validateaddress, {"address"} }, /* uses wallet if enabled */
{ "util", "createmultisig", createmultisig, {"nrequired","keys"} },
{ "util", "verifymessage", verifymessage, {"address","signature","message"} },
{ "util", "signmessagewithprivkey", signmessagewithprivkey, {"privkey","message"} },
/* Not shown in help */
{ "hidden", "setmocktime", setmocktime, {"timestamp"}},
{ "hidden", "echo", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
{ "hidden", "echojson", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
};
// clang-format on
void RegisterMiscRPCCommands(CRPCTable &t) {
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) {
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 276f1389c5..94bdf50b81 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1,1388 +1,1388 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Copyright (c) 2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_WALLET_WALLET_H
#define BITCOIN_WALLET_WALLET_H
#include <amount.h>
#include <script/ismine.h>
#include <script/sign.h>
#include <streams.h>
#include <tinyformat.h>
#include <ui_interface.h>
#include <util.h>
#include <utilstrencodings.h>
#include <validationinterface.h>
#include <wallet/crypter.h>
#include <wallet/rpcwallet.h>
#include <wallet/walletdb.h>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <map>
#include <set>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
typedef CWallet *CWalletRef;
extern std::vector<CWalletRef> vpwallets;
/**
* Settings
*/
extern CFeeRate payTxFee;
extern bool bSpendZeroConfChange;
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
//! -paytxfee default
static const Amount DEFAULT_TRANSACTION_FEE = Amount::zero();
//! -fallbackfee default
static const Amount DEFAULT_FALLBACK_FEE(20000 * SATOSHI);
//! minimum recommended increment for BIP 125 replacement txs
static const Amount WALLET_INCREMENTAL_RELAY_FEE(5000 * SATOSHI);
//! target minimum change amount
static const Amount MIN_CHANGE = CENT;
//! final minimum change amount after paying for fees
static const Amount MIN_FINAL_CHANGE = MIN_CHANGE / 2;
//! Default for -spendzeroconfchange
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
//! Default for -walletrejectlongchains
static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
//! Largest (in bytes) free transaction we're willing to create
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false;
static const int64_t TIMESTAMP_MIN = 0;
class CBlockIndex;
class CChainParams;
class CCoinControl;
class COutput;
class CReserveKey;
class CScript;
class CScheduler;
class CTxMemPool;
class CWalletTx;
/** (client) version numbers for particular wallet features */
enum WalletFeature {
- // the earliest version new wallets supports (only useful for getinfo's
- // clientversion output)
+ // the earliest version new wallets supports (only useful for
+ // getwalletinfo's clientversion output)
FEATURE_BASE = 10500,
// wallet encryption
FEATURE_WALLETCRYPT = 40000,
// compressed public keys
FEATURE_COMPRPUBKEY = 60000,
// Hierarchical key derivation after BIP32 (HD Wallet)
FEATURE_HD = 130000,
// Wallet with HD chain split (change outputs will use m/0'/1'/k)
FEATURE_HD_SPLIT = 160300,
// Wallet without a default key written
FEATURE_NO_DEFAULT_KEY = 190700,
// HD is optional, use FEATURE_COMPRPUBKEY as latest version
FEATURE_LATEST = FEATURE_COMPRPUBKEY,
};
enum class OutputType {
NONE,
LEGACY,
DEFAULT = LEGACY,
};
extern OutputType g_address_type;
extern OutputType g_change_type;
/** A key pool entry */
class CKeyPool {
public:
int64_t nTime;
CPubKey vchPubKey;
bool fInternal; // for change outputs
CKeyPool();
CKeyPool(const CPubKey &vchPubKeyIn, bool internalIn);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(nVersion);
}
READWRITE(nTime);
READWRITE(vchPubKey);
if (ser_action.ForRead()) {
try {
READWRITE(fInternal);
} catch (std::ios_base::failure &) {
/**
* flag as external address if we can't read the internal
* boolean
* (this will be the case for any wallet before the HD chain
* split version)
*/
fInternal = false;
}
} else {
READWRITE(fInternal);
}
}
};
/** Address book data */
class CAddressBookData {
public:
std::string name;
std::string purpose;
CAddressBookData() : purpose("unknown") {}
typedef std::map<std::string, std::string> StringMap;
StringMap destdata;
};
struct CRecipient {
CScript scriptPubKey;
Amount nAmount;
bool fSubtractFeeFromAmount;
};
typedef std::map<std::string, std::string> mapValue_t;
static inline void ReadOrderPos(int64_t &nOrderPos, mapValue_t &mapValue) {
if (!mapValue.count("n")) {
// TODO: calculate elsewhere
nOrderPos = -1;
return;
}
nOrderPos = atoi64(mapValue["n"].c_str());
}
static inline void WriteOrderPos(const int64_t &nOrderPos,
mapValue_t &mapValue) {
if (nOrderPos == -1) return;
mapValue["n"] = i64tostr(nOrderPos);
}
struct COutputEntry {
CTxDestination destination;
Amount amount;
int vout;
};
/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx {
private:
/** Constant used in hashBlock to indicate tx has been abandoned */
static const uint256 ABANDON_HASH;
public:
CTransactionRef tx;
uint256 hashBlock;
/**
* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest
* block in the chain we know this or any in-wallet dependency conflicts
* with. Older clients interpret nIndex == -1 as unconfirmed for backward
* compatibility.
*/
int nIndex;
CMerkleTx() {
SetTx(MakeTransactionRef());
Init();
}
explicit CMerkleTx(CTransactionRef arg) {
SetTx(std::move(arg));
Init();
}
void Init() {
hashBlock = uint256();
nIndex = -1;
}
void SetTx(CTransactionRef arg) { tx = std::move(arg); }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
// For compatibility with older versions.
std::vector<uint256> vMerkleBranch;
READWRITE(tx);
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
}
void SetMerkleBranch(const CBlockIndex *pIndex, int posInBlock);
/**
* Return depth of transaction in blockchain:
* <0 : conflicts with a transaction this deep in the blockchain
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
int GetDepthInMainChain(const CBlockIndex *&pindexRet) const;
int GetDepthInMainChain() const {
const CBlockIndex *pindexRet;
return GetDepthInMainChain(pindexRet);
}
bool IsInMainChain() const {
const CBlockIndex *pindexRet;
return GetDepthInMainChain(pindexRet) > 0;
}
/**
* @return number of blocks to maturity for this transaction:
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
* >0 : is a coinbase transaction which matures in this many blocks
*/
int GetBlocksToMaturity() const;
bool hashUnset() const {
return (hashBlock.IsNull() || hashBlock == ABANDON_HASH);
}
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
TxId GetId() const { return tx->GetId(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
bool IsImmatureCoinBase() const;
};
/**
* A transaction with a bunch of additional info that only the owner cares
* about. It includes any unrecorded transactions needed to link it back to the
* block chain.
*/
class CWalletTx : public CMerkleTx {
private:
const CWallet *pwallet;
public:
/**
* Key/value map with information about the transaction.
*
* The following keys can be read and written through the map and are
* serialized in the wallet database:
*
* "comment", "to" - comment strings provided to sendtoaddress,
* sendfrom, sendmany wallet RPCs
* "replaces_txid" - txid (as HexStr) of transaction replaced by
* bumpfee on transaction created by bumpfee
* "replaced_by_txid" - txid (as HexStr) of transaction created by
* bumpfee on transaction replaced by bumpfee
* "from", "message" - obsolete fields that could be set in UI prior to
* 2011 (removed in commit 4d9b223)
*
* The following keys are serialized in the wallet database, but shouldn't
* be read or written through the map (they will be temporarily added and
* removed from the map during serialization):
*
* "fromaccount" - serialized strFromAccount value
* "n" - serialized nOrderPos value
* "timesmart" - serialized nTimeSmart value
* "spent" - serialized vfSpent value that existed prior to
* 2014 (removed in commit 93a18a3)
*/
mapValue_t mapValue;
std::vector<std::pair<std::string, std::string>> vOrderForm;
unsigned int fTimeReceivedIsTxTime;
//!< time received by this node
unsigned int nTimeReceived;
/**
* Stable timestamp that never changes, and reflects the order a transaction
* was added to the wallet. Timestamp is based on the block time for a
* transaction added as part of a block, or else the time when the
* transaction was received if it wasn't part of a block, with the timestamp
* adjusted in both cases so timestamp order matches the order transactions
* were added to the wallet. More details can be found in
* CWallet::ComputeTimeSmart().
*/
unsigned int nTimeSmart;
/**
* From me flag is set to 1 for transactions that were created by the wallet
* on this bitcoin node, and set to 0 for transactions that were created
* externally and came in through the network or sendrawtransaction RPC.
*/
char fFromMe;
std::string strFromAccount;
//!< position in ordered transaction list
int64_t nOrderPos;
// memory only
mutable bool fDebitCached;
mutable bool fCreditCached;
mutable bool fImmatureCreditCached;
mutable bool fAvailableCreditCached;
mutable bool fWatchDebitCached;
mutable bool fWatchCreditCached;
mutable bool fImmatureWatchCreditCached;
mutable bool fAvailableWatchCreditCached;
mutable bool fChangeCached;
mutable bool fInMempool;
mutable Amount nDebitCached;
mutable Amount nCreditCached;
mutable Amount nImmatureCreditCached;
mutable Amount nAvailableCreditCached;
mutable Amount nWatchDebitCached;
mutable Amount nWatchCreditCached;
mutable Amount nImmatureWatchCreditCached;
mutable Amount nAvailableWatchCreditCached;
mutable Amount nChangeCached;
CWalletTx(const CWallet *pwalletIn, CTransactionRef arg)
: CMerkleTx(std::move(arg)) {
Init(pwalletIn);
}
void Init(const CWallet *pwalletIn) {
pwallet = pwalletIn;
mapValue.clear();
vOrderForm.clear();
fTimeReceivedIsTxTime = false;
nTimeReceived = 0;
nTimeSmart = 0;
fFromMe = false;
strFromAccount.clear();
fDebitCached = false;
fCreditCached = false;
fImmatureCreditCached = false;
fAvailableCreditCached = false;
fWatchDebitCached = false;
fWatchCreditCached = false;
fImmatureWatchCreditCached = false;
fAvailableWatchCreditCached = false;
fChangeCached = false;
fInMempool = false;
nDebitCached = Amount::zero();
nCreditCached = Amount::zero();
nImmatureCreditCached = Amount::zero();
nAvailableCreditCached = Amount::zero();
nWatchDebitCached = Amount::zero();
nWatchCreditCached = Amount::zero();
nAvailableWatchCreditCached = Amount::zero();
nImmatureWatchCreditCached = Amount::zero();
nChangeCached = Amount::zero();
nOrderPos = -1;
}
template <typename Stream> void Serialize(Stream &s) const {
char fSpent = false;
mapValue_t mapValueCopy = mapValue;
mapValueCopy["fromaccount"] = strFromAccount;
WriteOrderPos(nOrderPos, mapValueCopy);
if (nTimeSmart) {
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
}
s << static_cast<const CMerkleTx &>(*this);
//!< Used to be vtxPrev
std::vector<CMerkleTx> vUnused;
s << vUnused << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime
<< nTimeReceived << fFromMe << fSpent;
}
template <typename Stream> void Unserialize(Stream &s) {
Init(nullptr);
char fSpent;
s >> static_cast<CMerkleTx &>(*this);
//!< Used to be vtxPrev
std::vector<CMerkleTx> vUnused;
s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >>
nTimeReceived >> fFromMe >> fSpent;
strFromAccount = std::move(mapValue["fromaccount"]);
ReadOrderPos(nOrderPos, mapValue);
nTimeSmart = mapValue.count("timesmart")
? (unsigned int)atoi64(mapValue["timesmart"])
: 0;
mapValue.erase("fromaccount");
mapValue.erase("spent");
mapValue.erase("n");
mapValue.erase("timesmart");
}
//! make sure balances are recalculated
void MarkDirty() {
fCreditCached = false;
fAvailableCreditCached = false;
fImmatureCreditCached = false;
fWatchDebitCached = false;
fWatchCreditCached = false;
fAvailableWatchCreditCached = false;
fImmatureWatchCreditCached = false;
fDebitCached = false;
fChangeCached = false;
}
void BindWallet(CWallet *pwalletIn) {
pwallet = pwalletIn;
MarkDirty();
}
//! filter decides which addresses will count towards the debit
Amount GetDebit(const isminefilter &filter) const;
Amount GetCredit(const isminefilter &filter) const;
Amount GetImmatureCredit(bool fUseCache = true) const;
Amount GetAvailableCredit(bool fUseCache = true) const;
Amount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const;
Amount GetAvailableWatchOnlyCredit(const bool fUseCache = true) const;
Amount GetChange() const;
void GetAmounts(std::list<COutputEntry> &listReceived,
std::list<COutputEntry> &listSent, Amount &nFee,
std::string &strSentAccount,
const isminefilter &filter) const;
bool IsFromMe(const isminefilter &filter) const {
return GetDebit(filter) > Amount::zero();
}
// True if only scriptSigs are different
bool IsEquivalentTo(const CWalletTx &tx) const;
bool InMempool() const;
bool IsTrusted() const;
int64_t GetTxTime() const;
int GetRequestCount() const;
// RelayWalletTransaction may only be called if fBroadcastTransactions!
bool RelayWalletTransaction(CConnman *connman);
/**
* Pass this transaction to the mempool. Fails if absolute fee exceeds
* absurd fee.
*/
bool AcceptToMemoryPool(const Amount nAbsurdFee, CValidationState &state);
std::set<TxId> GetConflicts() const;
};
class CInputCoin {
public:
CInputCoin(const CWalletTx *walletTx, unsigned int i) : wtx(walletTx) {
if (!walletTx) {
throw std::invalid_argument("walletTx should not be null");
}
if (i >= walletTx->tx->vout.size()) {
throw std::out_of_range("The output index is out of range");
}
outpoint = COutPoint(walletTx->GetId(), i);
txout = walletTx->tx->vout[i];
}
COutPoint outpoint;
CTxOut txout;
const CWalletTx *wtx;
bool operator<(const CInputCoin &rhs) const {
return outpoint < rhs.outpoint;
}
bool operator!=(const CInputCoin &rhs) const {
return outpoint != rhs.outpoint;
}
bool operator==(const CInputCoin &rhs) const {
return outpoint == rhs.outpoint;
}
};
class COutput {
public:
const CWalletTx *tx;
int i;
int nDepth;
/** Whether we have the private keys to spend this output */
bool fSpendable;
/** Whether we know how to spend this output, ignoring the lack of keys */
bool fSolvable;
/**
* Whether this output is considered safe to spend. Unconfirmed transactions
* from outside keys are considered unsafe and will not be used to fund new
* spending transactions.
*/
bool fSafe;
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn,
bool fSolvableIn, bool fSafeIn) {
tx = txIn;
i = iIn;
nDepth = nDepthIn;
fSpendable = fSpendableIn;
fSolvable = fSolvableIn;
fSafe = fSafeIn;
}
std::string ToString() const;
};
/** Private key that includes an expiration date in case it never gets used. */
class CWalletKey {
public:
CPrivKey vchPrivKey;
int64_t nTimeCreated;
int64_t nTimeExpires;
std::string strComment;
//! todo: add something to note what created it (user, getnewaddress,
//! change) maybe should have a map<string, string> property map
explicit CWalletKey(int64_t nExpires = 0);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion);
READWRITE(vchPrivKey);
READWRITE(nTimeCreated);
READWRITE(nTimeExpires);
READWRITE(LIMITED_STRING(strComment, 65536));
}
};
/**
* Internal transfers.
* Database key is acentry<account><counter>.
*/
class CAccountingEntry {
public:
std::string strAccount;
Amount nCreditDebit;
int64_t nTime;
std::string strOtherAccount;
std::string strComment;
mapValue_t mapValue;
//!< position in ordered transaction list
int64_t nOrderPos;
uint64_t nEntryNo;
CAccountingEntry() { SetNull(); }
void SetNull() {
nCreditDebit = Amount::zero();
nTime = 0;
strAccount.clear();
strOtherAccount.clear();
strComment.clear();
nOrderPos = -1;
nEntryNo = 0;
}
template <typename Stream> void Serialize(Stream &s) const {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
s << nVersion;
}
//! Note: strAccount is serialized as part of the key, not here.
s << nCreditDebit << nTime << strOtherAccount;
mapValue_t mapValueCopy = mapValue;
WriteOrderPos(nOrderPos, mapValueCopy);
std::string strCommentCopy = strComment;
if (!mapValueCopy.empty() || !_ssExtra.empty()) {
CDataStream ss(s.GetType(), s.GetVersion());
ss.insert(ss.begin(), '\0');
ss << mapValueCopy;
ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
strCommentCopy.append(ss.str());
}
s << strCommentCopy;
}
template <typename Stream> void Unserialize(Stream &s) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
s >> nVersion;
}
//! Note: strAccount is serialized as part of the key, not here.
s >> nCreditDebit >> nTime >> LIMITED_STRING(strOtherAccount, 65536) >>
LIMITED_STRING(strComment, 65536);
size_t nSepPos = strComment.find("\0", 0, 1);
mapValue.clear();
if (std::string::npos != nSepPos) {
CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1,
strComment.end()),
s.GetType(), s.GetVersion());
ss >> mapValue;
_ssExtra = std::vector<char>(ss.begin(), ss.end());
}
ReadOrderPos(nOrderPos, mapValue);
if (std::string::npos != nSepPos) {
strComment.erase(nSepPos);
}
mapValue.erase("n");
}
private:
std::vector<char> _ssExtra;
};
// forward declarations for ScanForWalletTransactions/RescanFromTime
class WalletRescanReserver;
/**
* A CWallet is an extension of a keystore, which also maintains a set of
* transactions and balances, and provides the ability to create new
* transactions.
*/
class CWallet final : public CCryptoKeyStore, public CValidationInterface {
private:
static std::atomic<bool> fFlushScheduled;
std::atomic<bool> fAbortRescan;
// controlled by WalletRescanReserver
std::atomic<bool> fScanningWallet;
std::mutex mutexScanning;
friend class WalletRescanReserver;
/**
* Select a set of coins such that nValueRet >= nTargetValue and at least
* all coins from coinControl are selected; Never select unconfirmed coins
* if they are not ours.
*/
bool SelectCoins(const std::vector<COutput> &vAvailableCoins,
const Amount nTargetValue,
std::set<CInputCoin> &setCoinsRet, Amount &nValueRet,
const CCoinControl *coinControl = nullptr) const;
CWalletDB *pwalletdbEncryption;
//! the current wallet version: clients below this version are not able to
//! load the wallet
int nWalletVersion;
//! the maximum wallet format version: memory-only variable that specifies
//! to what version this wallet may be upgraded
int nWalletMaxVersion;
int64_t nNextResend;
int64_t nLastResend;
bool fBroadcastTransactions;
/**
* Used to keep track of spent outpoints, and detect and report conflicts
* (double-spends or mutated transactions where the mutant gets mined).
*/
typedef std::multimap<COutPoint, TxId> TxSpends;
TxSpends mapTxSpends;
void AddToSpends(const COutPoint &outpoint, const TxId &wtxid);
void AddToSpends(const TxId &wtxid);
/**
* Mark a transaction (and its in-wallet descendants) as conflicting with a
* particular block.
*/
void MarkConflicted(const uint256 &hashBlock, const TxId &txid);
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
/**
* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected.
* Should be called with pindexBlock and posInBlock if this is for a
* transaction that is included in a block.
*/
void SyncTransaction(const CTransactionRef &tx,
const CBlockIndex *pindex = nullptr,
int posInBlock = 0);
/* the HD chain data model (external chain counters) */
CHDChain hdChain;
/* HD derive new child key (on internal or external chain) */
void DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata &metadata,
CKey &secret, bool internal = false);
std::set<int64_t> setInternalKeyPool;
std::set<int64_t> setExternalKeyPool;
int64_t m_max_keypool_index;
std::map<CKeyID, int64_t> m_pool_key_to_index;
int64_t nTimeFirstKey;
/**
* Private version of AddWatchOnly method which does not accept a timestamp,
* and which will reset the wallet's nTimeFirstKey value to 1 if the watch
* key did not previously have a timestamp associated with it. Because this
* is an inherited virtual method, it is accessible despite being marked
* private, but it is marked private anyway to encourage use of the other
* AddWatchOnly which accepts a timestamp and sets nTimeFirstKey more
* intelligently for more efficient rescans.
*/
bool AddWatchOnly(const CScript &dest) override;
/**
* Wallet filename from wallet=<path> command line or config option.
* Used in debug logs and to send RPCs to the right wallet instance when
* more than one wallet is loaded.
*/
std::string m_name;
/** Internal database handle. */
std::unique_ptr<CWalletDBWrapper> dbw;
/**
* The following is used to keep track of how far behind the wallet is
* from the chain sync, and to allow clients to block on us being caught up.
*
* Note that this is *not* how far we've processed, we may need some rescan
* to have seen all transactions in the chain, but is only used to track
* live BlockConnected callbacks.
*
* Protected by cs_main (see BlockUntilSyncedToCurrentChain)
*/
const CBlockIndex *m_last_block_processed;
public:
const CChainParams &chainParams;
/*
* Main wallet lock.
* This lock protects all the fields added by CWallet.
*/
mutable CCriticalSection cs_wallet;
/**
* Get database handle used by this wallet. Ideally this function would not
* be necessary.
*/
CWalletDBWrapper &GetDBHandle() { return *dbw; }
/**
* Get a name for this wallet for logging/debugging purposes.
*/
std::string GetName() const { return m_name; }
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
// Map from Key ID to key metadata.
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
// Map from Script ID to key metadata (for watch-only keys).
std::map<CScriptID, CKeyMetadata> m_script_metadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
/** Construct wallet with specified name and database implementation. */
CWallet(const CChainParams &chainParamsIn, std::string name,
std::unique_ptr<CWalletDBWrapper> dbw_in)
: m_name(std::move(name)), dbw(std::move(dbw_in)),
chainParams(chainParamsIn) {
SetNull();
}
~CWallet() {
delete pwalletdbEncryption;
pwalletdbEncryption = nullptr;
}
void SetNull() {
nWalletVersion = FEATURE_BASE;
nWalletMaxVersion = FEATURE_BASE;
nMasterKeyMaxID = 0;
pwalletdbEncryption = nullptr;
nOrderPosNext = 0;
nAccountingEntryNumber = 0;
nNextResend = 0;
nLastResend = 0;
m_max_keypool_index = 0;
nTimeFirstKey = 0;
fBroadcastTransactions = false;
fAbortRescan = false;
fScanningWallet = false;
nRelockTime = 0;
}
std::map<TxId, CWalletTx> mapWallet;
std::list<CAccountingEntry> laccentries;
typedef std::pair<CWalletTx *, CAccountingEntry *> TxPair;
typedef std::multimap<int64_t, TxPair> TxItems;
TxItems wtxOrdered;
int64_t nOrderPosNext;
uint64_t nAccountingEntryNumber;
std::map<uint256, int> mapRequestCount;
std::map<CTxDestination, CAddressBookData> mapAddressBook;
std::set<COutPoint> setLockedCoins;
const CWalletTx *GetWalletTx(const TxId &txid) const;
//! check whether we are allowed to upgrade (or already support) to the
//! named feature
bool CanSupportFeature(enum WalletFeature wf) const {
AssertLockHeld(cs_wallet);
return nWalletMaxVersion >= wf;
}
/**
* populate vCoins with vector of available COutputs.
*/
void AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe = true,
const CCoinControl *coinControl = nullptr,
const Amount nMinimumAmount = SATOSHI,
const Amount nMaximumAmount = MAX_MONEY,
const Amount nMinimumSumAmount = MAX_MONEY,
const uint64_t nMaximumCount = 0,
const int nMinDepth = 0,
const int nMaxDepth = 9999999) const;
/**
* Return list of available coins and locked coins grouped by non-change
* output address.
*/
std::map<CTxDestination, std::vector<COutput>> ListCoins() const;
/**
* Find non-change parent output.
*/
const CTxOut &FindNonChangeParentOutput(const CTransaction &tx,
int output) const;
/**
* Shuffle and select coins until nTargetValue is reached while avoiding
* small change; This method is stochastic for some inputs and upon
* completion the coin set and corresponding actual target value is
* assembled.
*/
bool SelectCoinsMinConf(const Amount nTargetValue, int nConfMine,
int nConfTheirs, uint64_t nMaxAncestors,
std::vector<COutput> vCoins,
std::set<CInputCoin> &setCoinsRet,
Amount &nValueRet) const;
bool IsSpent(const TxId &txid, uint32_t n) const;
bool IsLockedCoin(const TxId &txid, uint32_t n) const;
void LockCoin(const COutPoint &output);
void UnlockCoin(const COutPoint &output);
void UnlockAllCoins();
void ListLockedCoins(std::vector<COutPoint> &vOutpts) const;
/*
* Rescan abort properties
*/
void AbortRescan() { fAbortRescan = true; }
bool IsAbortingRescan() { return fAbortRescan; }
bool IsScanning() { return fScanningWallet; }
/**
* keystore implementation
* Generate a new key
*/
CPubKey GenerateNewKey(CWalletDB &walletdb, bool internal = false);
//! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override;
bool AddKeyPubKeyWithDB(CWalletDB &walletdb, const CKey &key,
const CPubKey &pubkey);
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey &key, const CPubKey &pubkey) {
return CCryptoKeyStore::AddKeyPubKey(key, pubkey);
}
//! Load metadata (used by LoadWallet)
bool LoadKeyMetadata(const CKeyID &keyID, const CKeyMetadata &metadata);
bool LoadScriptMetadata(const CScriptID &script_id,
const CKeyMetadata &metadata);
bool LoadMinVersion(int nVersion) {
AssertLockHeld(cs_wallet);
nWalletVersion = nVersion;
nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion);
return true;
}
void UpdateTimeFirstKey(int64_t nCreateTime);
//! Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey,
const std::vector<uint8_t> &vchCryptedSecret) override;
//! Adds an encrypted key to the store, without saving it to disk (used by
//! LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey,
const std::vector<uint8_t> &vchCryptedSecret);
bool AddCScript(const CScript &redeemScript) override;
bool LoadCScript(const CScript &redeemScript);
//! Adds a destination data tuple to the store, and saves it to disk
bool AddDestData(const CTxDestination &dest, const std::string &key,
const std::string &value);
//! Erases a destination data tuple in the store and on disk
bool EraseDestData(const CTxDestination &dest, const std::string &key);
//! Adds a destination data tuple to the store, without saving it to disk
bool LoadDestData(const CTxDestination &dest, const std::string &key,
const std::string &value);
//! Look up a destination data tuple in the store, return true if found
//! false otherwise
bool GetDestData(const CTxDestination &dest, const std::string &key,
std::string *value) const;
//! Get all destination values matching a prefix.
std::vector<std::string> GetDestValues(const std::string &prefix) const;
//! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript &dest, int64_t nCreateTime);
bool RemoveWatchOnly(const CScript &dest) override;
//! Adds a watch-only address to the store, without saving it to disk (used
//! by LoadWallet)
bool LoadWatchOnly(const CScript &dest);
//! Holds a timestamp at which point the wallet is scheduled (externally) to
//! be relocked. Caller must arrange for actual relocking to occur via
//! Lock().
int64_t nRelockTime;
bool Unlock(const SecureString &strWalletPassphrase);
bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase,
const SecureString &strNewWalletPassphrase);
bool EncryptWallet(const SecureString &strWalletPassphrase);
void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
unsigned int ComputeTimeSmart(const CWalletTx &wtx) const;
/**
* Increment the next transaction order id
* @return next transaction order id
*/
int64_t IncOrderPosNext(CWalletDB *pwalletdb = nullptr);
DBErrors ReorderTransactions();
bool AccountMove(std::string strFrom, std::string strTo,
const Amount nAmount, std::string strComment = "");
bool GetLabelDestination(CTxDestination &dest, const std::string &label,
bool bForceNew = false);
void MarkDirty();
bool AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose = true);
bool LoadToWallet(const CWalletTx &wtxIn);
void TransactionAddedToMempool(const CTransactionRef &tx) override;
void
BlockConnected(const std::shared_ptr<const CBlock> &pblock,
const CBlockIndex *pindex,
const std::vector<CTransactionRef> &vtxConflicted) override;
void
BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) override;
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx,
const CBlockIndex *pIndex, int posInBlock,
bool fUpdate);
int64_t RescanFromTime(int64_t startTime,
const WalletRescanReserver &reserver, bool update);
CBlockIndex *ScanForWalletTransactions(CBlockIndex *pindexStart,
CBlockIndex *pindexStop,
const WalletRescanReserver &reserver,
bool fUpdate = false);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime,
CConnman *connman) override;
// ResendWalletTransactionsBefore may only be called if
// fBroadcastTransactions!
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime,
CConnman *connman);
Amount GetBalance() const;
Amount GetUnconfirmedBalance() const;
Amount GetImmatureBalance() const;
Amount GetWatchOnlyBalance() const;
Amount GetUnconfirmedWatchOnlyBalance() const;
Amount GetImmatureWatchOnlyBalance() const;
Amount GetLegacyBalance(const isminefilter &filter, int minDepth,
const std::string *account) const;
Amount GetAvailableBalance(const CCoinControl *coinControl = nullptr) const;
/**
* Insert additional inputs into the transaction by calling
* CreateTransaction();
*/
bool FundTransaction(CMutableTransaction &tx, Amount &nFeeRet,
int &nChangePosInOut, std::string &strFailReason,
bool lockUnspents,
const std::set<int> &setSubtractFeeFromOutputs,
CCoinControl coinControl, bool keepReserveKey);
bool SignTransaction(CMutableTransaction &tx);
/**
* Create a new transaction paying the recipients with a set of coins
* selected by SelectCoins(); Also create the change output, when needed
* @note passing nChangePosInOut as -1 will result in setting a random
* position
*/
bool CreateTransaction(const std::vector<CRecipient> &vecSend,
CTransactionRef &tx, CReserveKey &reservekey,
Amount &nFeeRet, int &nChangePosInOut,
std::string &strFailReason,
const CCoinControl &coinControl, bool sign = true);
bool CommitTransaction(
CTransactionRef tx, mapValue_t mapValue,
std::vector<std::pair<std::string, std::string>> orderForm,
std::string fromAccount, CReserveKey &reservekey, CConnman *connman,
CValidationState &state);
void ListAccountCreditDebit(const std::string &strAccount,
std::list<CAccountingEntry> &entries);
bool AddAccountingEntry(const CAccountingEntry &);
bool AddAccountingEntry(const CAccountingEntry &, CWalletDB *pwalletdb);
template <typename ContainerType>
bool DummySignTx(CMutableTransaction &txNew,
const ContainerType &coins) const;
static CFeeRate fallbackFee;
bool NewKeyPool();
size_t KeypoolCountExternalKeys();
bool TopUpKeyPool(unsigned int kpSize = 0);
void ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
bool fRequestedInternal);
void KeepKey(int64_t nIndex);
void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey);
bool GetKeyFromPool(CPubKey &key, bool internal = false);
int64_t GetOldestKeyPoolTime();
/**
* Marks all keys in the keypool up to and including reserve_key as used.
*/
void MarkReserveKeysAsUsed(int64_t keypool_id);
const std::map<CKeyID, int64_t> &GetAllReserveKeys() const {
return m_pool_key_to_index;
}
/** Does the wallet have at least min_keys in the keypool? */
bool HasUnusedKeys(size_t min_keys) const;
std::set<std::set<CTxDestination>> GetAddressGroupings();
std::map<CTxDestination, Amount> GetAddressBalances();
std::set<CTxDestination> GetLabelAddresses(const std::string &label) const;
isminetype IsMine(const CTxIn &txin) const;
/**
* Returns amount of debit if the input matches the filter, otherwise
* returns 0
*/
Amount GetDebit(const CTxIn &txin, const isminefilter &filter) const;
isminetype IsMine(const CTxOut &txout) const;
Amount GetCredit(const CTxOut &txout, const isminefilter &filter) const;
bool IsChange(const CTxOut &txout) const;
Amount GetChange(const CTxOut &txout) const;
bool IsMine(const CTransaction &tx) const;
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction &tx) const;
Amount GetDebit(const CTransaction &tx, const isminefilter &filter) const;
/** Returns whether all of the inputs match the filter */
bool IsAllFromMe(const CTransaction &tx, const isminefilter &filter) const;
Amount GetCredit(const CTransaction &tx, const isminefilter &filter) const;
Amount GetChange(const CTransaction &tx) const;
void ChainStateFlushed(const CBlockLocator &loc) override;
DBErrors LoadWallet(bool &fFirstRunRet);
DBErrors ZapWalletTx(std::vector<CWalletTx> &vWtx);
DBErrors ZapSelectTx(std::vector<TxId> &txIdsIn,
std::vector<TxId> &txIdsOut);
bool SetAddressBook(const CTxDestination &address,
const std::string &strName, const std::string &purpose);
bool DelAddressBook(const CTxDestination &address);
const std::string &GetLabelName(const CScript &scriptPubKey) const;
void Inventory(const uint256 &hash) override {
LOCK(cs_wallet);
std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
if (mi != mapRequestCount.end()) {
(*mi).second++;
}
}
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
unsigned int GetKeyPoolSize() {
// set{Ex,In}ternalKeyPool
AssertLockHeld(cs_wallet);
return setInternalKeyPool.size() + setExternalKeyPool.size();
}
//! signify that a particular wallet feature is now used. this may change
//! nWalletVersion and nWalletMaxVersion if those are lower
bool SetMinVersion(enum WalletFeature, CWalletDB *pwalletdbIn = nullptr,
bool fExplicit = false);
//! change which version we're allowed to upgrade to (note that this does
//! not immediately imply upgrading to that format)
bool SetMaxVersion(int nVersion);
//! get the current wallet format (the oldest client version guaranteed to
//! understand this wallet)
int GetVersion() {
LOCK(cs_wallet);
return nWalletVersion;
}
//! Get wallet transactions that conflict with given transaction (spend same
//! outputs)
std::set<TxId> GetConflicts(const TxId &txid) const;
//! Check if a given transaction has any of its outputs spent by another
//! transaction in the wallet
bool HasWalletSpend(const TxId &txid) const;
//! Flush wallet (bitdb flush)
void Flush(bool shutdown = false);
/**
* Address book entry changed.
* @note called with lock cs_wallet held.
*/
boost::signals2::signal<void(CWallet *wallet, const CTxDestination &address,
const std::string &label, bool isMine,
const std::string &purpose, ChangeType status)>
NotifyAddressBookChanged;
/**
* Wallet transaction added, removed or updated.
* @note called with lock cs_wallet held.
*/
boost::signals2::signal<void(CWallet *wallet, const TxId &txid,
ChangeType status)>
NotifyTransactionChanged;
/** Show progress e.g. for rescan */
boost::signals2::signal<void(const std::string &title, int nProgress)>
ShowProgress;
/** Watch-only address added */
boost::signals2::signal<void(bool fHaveWatchOnly)> NotifyWatchonlyChanged;
/** Inquire whether this wallet broadcasts transactions. */
bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */
void SetBroadcastTransactions(bool broadcast) {
fBroadcastTransactions = broadcast;
}
/** Return whether transaction can be abandoned */
bool TransactionCanBeAbandoned(const TxId &txid) const;
/**
* Mark a transaction (and it in-wallet descendants) as abandoned so its
* inputs may be respent.
*/
bool AbandonTransaction(const TxId &txid);
/**
* Initializes the wallet, returns a new CWallet instance or a null pointer
* in case of an error.
*/
static CWallet *CreateWalletFromFile(const CChainParams &chainParams,
const std::string &name,
const fs::path &path);
/**
* Wallet post-init setup
* Gives the wallet a chance to register repetitive tasks and complete
* post-init tasks
*/
void postInitProcess(CScheduler &scheduler);
bool BackupWallet(const std::string &strDest);
/* Set the HD chain model (chain child index counters) */
bool SetHDChain(const CHDChain &chain, bool memonly);
const CHDChain &GetHDChain() const { return hdChain; }
/* Returns true if HD is enabled */
bool IsHDEnabled() const;
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
/**
* Set the current HD master key (will reset the chain child index counters)
* Sets the master key's version based on the current wallet version (so the
* caller must ensure the current wallet version is correct before calling
* this function).
*/
bool SetHDMasterKey(const CPubKey &key);
/**
* Blocks until the wallet state is up-to-date to /at least/ the current
* chain at the time this function is entered.
* Obviously holding cs_main/cs_wallet when going into this call may cause
* deadlock
*/
void BlockUntilSyncedToCurrentChain();
/**
* Explicitly make the wallet learn the related scripts for outputs to the
* given key. This is purely to make the wallet file compatible with older
* software, as CBasicKeyStore automatically does this implicitly for all
* keys now.
*/
void LearnRelatedScripts(const CPubKey &key, OutputType);
/**
* Same as LearnRelatedScripts, but when the OutputType is not known (and
* could be anything).
*/
void LearnAllRelatedScripts(const CPubKey &key);
/**
* Get a destination of the requested type (if possible) to the specified
* script. This function will automatically add the necessary scripts to the
* wallet.
*/
CTxDestination AddAndGetDestinationForScript(const CScript &script,
OutputType);
};
/** A key allocated from the key pool. */
class CReserveKey final : public CReserveScript {
protected:
CWallet *pwallet;
int64_t nIndex;
CPubKey vchPubKey;
bool fInternal;
public:
explicit CReserveKey(CWallet *pwalletIn) {
nIndex = -1;
pwallet = pwalletIn;
fInternal = false;
}
CReserveKey() = default;
CReserveKey(const CReserveKey &) = delete;
CReserveKey &operator=(const CReserveKey &) = delete;
~CReserveKey() { ReturnKey(); }
void ReturnKey();
bool GetReservedKey(CPubKey &pubkey, bool internal = false);
void KeepKey();
void KeepScript() override { KeepKey(); }
};
/**
* Account information.
* Stored in wallet with key "acc"+string account name.
*/
class CAccount {
public:
CPubKey vchPubKey;
CAccount() { SetNull(); }
void SetNull() { vchPubKey = CPubKey(); }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(nVersion);
}
READWRITE(vchPubKey);
}
};
// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes)
// ContainerType is meant to hold pair<CWalletTx *, int>, and be iterable so
// that each entry corresponds to each vIn, in order.
template <typename ContainerType>
bool CWallet::DummySignTx(CMutableTransaction &txNew,
const ContainerType &coins) const {
// Fill in dummy signatures for fee calculation.
int nIn = 0;
for (const auto &coin : coins) {
const CScript &scriptPubKey = coin.txout.scriptPubKey;
SignatureData sigdata;
if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey,
sigdata)) {
return false;
} else {
UpdateTransaction(txNew, nIn, sigdata);
}
nIn++;
}
return true;
}
/** RAII object to check and reserve a wallet rescan */
class WalletRescanReserver {
private:
CWalletRef m_wallet;
bool m_could_reserve;
public:
explicit WalletRescanReserver(CWalletRef w)
: m_wallet(w), m_could_reserve(false) {}
bool reserve() {
assert(!m_could_reserve);
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
if (m_wallet->fScanningWallet) {
return false;
}
m_wallet->fScanningWallet = true;
m_could_reserve = true;
return true;
}
bool isReserved() const {
return (m_could_reserve && m_wallet->fScanningWallet);
}
~WalletRescanReserver() {
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
if (m_could_reserve) {
m_wallet->fScanningWallet = false;
}
}
};
OutputType ParseOutputType(const std::string &str,
OutputType default_type = OutputType::DEFAULT);
const std::string &FormatOutputType(OutputType type);
/**
* Get a destination of the requested type (if possible) to the specified key.
* The caller must make sure LearnRelatedScripts has been called beforehand.
*/
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType);
/**
* Get all destinations (potentially) supported by the wallet for the given key.
*/
std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey &key);
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/test/functional/rpc_named_arguments.py b/test/functional/rpc_named_arguments.py
index 5bc4527f56..502733a92b 100755
--- a/test/functional/rpc_named_arguments.py
+++ b/test/functional/rpc_named_arguments.py
@@ -1,34 +1,34 @@
#!/usr/bin/env python3
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
class NamedArgumentTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
def run_test(self):
node = self.nodes[0]
- h = node.help(command='getinfo')
- assert(h.startswith('getinfo\n'))
+ h = node.help(command='getblockchaininfo')
+ assert(h.startswith('getblockchaininfo\n'))
assert_raises_rpc_error(-8, 'Unknown named parameter',
- node.help, random='getinfo')
+ node.help, random='getblockchaininfo')
h = node.getblockhash(height=0)
node.getblock(blockhash=h)
assert_equal(node.echo(), [])
assert_equal(node.echo(arg0=0, arg9=9), [0] + [None] * 8 + [9])
assert_equal(node.echo(arg1=1), [None, 1])
assert_equal(node.echo(arg9=None), [None] * 10)
assert_equal(node.echo(arg0=0, arg3=3, arg9=9),
[0] + [None] * 2 + [3] + [None] * 5 + [9])
if __name__ == '__main__':
NamedArgumentTest().main()

File Metadata

Mime Type
text/x-diff
Expires
Thu, Apr 17, 03:21 (13 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5504670
Default Alt Text
(81 KB)

Event Timeline