aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/rpcwallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r--src/wallet/rpcwallet.cpp483
1 files changed, 313 insertions, 170 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index ee8c7548fc..e3639e4682 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -8,7 +8,7 @@
#include "chain.h"
#include "consensus/validation.h"
#include "core_io.h"
-#include "init.h"
+#include "httpserver.h"
#include "validation.h"
#include "net.h"
#include "policy/feerate.h"
@@ -16,6 +16,7 @@
#include "policy/policy.h"
#include "policy/rbf.h"
#include "rpc/mining.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
#include "script/sign.h"
#include "timedata.h"
@@ -26,14 +27,27 @@
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
+#include <init.h> // For StartShutdown
+
#include <stdint.h>
#include <univalue.h>
+static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
+
CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
- // TODO: Some way to access secondary wallets
- return vpwallets.empty() ? nullptr : vpwallets[0];
+ if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
+ // wallet endpoint was used
+ std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
+ for (CWalletRef pwallet : ::vpwallets) {
+ if (pwallet->GetName() == requestedWallet) {
+ return pwallet;
+ }
+ }
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ }
+ return ::vpwallets.size() == 1 || (request.fHelp && ::vpwallets.size() > 0) ? ::vpwallets[0] : nullptr;
}
std::string HelpRequiringPassphrase(CWallet * const pwallet)
@@ -45,13 +59,19 @@ std::string HelpRequiringPassphrase(CWallet * const pwallet)
bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
{
- if (!pwallet) {
- if (!avoidException)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
- else
- return false;
- }
- return true;
+ if (pwallet) return true;
+ if (avoidException) return false;
+ if (::vpwallets.empty()) {
+ // Note: It isn't currently possible to trigger this error because
+ // wallet RPC methods aren't registered unless a wallet is loaded. But
+ // this error is being kept as a precaution, because it's possible in
+ // the future that wallet RPC methods might get or remain registered
+ // when no wallets are loaded.
+ throw JSONRPCError(
+ RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)");
+ }
+ throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
+ "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
void EnsureWalletIsUnlocked(CWallet * const pwallet)
@@ -134,7 +154,7 @@ UniValue getnewaddress(const JSONRPCRequest& request)
// Parse the account first so we don't generate a key if there's an error
std::string strAccount;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
strAccount = AccountFromValue(request.params[0]);
if (!pwallet->IsLocked()) {
@@ -205,7 +225,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 1)
+ if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
"getrawchangeaddress\n"
"\nReturns a new Bitcoin address, for receiving change.\n"
@@ -262,7 +282,7 @@ UniValue setaccount(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
std::string strAccount;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
@@ -431,6 +451,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
CBitcoinAddress address(request.params[0].get_str());
@@ -444,26 +465,26 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
// Wallet comments
CWalletTx wtx;
- if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty())
+ if (!request.params[2].isNull() && !request.params[2].get_str().empty())
wtx.mapValue["comment"] = request.params[2].get_str();
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
- if (request.params.size() > 4 && !request.params[4].isNull()) {
+ if (!request.params[4].isNull()) {
fSubtractFeeFromAmount = request.params[4].get_bool();
}
CCoinControl coin_control;
- if (request.params.size() > 5 && !request.params[5].isNull()) {
+ if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
- if (request.params.size() > 6 && !request.params[6].isNull()) {
+ if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
- if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
@@ -484,7 +505,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp)
+ if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
"listaddressgroupings\n"
"\nLists groups of addresses which have had their common ownership\n"
@@ -507,6 +528,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
+ HelpExampleRpc("listaddressgroupings", "")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
@@ -610,12 +632,13 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") +
"\nThe amount including unconfirmed transactions, zero confirmations\n"
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 0") +
- "\nThe amount with at least 6 confirmation, very safe\n"
+ "\nThe amount with at least 6 confirmations\n"
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
// Bitcoin address
@@ -629,7 +652,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
// Minimum confirmations
int nMinDepth = 1;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int();
// Tally
@@ -670,17 +693,18 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleCli("getreceivedbyaccount", "\"\"") +
"\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
+ HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
- "\nThe amount with at least 6 confirmation, very safe\n"
+ "\nThe amount with at least 6 confirmations\n"
+ HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
// Minimum confirmations
int nMinDepth = 1;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int();
// Get the set of pub keys assigned to account
@@ -748,20 +772,34 @@ UniValue getbalance(const JSONRPCRequest& request)
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 0)
- return ValueFromAmount(pwallet->GetBalance());
+ const UniValue& account_value = request.params[0];
+ const UniValue& minconf = request.params[1];
+ const UniValue& include_watchonly = request.params[2];
+
+ if (account_value.isNull()) {
+ if (!minconf.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance minconf option is only currently supported if an account is specified");
+ }
+ if (!include_watchonly.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance include_watchonly option is only currently supported if an account is specified");
+ }
+ return ValueFromAmount(pwallet->GetBalance());
+ }
- const std::string& account_param = request.params[0].get_str();
+ const std::string& account_param = account_value.get_str();
const std::string* account = account_param != "*" ? &account_param : nullptr;
int nMinDepth = 1;
- if (request.params.size() > 1)
- nMinDepth = request.params[1].get_int();
+ if (!minconf.isNull())
+ nMinDepth = minconf.get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(request.params.size() > 2)
- if(request.params[2].get_bool())
+ if(!include_watchonly.isNull())
+ if(include_watchonly.get_bool())
filter = filter | ISMINE_WATCH_ONLY;
return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
@@ -779,6 +817,7 @@ UniValue getunconfirmedbalance(const JSONRPCRequest &request)
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
return ValueFromAmount(pwallet->GetUnconfirmedBalance());
@@ -813,6 +852,7 @@ UniValue movecmd(const JSONRPCRequest& request)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::string strFrom = AccountFromValue(request.params[0]);
@@ -820,11 +860,11 @@ UniValue movecmd(const JSONRPCRequest& request)
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)request.params[3].get_int();
std::string strComment;
- if (request.params.size() > 4)
+ if (!request.params[4].isNull())
strComment = request.params[4].get_str();
if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) {
@@ -871,6 +911,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = AccountFromValue(request.params[0]);
@@ -881,14 +922,14 @@ UniValue sendfrom(const JSONRPCRequest& request)
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
nMinDepth = request.params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())
+ if (!request.params[4].isNull() && !request.params[4].get_str().empty())
wtx.mapValue["comment"] = request.params[4].get_str();
- if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty())
+ if (!request.params[5].isNull() && !request.params[5].get_str().empty())
wtx.mapValue["to"] = request.params[5].get_str();
EnsureWalletIsUnlocked(pwallet);
@@ -954,6 +995,7 @@ UniValue sendmany(const JSONRPCRequest& request)
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
if (pwallet->GetBroadcastTransactions() && !g_connman) {
@@ -963,28 +1005,28 @@ UniValue sendmany(const JSONRPCRequest& request)
std::string strAccount = AccountFromValue(request.params[0]);
UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
nMinDepth = request.params[2].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
- if (request.params.size() > 4 && !request.params[4].isNull())
+ if (!request.params[4].isNull())
subtractFeeFromAmount = request.params[4].get_array();
CCoinControl coin_control;
- if (request.params.size() > 5 && !request.params[5].isNull()) {
+ if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
- if (request.params.size() > 6 && !request.params[6].isNull()) {
+ if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
- if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
@@ -1087,7 +1129,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
strAccount = AccountFromValue(request.params[2]);
// Construct using pay-to-script-hash:
@@ -1105,18 +1147,22 @@ public:
CWallet * const pwallet;
CScriptID result;
- Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
+ explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
bool operator()(const CNoDestination &dest) const { return false; }
bool operator()(const CKeyID &keyID) {
if (pwallet) {
CScript basescript = GetScriptForDestination(keyID);
- isminetype typ;
- typ = IsMine(*pwallet, basescript, SIGVERSION_WITNESS_V0);
- if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
- return false;
CScript witscript = GetScriptForWitness(basescript);
+ SignatureData sigs;
+ // This check is to make sure that the script we created can actually be solved for and signed by us
+ // if we were to have the private keys. This is just to make sure that the script is valid and that,
+ // if found in a transaction, we would still accept and relay that transaction.
+ if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
+ !VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
+ return false;
+ }
pwallet->AddCScript(witscript);
result = CScriptID(witscript);
return true;
@@ -1133,11 +1179,15 @@ public:
result = scriptID;
return true;
}
- isminetype typ;
- typ = IsMine(*pwallet, subscript, SIGVERSION_WITNESS_V0);
- if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
- return false;
CScript witscript = GetScriptForWitness(subscript);
+ SignatureData sigs;
+ // This check is to make sure that the script we created can actually be solved for and signed by us
+ // if we were to have the private keys. This is just to make sure that the script is valid and that,
+ // if found in a transaction, we would still accept and relay that transaction.
+ if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
+ !VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
+ return false;
+ }
pwallet->AddCScript(witscript);
result = CScriptID(witscript);
return true;
@@ -1171,7 +1221,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
{
LOCK(cs_main);
- if (!IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()) && !GetBoolArg("-walletprematurewitness", false)) {
+ if (!IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()) && !gArgs.GetBoolArg("-walletprematurewitness", false)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Segregated witness not enabled on network");
}
}
@@ -1210,16 +1260,16 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
{
// Minimum confirmations
int nMinDepth = 1;
- if (params.size() > 0)
+ if (!params[0].isNull())
nMinDepth = params[0].get_int();
// Whether to include empty accounts
bool fIncludeEmpty = false;
- if (params.size() > 1)
+ if (!params[1].isNull())
fIncludeEmpty = params[1].get_bool();
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 2)
+ if(!params[2].isNull())
if(params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
@@ -1363,6 +1413,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, false);
@@ -1402,6 +1453,7 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, true);
@@ -1414,6 +1466,17 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
entry.push_back(Pair("address", addr.ToString()));
}
+/**
+ * List transactions based on the given criteria.
+ *
+ * @param pwallet The wallet.
+ * @param wtx The wallet transaction.
+ * @param strAccount The account, if any, or "*" for all.
+ * @param nMinDepth The minimum confirmation depth.
+ * @param fLong Whether to include the JSON version of the transaction.
+ * @param ret The UniValue into which the result is stored.
+ * @param filter The "is mine" filter bool.
+ */
void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
{
CAmount nFee;
@@ -1578,19 +1641,20 @@ UniValue listtransactions(const JSONRPCRequest& request)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = "*";
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
strAccount = request.params[0].get_str();
int nCount = 10;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nCount = request.params[1].get_int();
int nFrom = 0;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
nFrom = request.params[2].get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(request.params.size() > 3)
+ if(!request.params[3].isNull())
if(request.params[3].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
@@ -1607,10 +1671,10 @@ UniValue listtransactions(const JSONRPCRequest& request)
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
- if (pwtx != 0)
+ if (pwtx != nullptr)
ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);
CAccountingEntry *const pacentry = (*it).second.second;
- if (pacentry != 0)
+ if (pacentry != nullptr)
AcentryToJSON(*pacentry, strAccount, ret);
if ((int)ret.size() >= (nCount+nFrom)) break;
@@ -1671,13 +1735,14 @@ UniValue listaccounts(const JSONRPCRequest& request)
+ HelpExampleRpc("listaccounts", "6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
int nMinDepth = 1;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
nMinDepth = request.params[0].get_int();
isminefilter includeWatchonly = ISMINE_SPENDABLE;
- if(request.params.size() > 1)
+ if(!request.params[1].isNull())
if(request.params[1].get_bool())
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
@@ -1730,14 +1795,18 @@ UniValue listsinceblock(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp)
+ if (request.fHelp || request.params.size() > 4)
throw std::runtime_error(
- "listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n"
- "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
+ "listsinceblock ( \"blockhash\" target_confirmations include_watchonly include_removed )\n"
+ "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
+ "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
+ "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n"
"\nArguments:\n"
"1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
- "2. target_confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
- "3. include_watchonly: (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')"
+ "2. target_confirmations: (numeric, optional, default=1) Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value\n"
+ "3. include_watchonly: (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
+ "4. include_removed: (bool, optional, default=true) Show transactions that were removed due to a reorg in the \"removed\" array\n"
+ " (not guaranteed to work on pruned nodes)\n"
"\nResult:\n"
"{\n"
" \"transactions\": [\n"
@@ -1762,8 +1831,12 @@ UniValue listsinceblock(const JSONRPCRequest& request)
" \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
" \"label\" : \"label\" (string) A comment for the address/transaction, if any\n"
" \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
- " ],\n"
- " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
+ " ],\n"
+ " \"removed\": [\n"
+ " <structure is the same as \"transactions\" above, only present if include_removed=true>\n"
+ " Note: transactions that were readded in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n"
+ " ],\n"
+ " \"lastblock\": \"lastblockhash\" (string) The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("listsinceblock", "")
@@ -1771,23 +1844,22 @@ UniValue listsinceblock(const JSONRPCRequest& request)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
- const CBlockIndex *pindex = NULL;
+ const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
+ const CBlockIndex* paltindex = nullptr; // Block index of the specified block, even if it's in a deactivated chain.
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
- if (request.params.size() > 0)
- {
+ if (!request.params[0].isNull()) {
uint256 blockId;
blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
- if (it != mapBlockIndex.end())
- {
- pindex = it->second;
- if (chainActive[pindex->nHeight] != pindex)
- {
+ if (it != mapBlockIndex.end()) {
+ paltindex = pindex = it->second;
+ if (chainActive[pindex->nHeight] != pindex) {
// the block being asked for is a part of a deactivated chain;
// we don't want to depend on its perceived height in the block
// chain, we want to instead use the last common ancestor
@@ -1796,19 +1868,20 @@ UniValue listsinceblock(const JSONRPCRequest& request)
}
}
- if (request.params.size() > 1)
- {
+ if (!request.params[1].isNull()) {
target_confirms = request.params[1].get_int();
- if (target_confirms < 1)
+ if (target_confirms < 1) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
+ }
}
- if (request.params.size() > 2 && request.params[2].get_bool())
- {
+ if (!request.params[2].isNull() && request.params[2].get_bool()) {
filter = filter | ISMINE_WATCH_ONLY;
}
+ bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
+
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
UniValue transactions(UniValue::VARR);
@@ -1816,8 +1889,28 @@ UniValue listsinceblock(const JSONRPCRequest& request)
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
CWalletTx tx = pairWtx.second;
- if (depth == -1 || tx.GetDepthInMainChain() < depth)
+ if (depth == -1 || tx.GetDepthInMainChain() < depth) {
ListTransactions(pwallet, tx, "*", 0, true, transactions, filter);
+ }
+ }
+
+ // when a reorg'd block is requested, we also list any relevant transactions
+ // in the blocks of the chain that was detached
+ UniValue removed(UniValue::VARR);
+ while (include_removed && paltindex && paltindex != pindex) {
+ CBlock block;
+ if (!ReadBlockFromDisk(block, paltindex, Params().GetConsensus())) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
+ }
+ for (const CTransactionRef& tx : block.vtx) {
+ auto it = pwallet->mapWallet.find(tx->GetHash());
+ if (it != pwallet->mapWallet.end()) {
+ // We want all transactions regardless of confirmation count to appear here,
+ // even negative confirmation ones, hence the big negative.
+ ListTransactions(pwallet, it->second, "*", -100000000, true, removed, filter);
+ }
+ }
+ paltindex = paltindex->pprev;
}
CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
@@ -1825,6 +1918,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("transactions", transactions));
+ if (include_removed) ret.push_back(Pair("removed", removed));
ret.push_back(Pair("lastblock", lastblock.GetHex()));
return ret;
@@ -1882,21 +1976,23 @@ UniValue gettransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
hash.SetHex(request.params[0].get_str());
isminefilter filter = ISMINE_SPENDABLE;
- if(request.params.size() > 1)
+ if(!request.params[1].isNull())
if(request.params[1].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
UniValue entry(UniValue::VOBJ);
- if (!pwallet->mapWallet.count(hash)) {
+ auto it = pwallet->mapWallet.find(hash);
+ if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
}
- const CWalletTx& wtx = pwallet->mapWallet[hash];
+ const CWalletTx& wtx = it->second;
CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
@@ -1942,6 +2038,7 @@ UniValue abandontransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
@@ -2010,7 +2107,7 @@ UniValue keypoolrefill(const JSONRPCRequest& request)
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0;
- if (request.params.size() > 0) {
+ if (!request.params[0].isNull()) {
if (request.params[0].get_int() < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
kpSize = (unsigned int)request.params[0].get_int();
@@ -2053,7 +2150,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
"Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
"time that overrides the old one.\n"
"\nExamples:\n"
- "\nunlock the wallet for 60 seconds\n"
+ "\nUnlock the wallet for 60 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
"\nLock the wallet again (before 60 seconds)\n"
+ HelpExampleCli("walletlock", "") +
@@ -2208,11 +2305,11 @@ UniValue encryptwallet(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
"\nExamples:\n"
- "\nEncrypt you wallet\n"
+ "\nEncrypt your wallet\n"
+ HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
"\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
- "\nNow we can so something like sign\n"
+ "\nNow we can do something like sign\n"
+ HelpExampleCli("signmessage", "\"address\" \"test message\"") +
"\nNow lock the wallet again by removing the passphrase\n"
+ HelpExampleCli("walletlock", "") +
@@ -2297,19 +2394,18 @@ UniValue lockunspent(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 1)
- RPCTypeCheck(request.params, {UniValue::VBOOL});
- else
- RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VARR});
+ RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
bool fUnlock = request.params[0].get_bool();
- if (request.params.size() == 1) {
+ if (request.params[1].isNull()) {
if (fUnlock)
pwallet->UnlockAllCoins();
return true;
}
+ RPCTypeCheckArgument(request.params[1], UniValue::VARR);
+
UniValue outputs = request.params[1].get_array();
for (unsigned int idx = 0; idx < outputs.size(); idx++) {
const UniValue& output = outputs[idx];
@@ -2375,6 +2471,7 @@ UniValue listlockunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listlockunspent", "")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::vector<COutPoint> vOutpts;
@@ -2435,6 +2532,7 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
"Returns an object containing various wallet state info.\n"
"\nResult:\n"
"{\n"
+ " \"walletname\": xxxxx, (string) the wallet name\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
" \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
" \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
@@ -2452,11 +2550,13 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
+ HelpExampleRpc("getwalletinfo", "")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
UniValue obj(UniValue::VOBJ);
size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
+ obj.push_back(Pair("walletname", pwallet->GetName()));
obj.push_back(Pair("walletversion", pwallet->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance())));
@@ -2477,6 +2577,39 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
return obj;
}
+UniValue listwallets(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
+ "listwallets\n"
+ "Returns a list of currently loaded wallets.\n"
+ "For full information on the wallet, use \"getwalletinfo\"\n"
+ "\nResult:\n"
+ "[ (json array of strings)\n"
+ " \"walletname\" (string) the wallet name\n"
+ " ...\n"
+ "]\n"
+ "\nExamples:\n"
+ + HelpExampleCli("listwallets", "")
+ + HelpExampleRpc("listwallets", "")
+ );
+
+ UniValue obj(UniValue::VARR);
+
+ for (CWalletRef pwallet : vpwallets) {
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ LOCK(pwallet->cs_wallet);
+
+ obj.push_back(pwallet->GetName());
+ }
+
+ return obj;
+}
+
UniValue resendwallettransactions(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
@@ -2490,6 +2623,7 @@ UniValue resendwallettransactions(const JSONRPCRequest& request)
"Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
"Intended only for testing; the wallet code periodically re-broadcasts\n"
"automatically.\n"
+ "Returns an RPC error if -walletbroadcast is set to false.\n"
"Returns array of transaction ids that were re-broadcast.\n"
);
@@ -2498,6 +2632,10 @@ UniValue resendwallettransactions(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
+ if (!pwallet->GetBroadcastTransactions()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast");
+ }
+
std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
UniValue result(UniValue::VARR);
for (const uint256& txid : txids)
@@ -2565,20 +2703,22 @@ UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
);
+ ObserveSafeMode();
+
int nMinDepth = 1;
- if (request.params.size() > 0 && !request.params[0].isNull()) {
+ if (!request.params[0].isNull()) {
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
nMinDepth = request.params[0].get_int();
}
int nMaxDepth = 9999999;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
nMaxDepth = request.params[1].get_int();
}
std::set<CBitcoinAddress> setAddress;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
@@ -2593,7 +2733,7 @@ UniValue listunspent(const JSONRPCRequest& request)
}
bool include_unsafe = true;
- if (request.params.size() > 3 && !request.params[3].isNull()) {
+ if (!request.params[3].isNull()) {
RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
include_unsafe = request.params[3].get_bool();
}
@@ -2603,7 +2743,7 @@ UniValue listunspent(const JSONRPCRequest& request)
CAmount nMinimumSumAmount = MAX_MONEY;
uint64_t nMaximumCount = 0;
- if (request.params.size() > 4) {
+ if (!request.params[4].isNull()) {
const UniValue& options = request.params[4].get_obj();
if (options.exists("minimumAmount"))
@@ -2621,10 +2761,10 @@ UniValue listunspent(const JSONRPCRequest& request)
UniValue results(UniValue::VARR);
std::vector<COutput> vecOutputs;
- assert(pwallet != NULL);
+ assert(pwallet != nullptr);
LOCK2(cs_main, pwallet->cs_wallet);
- pwallet->AvailableCoins(vecOutputs, !include_unsafe, NULL, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
+ pwallet->AvailableCoins(vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
for (const COutput& out : vecOutputs) {
CTxDestination address;
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
@@ -2672,7 +2812,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
"fundrawtransaction \"hexstring\" ( options )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
@@ -2693,8 +2833,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
- " \"reserveChangeKey\" (boolean, optional, default true) Reserves the change output key from the keypool\n"
- " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per KB)\n"
+ " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
" The outputs are specified by their zero-based index, before any change output is added.\n"
@@ -2727,16 +2866,16 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);
+ ObserveSafeMode();
RPCTypeCheck(request.params, {UniValue::VSTR});
CCoinControl coinControl;
int changePosition = -1;
bool lockUnspents = false;
- bool reserveChangeKey = true;
UniValue subtractFeeFromOutputs;
std::set<int> setSubtractFeeFromOutputs;
- if (request.params.size() > 1) {
+ if (!request.params[1].isNull()) {
if (request.params[1].type() == UniValue::VBOOL) {
// backward compatibility bool only fallback
coinControl.fAllowWatchOnly = request.params[1].get_bool();
@@ -2752,7 +2891,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
{"changePosition", UniValueType(UniValue::VNUM)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
- {"reserveChangeKey", UniValueType(UniValue::VBOOL)},
+ {"reserveChangeKey", UniValueType(UniValue::VBOOL)}, // DEPRECATED (and ignored), should be removed in 0.16 or so.
{"feeRate", UniValueType()}, // will be checked below
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
{"replaceable", UniValueType(UniValue::VBOOL)},
@@ -2779,9 +2918,6 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if (options.exists("lockUnspents"))
lockUnspents = options["lockUnspents"].get_bool();
- if (options.exists("reserveChangeKey"))
- reserveChangeKey = options["reserveChangeKey"].get_bool();
-
if (options.exists("feeRate"))
{
coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
@@ -2795,9 +2931,15 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
coinControl.signalRbf = options["replaceable"].get_bool();
}
if (options.exists("conf_target")) {
+ if (options.exists("feeRate")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate");
+ }
coinControl.m_confirm_target = ParseConfirmTarget(options["conf_target"]);
}
if (options.exists("estimate_mode")) {
+ if (options.exists("feeRate")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
+ }
if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
@@ -2830,7 +2972,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
CAmount nFeeOut;
std::string strFailReason;
- if (!pwallet->FundTransaction(tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl, reserveChangeKey)) {
+ if (!pwallet->FundTransaction(tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
@@ -2904,7 +3046,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
CAmount totalFee = 0;
CCoinControl coin_control;
coin_control.signalRbf = true;
- if (request.params.size() > 1) {
+ if (!request.params[1].isNull()) {
UniValue options = request.params[1];
RPCTypeCheckObj(options,
{
@@ -3007,7 +3149,7 @@ UniValue generate(const JSONRPCRequest& request)
int num_generate = request.params[0].get_int();
uint64_t max_tries = 1000000;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
max_tries = request.params[1].get_int();
}
@@ -3039,64 +3181,65 @@ extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} },
- { "hidden", "resendwallettransactions", &resendwallettransactions, true, {} },
- { "wallet", "abandontransaction", &abandontransaction, false, {"txid"} },
- { "wallet", "abortrescan", &abortrescan, false, {} },
- { "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} },
- { "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} },
- { "wallet", "backupwallet", &backupwallet, true, {"destination"} },
- { "wallet", "bumpfee", &bumpfee, true, {"txid", "options"} },
- { "wallet", "dumpprivkey", &dumpprivkey, true, {"address"} },
- { "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
- { "wallet", "encryptwallet", &encryptwallet, true, {"passphrase"} },
- { "wallet", "getaccountaddress", &getaccountaddress, true, {"account"} },
- { "wallet", "getaccount", &getaccount, true, {"address"} },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, {"account"} },
- { "wallet", "getbalance", &getbalance, false, {"account","minconf","include_watchonly"} },
- { "wallet", "getnewaddress", &getnewaddress, true, {"account"} },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, {} },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, {"account","minconf"} },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, {"address","minconf"} },
- { "wallet", "gettransaction", &gettransaction, false, {"txid","include_watchonly"} },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, {} },
- { "wallet", "getwalletinfo", &getwalletinfo, false, {} },
- { "wallet", "importmulti", &importmulti, true, {"requests","options"} },
- { "wallet", "importprivkey", &importprivkey, true, {"privkey","label","rescan"} },
- { "wallet", "importwallet", &importwallet, true, {"filename"} },
- { "wallet", "importaddress", &importaddress, true, {"address","label","rescan","p2sh"} },
- { "wallet", "importprunedfunds", &importprunedfunds, true, {"rawtransaction","txoutproof"} },
- { "wallet", "importpubkey", &importpubkey, true, {"pubkey","label","rescan"} },
- { "wallet", "keypoolrefill", &keypoolrefill, true, {"newsize"} },
- { "wallet", "listaccounts", &listaccounts, false, {"minconf","include_watchonly"} },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false, {} },
- { "wallet", "listlockunspent", &listlockunspent, false, {} },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly"} },
- { "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} },
- { "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
- { "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
- { "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
- { "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
- { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
- { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
- { "wallet", "setaccount", &setaccount, true, {"address","account"} },
- { "wallet", "settxfee", &settxfee, true, {"amount"} },
- { "wallet", "signmessage", &signmessage, true, {"address","message"} },
- { "wallet", "walletlock", &walletlock, true, {} },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} },
- { "wallet", "walletpassphrase", &walletpassphrase, true, {"passphrase","timeout"} },
- { "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} },
-
- { "generating", "generate", &generate, true, {"nblocks","maxtries"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options"} },
+ { "hidden", "resendwallettransactions", &resendwallettransactions, {} },
+ { "wallet", "abandontransaction", &abandontransaction, {"txid"} },
+ { "wallet", "abortrescan", &abortrescan, {} },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} },
+ { "wallet", "addwitnessaddress", &addwitnessaddress, {"address"} },
+ { "wallet", "backupwallet", &backupwallet, {"destination"} },
+ { "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
+ { "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
+ { "wallet", "dumpwallet", &dumpwallet, {"filename"} },
+ { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
+ { "wallet", "getaccountaddress", &getaccountaddress, {"account"} },
+ { "wallet", "getaccount", &getaccount, {"address"} },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
+ { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} },
+ { "wallet", "getnewaddress", &getnewaddress, {"account"} },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, {} },
+ { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
+ { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
+ { "wallet", "getwalletinfo", &getwalletinfo, {} },
+ { "wallet", "importmulti", &importmulti, {"requests","options"} },
+ { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
+ { "wallet", "importwallet", &importwallet, {"filename"} },
+ { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
+ { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
+ { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
+ { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
+ { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, {} },
+ { "wallet", "listlockunspent", &listlockunspent, {} },
+ { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
+ { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} },
+ { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
+ { "wallet", "listwallets", &listwallets, {} },
+ { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
+ { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
+ { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
+ { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "setaccount", &setaccount, {"address","account"} },
+ { "wallet", "settxfee", &settxfee, {"amount"} },
+ { "wallet", "signmessage", &signmessage, {"address","message"} },
+ { "wallet", "walletlock", &walletlock, {} },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
+ { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+
+ { "generating", "generate", &generate, {"nblocks","maxtries"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)
{
- if (GetBoolArg("-disablewallet", false))
+ if (gArgs.GetBoolArg("-disablewallet", false))
return;
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)