aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/misc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/misc.cpp')
-rw-r--r--src/rpc/misc.cpp201
1 files changed, 119 insertions, 82 deletions
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index f7c4ecc20c..2a8f95b615 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -14,6 +14,7 @@
#include "util.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
+#include "wallet/rpcwallet.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#endif
@@ -24,8 +25,6 @@
#include <univalue.h>
-using namespace std;
-
/**
* @note Do not add or change anything in the information returned by this
* method. `getinfo` exists for backwards-compatibility only. It combines
@@ -42,7 +41,7 @@ using namespace std;
UniValue getinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getinfo\n"
"\nDEPRECATED. Returns an object containing various state info.\n"
"\nResult:\n"
@@ -61,7 +60,7 @@ UniValue getinfo(const JSONRPCRequest& request)
" \"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"
+ " \"relayfee\": x.xxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n"
@@ -70,7 +69,9 @@ UniValue getinfo(const JSONRPCRequest& request)
);
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
@@ -82,25 +83,26 @@ UniValue getinfo(const JSONRPCRequest& request)
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
- if (pwalletMain) {
- obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
- obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
+ if (pwallet) {
+ obj.push_back(Pair("walletversion", pwallet->GetVersion()));
+ obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
}
#endif
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
if(g_connman)
obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
- obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
+ obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET
- if (pwalletMain) {
- obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
- obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
+ if (pwallet) {
+ obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize()));
+ }
+ if (pwallet && pwallet->IsCrypted()) {
+ obj.push_back(Pair("unlocked_until", pwallet->nRelockTime));
}
- if (pwalletMain && pwalletMain->IsCrypted())
- obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
#endif
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
@@ -112,13 +114,17 @@ UniValue getinfo(const JSONRPCRequest& request)
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
+ CWallet * const pwallet;
+
+ DescribeAddressVisitor(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;
obj.push_back(Pair("isscript", false));
- if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) {
+ if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
@@ -129,7 +135,7 @@ public:
UniValue obj(UniValue::VOBJ);
CScript subscript;
obj.push_back(Pair("isscript", true));
- if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) {
+ if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
@@ -151,15 +157,15 @@ public:
UniValue validateaddress(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
- "validateaddress \"bitcoinaddress\"\n"
+ throw std::runtime_error(
+ "validateaddress \"address\"\n"
"\nReturn information about the given bitcoin address.\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (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\" : \"bitcoinaddress\", (string) The bitcoin address validated\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"
@@ -167,6 +173,7 @@ UniValue validateaddress(const JSONRPCRequest& request)
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\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"
@@ -176,7 +183,9 @@ UniValue validateaddress(const JSONRPCRequest& request)
);
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
@@ -189,48 +198,61 @@ UniValue validateaddress(const JSONRPCRequest& request)
if (isValid)
{
CTxDestination dest = address.Get();
- string currentAddress = address.ToString();
+ std::string currentAddress = address.ToString();
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 = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
+ isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO;
ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
- UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
+ UniValue detail = boost::apply_visitor(DescribeAddressVisitor(pwallet), dest);
ret.pushKVs(detail);
- if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
- ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
+ if (pwallet && pwallet->mapAddressBook.count(dest)) {
+ ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name));
+ }
CKeyID keyID;
- if (pwalletMain && address.GetKeyID(keyID) && pwalletMain->mapKeyMetadata.count(keyID) && !pwalletMain->mapKeyMetadata[keyID].hdKeypath.empty())
- {
- ret.push_back(Pair("hdkeypath", pwalletMain->mapKeyMetadata[keyID].hdKeypath));
- ret.push_back(Pair("hdmasterkeyid", pwalletMain->mapKeyMetadata[keyID].hdMasterKeyID.GetHex()));
+ if (pwallet) {
+ const auto& meta = pwallet->mapKeyMetadata;
+ auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end();
+ if (it == meta.end()) {
+ it = meta.find(CScriptID(scriptPubKey));
+ }
+ if (it != meta.end()) {
+ ret.push_back(Pair("timestamp", it->second.nCreateTime));
+ if (!it->second.hdKeypath.empty()) {
+ ret.push_back(Pair("hdkeypath", it->second.hdKeypath));
+ ret.push_back(Pair("hdmasterkeyid", it->second.hdMasterKeyID.GetHex()));
+ }
+ }
}
#endif
}
return ret;
}
+// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around
+class CWallet;
+
/**
* Used by addmultisigaddress / createmultisig:
*/
-CScript _createmultisig_redeemScript(const UniValue& params)
+CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& params)
{
int nRequired = params[0].get_int();
const UniValue& keys = params[1].get_array();
// Gather public keys
if (nRequired < 1)
- throw runtime_error("a multisignature address must require at least one key to redeem");
+ throw std::runtime_error("a multisignature address must require at least one key to redeem");
if ((int)keys.size() < nRequired)
- throw runtime_error(
+ throw std::runtime_error(
strprintf("not enough keys supplied "
"(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
if (keys.size() > 16)
- throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
+ throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
std::vector<CPubKey> pubkeys;
pubkeys.resize(keys.size());
for (unsigned int i = 0; i < keys.size(); i++)
@@ -239,18 +261,18 @@ CScript _createmultisig_redeemScript(const UniValue& params)
#ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key:
CBitcoinAddress address(ks);
- if (pwalletMain && address.IsValid())
- {
+ if (pwallet && address.IsValid()) {
CKeyID keyID;
if (!address.GetKeyID(keyID))
- throw runtime_error(
+ throw std::runtime_error(
strprintf("%s does not refer to a key",ks));
CPubKey vchPubKey;
- if (!pwalletMain->GetPubKey(keyID, vchPubKey))
- throw runtime_error(
+ if (!pwallet->GetPubKey(keyID, vchPubKey)) {
+ throw std::runtime_error(
strprintf("no full public key for address %s",ks));
+ }
if (!vchPubKey.IsFullyValid())
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
}
@@ -261,18 +283,18 @@ CScript _createmultisig_redeemScript(const UniValue& params)
{
CPubKey vchPubKey(ParseHex(ks));
if (!vchPubKey.IsFullyValid())
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
}
else
{
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
}
}
CScript result = GetScriptForMultisig(nRequired, pubkeys);
if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
- throw runtime_error(
+ throw std::runtime_error(
strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
return result;
@@ -280,9 +302,15 @@ CScript _createmultisig_redeemScript(const UniValue& params)
UniValue createmultisig(const JSONRPCRequest& request)
{
+#ifdef ENABLE_WALLET
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+#else
+ CWallet * const pwallet = NULL;
+#endif
+
if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
{
- string msg = "createmultisig nrequired [\"key\",...]\n"
+ 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"
@@ -306,11 +334,11 @@ UniValue createmultisig(const JSONRPCRequest& request)
"\nAs a json rpc call\n"
+ HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
// Construct using pay-to-script-hash:
- CScript inner = _createmultisig_redeemScript(request.params);
+ CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
@@ -324,11 +352,11 @@ UniValue createmultisig(const JSONRPCRequest& request)
UniValue verifymessage(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 3)
- throw runtime_error(
- "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
+ throw std::runtime_error(
+ "verifymessage \"address\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
- "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\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"
@@ -337,18 +365,18 @@ UniValue verifymessage(const JSONRPCRequest& request)
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
- + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
+ + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n"
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs json rpc\n"
- + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
+ + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
);
LOCK(cs_main);
- string strAddress = request.params[0].get_str();
- string strSign = request.params[1].get_str();
- string strMessage = request.params[2].get_str();
+ std::string strAddress = request.params[0].get_str();
+ std::string strSign = request.params[1].get_str();
+ std::string strMessage = request.params[2].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
@@ -359,7 +387,7 @@ UniValue verifymessage(const JSONRPCRequest& request)
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
bool fInvalid = false;
- vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
+ std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
if (fInvalid)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
@@ -378,7 +406,7 @@ UniValue verifymessage(const JSONRPCRequest& request)
UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2)
- throw runtime_error(
+ throw std::runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
"\nArguments:\n"
@@ -390,13 +418,13 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
"\nCreate the signature\n"
+ HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
"\nVerify the signature\n"
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs json rpc\n"
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
);
- string strPrivkey = request.params[0].get_str();
- string strMessage = request.params[1].get_str();
+ std::string strPrivkey = request.params[0].get_str();
+ std::string strMessage = request.params[1].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strPrivkey);
@@ -410,7 +438,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
ss << strMessageMagic;
ss << strMessage;
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
if (!key.SignCompact(ss.GetHash(), vchSig))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
@@ -420,7 +448,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
UniValue setmocktime(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nArguments:\n"
@@ -429,24 +457,18 @@ UniValue setmocktime(const JSONRPCRequest& request)
);
if (!Params().MineBlocksOnDemand())
- throw runtime_error("setmocktime for regression testing (-regtest mode) only");
+ throw std::runtime_error("setmocktime for regression testing (-regtest mode) only");
- // cs_vNodes is locked and node send/receive times are updated
- // atomically with the time change to prevent peers from being
- // disconnected because we think we haven't communicated with them
- // in a long time.
+ // 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
+ // IsCurrentForFeeEstimation() and 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, boost::assign::list_of(UniValue::VNUM));
SetMockTime(request.params[0].get_int64());
- uint64_t t = GetTime();
- if(g_connman) {
- g_connman->ForEachNode([t](CNode* pnode) {
- pnode->nLastSend = pnode->nLastRecv = t;
- });
- }
-
return NullUniValue;
}
@@ -469,7 +491,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
* as users will undoubtedly confuse it with the other "memory pool"
*/
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getmemoryinfo\n"
"Returns an object containing information about memory usage.\n"
"\nResult:\n"
@@ -492,18 +514,33 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
return obj;
}
+UniValue echo(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;
+}
+
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
- { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */
- { "control", "getmemoryinfo", &getmemoryinfo, true },
- { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
- { "util", "createmultisig", &createmultisig, true },
- { "util", "verifymessage", &verifymessage, true },
- { "util", "signmessagewithprivkey", &signmessagewithprivkey, true },
+ { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
+ { "control", "getmemoryinfo", &getmemoryinfo, true, {} },
+ { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */
+ { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} },
+ { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, true },
+ { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
+ { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
};
void RegisterMiscRPCCommands(CRPCTable &t)