1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
8 #include "clientversion.h"
10 #include "crypto/ripemd160.h"
12 #include "validation.h"
13 #include "httpserver.h"
16 #include "rpc/blockchain.h"
17 #include "rpc/server.h"
20 #include "utilstrencodings.h"
22 #include "wallet/rpcwallet.h"
23 #include "wallet/wallet.h"
24 #include "wallet/walletdb.h"
29 #ifdef HAVE_MALLOC_INFO
36 class DescribeAddressVisitor
: public boost::static_visitor
<UniValue
>
39 CWallet
* const pwallet
;
41 explicit DescribeAddressVisitor(CWallet
*_pwallet
) : pwallet(_pwallet
) {}
43 UniValue
operator()(const CNoDestination
&dest
) const { return UniValue(UniValue::VOBJ
); }
45 UniValue
operator()(const CKeyID
&keyID
) const {
46 UniValue
obj(UniValue::VOBJ
);
48 obj
.push_back(Pair("isscript", false));
49 obj
.push_back(Pair("iswitness", false));
50 if (pwallet
&& pwallet
->GetPubKey(keyID
, vchPubKey
)) {
51 obj
.push_back(Pair("pubkey", HexStr(vchPubKey
)));
52 obj
.push_back(Pair("iscompressed", vchPubKey
.IsCompressed()));
57 UniValue
operator()(const CScriptID
&scriptID
) const {
58 UniValue
obj(UniValue::VOBJ
);
60 obj
.push_back(Pair("isscript", true));
61 obj
.push_back(Pair("iswitness", false));
62 if (pwallet
&& pwallet
->GetCScript(scriptID
, subscript
)) {
63 std::vector
<CTxDestination
> addresses
;
66 ExtractDestinations(subscript
, whichType
, addresses
, nRequired
);
67 obj
.push_back(Pair("script", GetTxnOutputType(whichType
)));
68 obj
.push_back(Pair("hex", HexStr(subscript
.begin(), subscript
.end())));
69 UniValue
a(UniValue::VARR
);
70 for (const CTxDestination
& addr
: addresses
) {
71 a
.push_back(EncodeDestination(addr
));
73 obj
.push_back(Pair("addresses", a
));
74 if (whichType
== TX_MULTISIG
)
75 obj
.push_back(Pair("sigsrequired", nRequired
));
80 UniValue
operator()(const WitnessV0KeyHash
& id
) const
82 UniValue
obj(UniValue::VOBJ
);
84 obj
.push_back(Pair("isscript", false));
85 obj
.push_back(Pair("iswitness", true));
86 obj
.push_back(Pair("witness_version", 0));
87 obj
.push_back(Pair("witness_program", HexStr(id
.begin(), id
.end())));
88 if (pwallet
&& pwallet
->GetPubKey(CKeyID(id
), pubkey
)) {
89 obj
.push_back(Pair("pubkey", HexStr(pubkey
)));
94 UniValue
operator()(const WitnessV0ScriptHash
& id
) const
96 UniValue
obj(UniValue::VOBJ
);
98 obj
.push_back(Pair("isscript", true));
99 obj
.push_back(Pair("iswitness", true));
100 obj
.push_back(Pair("witness_version", 0));
101 obj
.push_back(Pair("witness_program", HexStr(id
.begin(), id
.end())));
104 hasher
.Write(id
.begin(), 32).Finalize(hash
.begin());
105 if (pwallet
&& pwallet
->GetCScript(CScriptID(hash
), subscript
)) {
106 obj
.push_back(Pair("hex", HexStr(subscript
.begin(), subscript
.end())));
111 UniValue
operator()(const WitnessUnknown
& id
) const
113 UniValue
obj(UniValue::VOBJ
);
115 obj
.push_back(Pair("iswitness", true));
116 obj
.push_back(Pair("witness_version", (int)id
.version
));
117 obj
.push_back(Pair("witness_program", HexStr(id
.program
, id
.program
+ id
.length
)));
123 UniValue
validateaddress(const JSONRPCRequest
& request
)
125 if (request
.fHelp
|| request
.params
.size() != 1)
126 throw std::runtime_error(
127 "validateaddress \"address\"\n"
128 "\nReturn information about the given bitcoin address.\n"
130 "1. \"address\" (string, required) The bitcoin address to validate\n"
133 " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
134 " \"address\" : \"address\", (string) The bitcoin address validated\n"
135 " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
136 " \"ismine\" : true|false, (boolean) If the address is yours or not\n"
137 " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
138 " \"isscript\" : true|false, (boolean) If the key is a script\n"
139 " \"script\" : \"type\" (string, optional) The output script type. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash\n"
140 " \"hex\" : \"hex\", (string, optional) The redeemscript for the p2sh address\n"
141 " \"addresses\" (string, optional) Array of addresses associated with the known redeemscript\n"
146 " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output\n"
147 " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
148 " \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
149 " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
150 " \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
151 " \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
152 " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n"
155 + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
156 + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
160 CWallet
* const pwallet
= GetWalletForJSONRPCRequest(request
);
162 LOCK2(cs_main
, pwallet
? &pwallet
->cs_wallet
: nullptr);
167 CTxDestination dest
= DecodeDestination(request
.params
[0].get_str());
168 bool isValid
= IsValidDestination(dest
);
170 UniValue
ret(UniValue::VOBJ
);
171 ret
.push_back(Pair("isvalid", isValid
));
174 std::string currentAddress
= EncodeDestination(dest
);
175 ret
.push_back(Pair("address", currentAddress
));
177 CScript scriptPubKey
= GetScriptForDestination(dest
);
178 ret
.push_back(Pair("scriptPubKey", HexStr(scriptPubKey
.begin(), scriptPubKey
.end())));
181 isminetype mine
= pwallet
? IsMine(*pwallet
, dest
) : ISMINE_NO
;
182 ret
.push_back(Pair("ismine", bool(mine
& ISMINE_SPENDABLE
)));
183 ret
.push_back(Pair("iswatchonly", bool(mine
& ISMINE_WATCH_ONLY
)));
184 UniValue detail
= boost::apply_visitor(DescribeAddressVisitor(pwallet
), dest
);
186 if (pwallet
&& pwallet
->mapAddressBook
.count(dest
)) {
187 ret
.push_back(Pair("account", pwallet
->mapAddressBook
[dest
].name
));
190 const auto& meta
= pwallet
->mapKeyMetadata
;
191 const CKeyID
*keyID
= boost::get
<CKeyID
>(&dest
);
192 auto it
= keyID
? meta
.find(*keyID
) : meta
.end();
193 if (it
== meta
.end()) {
194 it
= meta
.find(CScriptID(scriptPubKey
));
196 if (it
!= meta
.end()) {
197 ret
.push_back(Pair("timestamp", it
->second
.nCreateTime
));
198 if (!it
->second
.hdKeypath
.empty()) {
199 ret
.push_back(Pair("hdkeypath", it
->second
.hdKeypath
));
200 ret
.push_back(Pair("hdmasterkeyid", it
->second
.hdMasterKeyID
.GetHex()));
209 // Needed even with !ENABLE_WALLET, to pass (ignored) pointers around
213 * Used by addmultisigaddress / createmultisig:
215 CScript
_createmultisig_redeemScript(CWallet
* const pwallet
, const UniValue
& params
)
217 int nRequired
= params
[0].get_int();
218 const UniValue
& keys
= params
[1].get_array();
220 // Gather public keys
222 throw std::runtime_error("a multisignature address must require at least one key to redeem");
223 if ((int)keys
.size() < nRequired
)
224 throw std::runtime_error(
225 strprintf("not enough keys supplied "
226 "(got %u keys, but need at least %d to redeem)", keys
.size(), nRequired
));
227 if (keys
.size() > 16)
228 throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
229 std::vector
<CPubKey
> pubkeys
;
230 pubkeys
.resize(keys
.size());
231 for (unsigned int i
= 0; i
< keys
.size(); i
++)
233 const std::string
& ks
= keys
[i
].get_str();
235 // Case 1: Bitcoin address and we have full public key:
236 CTxDestination dest
= DecodeDestination(ks
);
237 if (pwallet
&& IsValidDestination(dest
)) {
238 const CKeyID
*keyID
= boost::get
<CKeyID
>(&dest
);
240 throw std::runtime_error(strprintf("%s does not refer to a key", ks
));
243 if (!pwallet
->GetPubKey(*keyID
, vchPubKey
)) {
244 throw std::runtime_error(strprintf("no full public key for address %s", ks
));
246 if (!vchPubKey
.IsFullyValid())
247 throw std::runtime_error(" Invalid public key: "+ks
);
248 pubkeys
[i
] = vchPubKey
;
251 // Case 2: hex public key
256 CPubKey
vchPubKey(ParseHex(ks
));
257 if (!vchPubKey
.IsFullyValid())
258 throw std::runtime_error(" Invalid public key: "+ks
);
259 pubkeys
[i
] = vchPubKey
;
263 throw std::runtime_error(" Invalid public key: "+ks
);
266 CScript result
= GetScriptForMultisig(nRequired
, pubkeys
);
268 if (result
.size() > MAX_SCRIPT_ELEMENT_SIZE
)
269 throw std::runtime_error(
270 strprintf("redeemScript exceeds size limit: %d > %d", result
.size(), MAX_SCRIPT_ELEMENT_SIZE
));
275 UniValue
createmultisig(const JSONRPCRequest
& request
)
278 CWallet
* const pwallet
= GetWalletForJSONRPCRequest(request
);
280 CWallet
* const pwallet
= nullptr;
283 if (request
.fHelp
|| request
.params
.size() < 2 || request
.params
.size() > 2)
285 std::string msg
= "createmultisig nrequired [\"key\",...]\n"
286 "\nCreates a multi-signature address with n signature of m keys required.\n"
287 "It returns a json object with the address and redeemScript.\n"
290 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
291 "2. \"keys\" (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n"
293 " \"key\" (string) bitcoin address or hex-encoded public key\n"
299 " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
300 " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
304 "\nCreate a multisig address from 2 addresses\n"
305 + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
306 "\nAs a json rpc call\n"
307 + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
309 throw std::runtime_error(msg
);
312 // Construct using pay-to-script-hash:
313 CScript inner
= _createmultisig_redeemScript(pwallet
, request
.params
);
314 CScriptID
innerID(inner
);
316 UniValue
result(UniValue::VOBJ
);
317 result
.push_back(Pair("address", EncodeDestination(innerID
)));
318 result
.push_back(Pair("redeemScript", HexStr(inner
.begin(), inner
.end())));
323 UniValue
verifymessage(const JSONRPCRequest
& request
)
325 if (request
.fHelp
|| request
.params
.size() != 3)
326 throw std::runtime_error(
327 "verifymessage \"address\" \"signature\" \"message\"\n"
328 "\nVerify a signed message\n"
330 "1. \"address\" (string, required) The bitcoin address to use for the signature.\n"
331 "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
332 "3. \"message\" (string, required) The message that was signed.\n"
334 "true|false (boolean) If the signature is verified or not.\n"
336 "\nUnlock the wallet for 30 seconds\n"
337 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
338 "\nCreate the signature\n"
339 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
340 "\nVerify the signature\n"
341 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
343 + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
348 std::string strAddress
= request
.params
[0].get_str();
349 std::string strSign
= request
.params
[1].get_str();
350 std::string strMessage
= request
.params
[2].get_str();
352 CTxDestination destination
= DecodeDestination(strAddress
);
353 if (!IsValidDestination(destination
)) {
354 throw JSONRPCError(RPC_TYPE_ERROR
, "Invalid address");
357 const CKeyID
*keyID
= boost::get
<CKeyID
>(&destination
);
359 throw JSONRPCError(RPC_TYPE_ERROR
, "Address does not refer to key");
362 bool fInvalid
= false;
363 std::vector
<unsigned char> vchSig
= DecodeBase64(strSign
.c_str(), &fInvalid
);
366 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY
, "Malformed base64 encoding");
368 CHashWriter
ss(SER_GETHASH
, 0);
369 ss
<< strMessageMagic
;
373 if (!pubkey
.RecoverCompact(ss
.GetHash(), vchSig
))
376 return (pubkey
.GetID() == *keyID
);
379 UniValue
signmessagewithprivkey(const JSONRPCRequest
& request
)
381 if (request
.fHelp
|| request
.params
.size() != 2)
382 throw std::runtime_error(
383 "signmessagewithprivkey \"privkey\" \"message\"\n"
384 "\nSign a message with the private key of an address\n"
386 "1. \"privkey\" (string, required) The private key to sign the message with.\n"
387 "2. \"message\" (string, required) The message to create a signature of.\n"
389 "\"signature\" (string) The signature of the message encoded in base 64\n"
391 "\nCreate the signature\n"
392 + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
393 "\nVerify the signature\n"
394 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
396 + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
399 std::string strPrivkey
= request
.params
[0].get_str();
400 std::string strMessage
= request
.params
[1].get_str();
402 CBitcoinSecret vchSecret
;
403 bool fGood
= vchSecret
.SetString(strPrivkey
);
405 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY
, "Invalid private key");
406 CKey key
= vchSecret
.GetKey();
408 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY
, "Private key outside allowed range");
410 CHashWriter
ss(SER_GETHASH
, 0);
411 ss
<< strMessageMagic
;
414 std::vector
<unsigned char> vchSig
;
415 if (!key
.SignCompact(ss
.GetHash(), vchSig
))
416 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY
, "Sign failed");
418 return EncodeBase64(vchSig
.data(), vchSig
.size());
421 UniValue
setmocktime(const JSONRPCRequest
& request
)
423 if (request
.fHelp
|| request
.params
.size() != 1)
424 throw std::runtime_error(
425 "setmocktime timestamp\n"
426 "\nSet the local time to given timestamp (-regtest only)\n"
428 "1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n"
429 " Pass 0 to go back to using the system time."
432 if (!Params().MineBlocksOnDemand())
433 throw std::runtime_error("setmocktime for regression testing (-regtest mode) only");
435 // For now, don't change mocktime if we're in the middle of validation, as
436 // this could have an effect on mempool time-based eviction, as well as
437 // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
438 // TODO: figure out the right way to synchronize around mocktime, and
439 // ensure all call sites of GetTime() are accessing this safely.
442 RPCTypeCheck(request
.params
, {UniValue::VNUM
});
443 SetMockTime(request
.params
[0].get_int64());
448 static UniValue
RPCLockedMemoryInfo()
450 LockedPool::Stats stats
= LockedPoolManager::Instance().stats();
451 UniValue
obj(UniValue::VOBJ
);
452 obj
.push_back(Pair("used", uint64_t(stats
.used
)));
453 obj
.push_back(Pair("free", uint64_t(stats
.free
)));
454 obj
.push_back(Pair("total", uint64_t(stats
.total
)));
455 obj
.push_back(Pair("locked", uint64_t(stats
.locked
)));
456 obj
.push_back(Pair("chunks_used", uint64_t(stats
.chunks_used
)));
457 obj
.push_back(Pair("chunks_free", uint64_t(stats
.chunks_free
)));
461 #ifdef HAVE_MALLOC_INFO
462 static std::string
RPCMallocInfo()
466 FILE *f
= open_memstream(&ptr
, &size
);
471 std::string
rv(ptr
, size
);
480 UniValue
getmemoryinfo(const JSONRPCRequest
& request
)
482 /* Please, avoid using the word "pool" here in the RPC interface or help,
483 * as users will undoubtedly confuse it with the other "memory pool"
485 if (request
.fHelp
|| request
.params
.size() > 1)
486 throw std::runtime_error(
487 "getmemoryinfo (\"mode\")\n"
488 "Returns an object containing information about memory usage.\n"
490 "1. \"mode\" determines what kind of information is returned. This argument is optional, the default mode is \"stats\".\n"
491 " - \"stats\" returns general statistics about memory usage in the daemon.\n"
492 " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+).\n"
493 "\nResult (mode \"stats\"):\n"
495 " \"locked\": { (json object) Information about locked memory manager\n"
496 " \"used\": xxxxx, (numeric) Number of bytes used\n"
497 " \"free\": xxxxx, (numeric) Number of bytes available in current arenas\n"
498 " \"total\": xxxxxxx, (numeric) Total number of bytes managed\n"
499 " \"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"
500 " \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n"
501 " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
504 "\nResult (mode \"mallocinfo\"):\n"
505 "\"<malloc version=\"1\">...\"\n"
507 + HelpExampleCli("getmemoryinfo", "")
508 + HelpExampleRpc("getmemoryinfo", "")
511 std::string mode
= request
.params
[0].isNull() ? "stats" : request
.params
[0].get_str();
512 if (mode
== "stats") {
513 UniValue
obj(UniValue::VOBJ
);
514 obj
.push_back(Pair("locked", RPCLockedMemoryInfo()));
516 } else if (mode
== "mallocinfo") {
517 #ifdef HAVE_MALLOC_INFO
518 return RPCMallocInfo();
520 throw JSONRPCError(RPC_INVALID_PARAMETER
, "mallocinfo is only available when compiled with glibc 2.10+");
523 throw JSONRPCError(RPC_INVALID_PARAMETER
, "unknown mode " + mode
);
527 uint32_t getCategoryMask(UniValue cats
) {
528 cats
= cats
.get_array();
530 for (unsigned int i
= 0; i
< cats
.size(); ++i
) {
532 std::string cat
= cats
[i
].get_str();
533 if (!GetLogCategory(&flag
, &cat
)) {
534 throw JSONRPCError(RPC_INVALID_PARAMETER
, "unknown logging category " + cat
);
541 UniValue
logging(const JSONRPCRequest
& request
)
543 if (request
.fHelp
|| request
.params
.size() > 2) {
544 throw std::runtime_error(
545 "logging [include,...] <exclude>\n"
546 "Gets and sets the logging configuration.\n"
547 "When called without an argument, returns the list of categories that are currently being debug logged.\n"
548 "When called with arguments, adds or removes categories from debug logging.\n"
549 "The valid logging categories are: " + ListLogCategories() + "\n"
550 "libevent logging is configured on startup and cannot be modified by this RPC during runtime."
552 "1. \"include\" (array of strings) add debug logging for these categories.\n"
553 "2. \"exclude\" (array of strings) remove debug logging for these categories.\n"
554 "\nResult: <categories> (string): a list of the logging categories that are active.\n"
556 + HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
557 + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
561 uint32_t originalLogCategories
= logCategories
;
562 if (request
.params
[0].isArray()) {
563 logCategories
|= getCategoryMask(request
.params
[0]);
566 if (request
.params
[1].isArray()) {
567 logCategories
&= ~getCategoryMask(request
.params
[1]);
570 // Update libevent logging if BCLog::LIBEVENT has changed.
571 // If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,
572 // in which case we should clear the BCLog::LIBEVENT flag.
573 // Throw an error if the user has explicitly asked to change only the libevent
574 // flag and it failed.
575 uint32_t changedLogCategories
= originalLogCategories
^ logCategories
;
576 if (changedLogCategories
& BCLog::LIBEVENT
) {
577 if (!UpdateHTTPServerLogging(logCategories
& BCLog::LIBEVENT
)) {
578 logCategories
&= ~BCLog::LIBEVENT
;
579 if (changedLogCategories
== BCLog::LIBEVENT
) {
580 throw JSONRPCError(RPC_INVALID_PARAMETER
, "libevent logging cannot be updated when using libevent before v2.1.1.");
585 UniValue
result(UniValue::VOBJ
);
586 std::vector
<CLogCategoryActive
> vLogCatActive
= ListActiveLogCategories();
587 for (const auto& logCatActive
: vLogCatActive
) {
588 result
.pushKV(logCatActive
.category
, logCatActive
.active
);
594 UniValue
echo(const JSONRPCRequest
& request
)
597 throw std::runtime_error(
598 "echo|echojson \"message\" ...\n"
599 "\nSimply echo back the input arguments. This command is for testing.\n"
600 "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in"
601 "bitcoin-cli and the GUI. There is no server-side difference."
604 return request
.params
;
607 static const CRPCCommand commands
[] =
608 { // category name actor (function) argNames
609 // --------------------- ------------------------ ----------------------- ----------
610 { "control", "getmemoryinfo", &getmemoryinfo
, {"mode"} },
611 { "control", "logging", &logging
, {"include", "exclude"}},
612 { "util", "validateaddress", &validateaddress
, {"address"} }, /* uses wallet if enabled */
613 { "util", "createmultisig", &createmultisig
, {"nrequired","keys"} },
614 { "util", "verifymessage", &verifymessage
, {"address","signature","message"} },
615 { "util", "signmessagewithprivkey", &signmessagewithprivkey
, {"privkey","message"} },
617 /* Not shown in help */
618 { "hidden", "setmocktime", &setmocktime
, {"timestamp"}},
619 { "hidden", "echo", &echo
, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
620 { "hidden", "echojson", &echo
, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
623 void RegisterMiscRPCCommands(CRPCTable
&t
)
625 for (unsigned int vcidx
= 0; vcidx
< ARRAYLEN(commands
); vcidx
++)
626 t
.appendCommand(commands
[vcidx
].name
, &commands
[vcidx
]);