diff options
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r-- | src/wallet/rpcwallet.cpp | 361 |
1 files changed, 105 insertions, 256 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index eae5f876ea..a86e93481c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -52,6 +52,14 @@ static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& pa return avoid_reuse; } +/** Checks if a CKey is in the given CWallet compressed or otherwise*/ +bool HaveKey(const CWallet& wallet, const CKey& key) +{ + CKey key2; + key2.Set(key.begin(), key.end(), !key.IsCompressed()); + return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID()); +} + bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name) { if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) { @@ -159,8 +167,6 @@ static UniValue getnewaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 2) - throw std::runtime_error( RPCHelpMan{"getnewaddress", "\nReturns a new Bitcoin address for receiving payments.\n" "If 'label' is specified, it is added to the address book \n" @@ -176,7 +182,7 @@ static UniValue getnewaddress(const JSONRPCRequest& request) HelpExampleCli("getnewaddress", "") + HelpExampleRpc("getnewaddress", "") }, - }.ToString()); + }.Check(request); LOCK(pwallet->cs_wallet); @@ -196,19 +202,11 @@ static UniValue getnewaddress(const JSONRPCRequest& request) } } - if (!pwallet->IsLocked()) { - pwallet->TopUpKeyPool(); - } - - // Generate a new key that is added to wallet - CPubKey newKey; - if (!pwallet->GetKeyFromPool(newKey)) { - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + CTxDestination dest; + std::string error; + if (!pwallet->GetNewDestination(output_type, label, dest, error)) { + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error); } - pwallet->LearnRelatedScripts(newKey, output_type); - CTxDestination dest = GetDestinationForKey(newKey, output_type); - - pwallet->SetAddressBook(dest, label, "receive"); return EncodeDestination(dest); } @@ -222,8 +220,6 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 1) - throw std::runtime_error( RPCHelpMan{"getrawchangeaddress", "\nReturns a new Bitcoin address, for receiving change.\n" "This is for use with raw transactions, NOT normal use.\n", @@ -237,7 +233,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "") }, - }.ToString()); + }.Check(request); LOCK(pwallet->cs_wallet); @@ -245,10 +241,6 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys"); } - if (!pwallet->IsLocked()) { - pwallet->TopUpKeyPool(); - } - OutputType output_type = pwallet->m_default_change_type != OutputType::CHANGE_AUTO ? pwallet->m_default_change_type : pwallet->m_default_address_type; if (!request.params[0].isNull()) { if (!ParseOutputType(request.params[0].get_str(), output_type)) { @@ -256,16 +248,11 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) } } - CReserveKey reservekey(pwallet); - CPubKey vchPubKey; - if (!reservekey.GetReservedKey(vchPubKey, true)) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - reservekey.KeepKey(); - - pwallet->LearnRelatedScripts(vchPubKey, output_type); - CTxDestination dest = GetDestinationForKey(vchPubKey, output_type); - + CTxDestination dest; + std::string error; + if (!pwallet->GetNewChangeDestination(output_type, dest, error)) { + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error); + } return EncodeDestination(dest); } @@ -279,8 +266,6 @@ static UniValue setlabel(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 2) - throw std::runtime_error( RPCHelpMan{"setlabel", "\nSets the label associated with the given address.\n", { @@ -292,7 +277,7 @@ static UniValue setlabel(const JSONRPCRequest& request) HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") + HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") }, - }.ToString()); + }.Check(request); LOCK(pwallet->cs_wallet); @@ -332,7 +317,6 @@ static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet CScript scriptPubKey = GetScriptForDestination(address); // Create and send the transaction - CReserveKey reservekey(pwallet); CAmount nFeeRequired; std::string strError; std::vector<CRecipient> vecSend; @@ -340,13 +324,13 @@ static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; vecSend.push_back(recipient); CTransactionRef tx; - if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) { + if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control)) { if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } CValidationState state; - if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, reservekey, state)) { + if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, state)) { strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } @@ -362,8 +346,6 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 2 || request.params.size() > 9) - throw std::runtime_error( RPCHelpMan{"sendtoaddress", "\nSend an amount to a given address." + HelpRequiringPassphrase(pwallet) + "\n", @@ -395,7 +377,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true") + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -460,8 +442,6 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 0) - throw std::runtime_error( RPCHelpMan{"listaddressgroupings", "\nLists groups of addresses which have had their common ownership\n" "made public by common use as inputs or as the resulting change\n" @@ -484,7 +464,7 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -523,8 +503,6 @@ static UniValue signmessage(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 2) - throw std::runtime_error( RPCHelpMan{"signmessage", "\nSign a message with the private key of an address" + HelpRequiringPassphrase(pwallet) + "\n", @@ -545,7 +523,7 @@ static UniValue signmessage(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"") }, - }.ToString()); + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -591,8 +569,6 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw std::runtime_error( RPCHelpMan{"getreceivedbyaddress", "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n", { @@ -612,7 +588,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -663,8 +639,6 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw std::runtime_error( RPCHelpMan{"getreceivedbylabel", "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n", { @@ -684,7 +658,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -733,8 +707,6 @@ static UniValue getbalance(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 4) - throw std::runtime_error( RPCHelpMan{"getbalance", "\nReturns the total available balance.\n" "The available balance is what the wallet considers currently spendable, and is\n" @@ -756,7 +728,7 @@ static UniValue getbalance(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("getbalance", "\"*\", 6") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -796,14 +768,12 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request) return NullUniValue; } - if (request.fHelp || request.params.size() > 0) - throw std::runtime_error( RPCHelpMan{"getunconfirmedbalance", "DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n", {}, RPCResults{}, RPCExamples{""}, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -825,7 +795,7 @@ static UniValue sendmany(const JSONRPCRequest& request) return NullUniValue; } - const RPCHelpMan help{"sendmany", + RPCHelpMan{"sendmany", "\nSend multiple times. Amounts are double-precision floating point numbers." + HelpRequiringPassphrase(pwallet) + "\n", { @@ -866,11 +836,7 @@ static UniValue sendmany(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"") }, - }; - - if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { - throw std::runtime_error(help.ToString()); - } + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -948,16 +914,15 @@ static UniValue sendmany(const JSONRPCRequest& request) std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext()); // Send - CReserveKey keyChange(pwallet); CAmount nFeeRequired = 0; int nChangePosRet = -1; std::string strFailReason; CTransactionRef tx; - bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control); + bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strFailReason, coin_control); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); CValidationState state; - if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, keyChange, state)) { + if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, state)) { strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } @@ -974,8 +939,6 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) { - std::string msg = RPCHelpMan{"addmultisigaddress", "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n" "Each key is a Bitcoin address or hex-encoded public key.\n" @@ -1004,9 +967,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") }, - }.ToString(); - throw std::runtime_error(msg); - } + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -1211,8 +1172,6 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 4) - throw std::runtime_error( RPCHelpMan{"listreceivedbyaddress", "\nList balances by receiving address.\n", { @@ -1243,7 +1202,7 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) + HelpExampleRpc("listreceivedbyaddress", "6, true, true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1264,8 +1223,6 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 3) - throw std::runtime_error( RPCHelpMan{"listreceivedbylabel", "\nList received transactions by label.\n", { @@ -1289,7 +1246,7 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) + HelpExampleCli("listreceivedbylabel", "6 true") + HelpExampleRpc("listreceivedbylabel", "6, true, true") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1404,8 +1361,6 @@ UniValue listtransactions(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 4) - throw std::runtime_error( RPCHelpMan{"listtransactions", "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n" "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n", @@ -1457,7 +1412,7 @@ UniValue listtransactions(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("listtransactions", "\"*\", 20, 100") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1538,8 +1493,6 @@ static UniValue listsinceblock(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 4) - throw std::runtime_error( RPCHelpMan{"listsinceblock", "\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" @@ -1592,7 +1545,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request) + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6") + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1683,8 +1636,6 @@ static UniValue gettransaction(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw std::runtime_error( RPCHelpMan{"gettransaction", "\nGet detailed information about in-wallet transaction <txid>\n", { @@ -1732,7 +1683,7 @@ static UniValue gettransaction(const JSONRPCRequest& request) + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true") + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1785,8 +1736,6 @@ static UniValue abandontransaction(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 1) { - throw std::runtime_error( RPCHelpMan{"abandontransaction", "\nMark in-wallet transaction <txid> as abandoned\n" "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n" @@ -1801,8 +1750,7 @@ static UniValue abandontransaction(const JSONRPCRequest& request) HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") }, - }.ToString()); - } + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1833,8 +1781,6 @@ static UniValue backupwallet(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 1) - throw std::runtime_error( RPCHelpMan{"backupwallet", "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n", { @@ -1845,7 +1791,7 @@ static UniValue backupwallet(const JSONRPCRequest& request) HelpExampleCli("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backup.dat\"") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -1872,8 +1818,6 @@ static UniValue keypoolrefill(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 1) - throw std::runtime_error( RPCHelpMan{"keypoolrefill", "\nFills the keypool."+ HelpRequiringPassphrase(pwallet) + "\n", @@ -1885,7 +1829,7 @@ static UniValue keypoolrefill(const JSONRPCRequest& request) HelpExampleCli("keypoolrefill", "") + HelpExampleRpc("keypoolrefill", "") }, - }.ToString()); + }.Check(request); if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet"); @@ -1922,8 +1866,6 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 2) { - throw std::runtime_error( RPCHelpMan{"walletpassphrase", "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" "This is needed prior to performing transactions related to private keys such as sending bitcoins\n" @@ -1943,8 +1885,7 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60") }, - }.ToString()); - } + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -2009,8 +1950,6 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 2) { - throw std::runtime_error( RPCHelpMan{"walletpassphrasechange", "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n", { @@ -2022,8 +1961,7 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request) HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"") }, - }.ToString()); - } + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -2063,8 +2001,6 @@ static UniValue walletlock(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 0) { - throw std::runtime_error( RPCHelpMan{"walletlock", "\nRemoves the wallet encryption key from memory, locking the wallet.\n" "After calling this method, you will need to call walletpassphrase again\n" @@ -2081,8 +2017,7 @@ static UniValue walletlock(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("walletlock", "") }, - }.ToString()); - } + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -2107,8 +2042,6 @@ static UniValue encryptwallet(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 1) { - throw std::runtime_error( RPCHelpMan{"encryptwallet", "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" "After this, any calls that interact with private keys such as sending or signing \n" @@ -2131,8 +2064,7 @@ static UniValue encryptwallet(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("encryptwallet", "\"my pass phrase\"") }, - }.ToString()); - } + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -2171,8 +2103,6 @@ static UniValue lockunspent(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw std::runtime_error( RPCHelpMan{"lockunspent", "\nUpdates list of temporarily unspendable outputs.\n" "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" @@ -2209,7 +2139,7 @@ static UniValue lockunspent(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") }, - }.ToString()); + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -2300,8 +2230,6 @@ static UniValue listlockunspent(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 0) - throw std::runtime_error( RPCHelpMan{"listlockunspent", "\nReturns list of temporarily unspendable outputs.\n" "See the lockunspent call to lock and unlock transactions for spending.\n", @@ -2327,7 +2255,7 @@ static UniValue listlockunspent(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("listlockunspent", "") }, - }.ToString()); + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -2357,8 +2285,6 @@ static UniValue settxfee(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) { - throw std::runtime_error( RPCHelpMan{"settxfee", "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n", { @@ -2371,8 +2297,7 @@ static UniValue settxfee(const JSONRPCRequest& request) HelpExampleCli("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001") }, - }.ToString()); - } + }.Check(request); auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); @@ -2399,7 +2324,7 @@ static UniValue getbalances(const JSONRPCRequest& request) } CWallet& wallet = *rpc_wallet; - const RPCHelpMan help{ + RPCHelpMan{ "getbalances", "Returns an object with all balances in " + CURRENCY_UNIT + ".\n", {}, @@ -2420,11 +2345,7 @@ static UniValue getbalances(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("getbalances", "") + HelpExampleRpc("getbalances", "")}, - }; - - if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { - throw std::runtime_error(help.ToString()); - } + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -2469,7 +2390,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) return NullUniValue; } - const RPCHelpMan help{"getwalletinfo", + RPCHelpMan{"getwalletinfo", "Returns an object containing various wallet state info.\n", {}, RPCResult{ @@ -2499,11 +2420,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "") }, - }; - - if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { - throw std::runtime_error(help.ToString()); - } + }.Check(request); // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now @@ -2550,8 +2467,6 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) static UniValue listwalletdir(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() != 0) { - throw std::runtime_error( RPCHelpMan{"listwalletdir", "Returns a list of wallets in the wallet directory.\n", {}, @@ -2569,8 +2484,7 @@ static UniValue listwalletdir(const JSONRPCRequest& request) HelpExampleCli("listwalletdir", "") + HelpExampleRpc("listwalletdir", "") }, - }.ToString()); - } + }.Check(request); UniValue wallets(UniValue::VARR); for (const auto& path : ListWalletDir()) { @@ -2586,8 +2500,6 @@ static UniValue listwalletdir(const JSONRPCRequest& request) static UniValue listwallets(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() != 0) - throw std::runtime_error( RPCHelpMan{"listwallets", "Returns a list of currently loaded wallets.\n" "For full information on the wallet, use \"getwalletinfo\"\n", @@ -2602,7 +2514,7 @@ static UniValue listwallets(const JSONRPCRequest& request) HelpExampleCli("listwallets", "") + HelpExampleRpc("listwallets", "") }, - }.ToString()); + }.Check(request); UniValue obj(UniValue::VARR); @@ -2621,8 +2533,6 @@ static UniValue listwallets(const JSONRPCRequest& request) static UniValue loadwallet(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() != 1) - throw std::runtime_error( RPCHelpMan{"loadwallet", "\nLoads a wallet from a wallet file or directory." "\nNote that all wallet command-line options used when starting bitcoind will be" @@ -2640,7 +2550,7 @@ static UniValue loadwallet(const JSONRPCRequest& request) HelpExampleCli("loadwallet", "\"test.dat\"") + HelpExampleRpc("loadwallet", "\"test.dat\"") }, - }.ToString()); + }.Check(request); WalletLocation location(request.params[0].get_str()); @@ -2674,12 +2584,10 @@ static UniValue setwalletflag(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { - std::string flags = ""; - for (auto& it : WALLET_FLAG_MAP) - if (it.second & MUTABLE_WALLET_FLAGS) - flags += (flags == "" ? "" : ", ") + it.first; - throw std::runtime_error( + std::string flags = ""; + for (auto& it : WALLET_FLAG_MAP) + if (it.second & MUTABLE_WALLET_FLAGS) + flags += (flags == "" ? "" : ", ") + it.first; RPCHelpMan{"setwalletflag", "\nChange the state of the given wallet flag for a wallet.\n", { @@ -2697,8 +2605,7 @@ static UniValue setwalletflag(const JSONRPCRequest& request) HelpExampleCli("setwalletflag", "avoid_reuse") + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"") }, - }.ToString()); - } + }.Check(request); std::string flag_str = request.params[0].get_str(); bool value = request.params[1].isNull() || request.params[1].get_bool(); @@ -2737,7 +2644,7 @@ static UniValue setwalletflag(const JSONRPCRequest& request) static UniValue createwallet(const JSONRPCRequest& request) { - const RPCHelpMan help{ + RPCHelpMan{ "createwallet", "\nCreates and loads a new wallet.\n", { @@ -2757,81 +2664,51 @@ static UniValue createwallet(const JSONRPCRequest& request) HelpExampleCli("createwallet", "\"testwallet\"") + HelpExampleRpc("createwallet", "\"testwallet\"") }, - }; - - if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { - throw std::runtime_error(help.ToString()); - } - std::string error; - std::string warning; + }.Check(request); uint64_t flags = 0; if (!request.params[1].isNull() && request.params[1].get_bool()) { flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; } - bool create_blank = false; // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted if (!request.params[2].isNull() && request.params[2].get_bool()) { - create_blank = true; flags |= WALLET_FLAG_BLANK_WALLET; } SecureString passphrase; passphrase.reserve(100); + std::string warning; if (!request.params[3].isNull()) { passphrase = request.params[3].get_str().c_str(); if (passphrase.empty()) { - // Empty string is invalid - throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password"); + // Empty string means unencrypted + warning = "Empty string given as passphrase, wallet will not be encrypted."; } - // Born encrypted wallets need to be blank first so that wallet creation doesn't make any unencrypted keys - flags |= WALLET_FLAG_BLANK_WALLET; } if (!request.params[4].isNull() && request.params[4].get_bool()) { flags |= WALLET_FLAG_AVOID_REUSE; } - WalletLocation location(request.params[0].get_str()); - if (location.Exists()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists."); - } - - // Wallet::Verify will check if we're trying to create a wallet with a duplication name. - if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error); - } - - std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, flags); - if (!wallet) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed."); + std::string error; + std::string create_warning; + std::shared_ptr<CWallet> wallet; + WalletCreationStatus status = CreateWallet(*g_rpc_interfaces->chain, passphrase, flags, request.params[0].get_str(), error, create_warning, wallet); + switch (status) { + case WalletCreationStatus::CREATION_FAILED: + throw JSONRPCError(RPC_WALLET_ERROR, error); + case WalletCreationStatus::ENCRYPTION_FAILED: + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error); + case WalletCreationStatus::SUCCESS: + break; + // no default case, so the compiler can warn about missing cases } - // Encrypt the wallet if there's a passphrase - if (!passphrase.empty() && !(flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - if (!wallet->EncryptWallet(passphrase)) { - throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet created but failed to encrypt."); - } - - if (!create_blank) { - // Unlock the wallet - if (!wallet->Unlock(passphrase)) { - throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet was encrypted but could not be unlocked"); - } - - // Set a seed for the wallet - CPubKey master_pub_key = wallet->GenerateNewSeed(); - wallet->SetHDSeed(master_pub_key); - wallet->NewKeyPool(); - - // Relock the wallet - wallet->Lock(); - } + if (warning.empty()) { + warning = create_warning; + } else if (!warning.empty() && !create_warning.empty()){ + warning += "; " + create_warning; } - AddWallet(wallet); - - wallet->postInitProcess(); - UniValue obj(UniValue::VOBJ); obj.pushKV("name", wallet->GetName()); obj.pushKV("warning", warning); @@ -2841,8 +2718,6 @@ static UniValue createwallet(const JSONRPCRequest& request) static UniValue unloadwallet(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() > 1) { - throw std::runtime_error( RPCHelpMan{"unloadwallet", "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n" "Specifying the wallet name on a wallet endpoint is invalid.", @@ -2854,8 +2729,7 @@ static UniValue unloadwallet(const JSONRPCRequest& request) HelpExampleCli("unloadwallet", "wallet_name") + HelpExampleRpc("unloadwallet", "wallet_name") }, - }.ToString()); - } + }.Check(request); std::string wallet_name; if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) { @@ -2892,7 +2766,7 @@ static UniValue listunspent(const JSONRPCRequest& request) return NullUniValue; } - const RPCHelpMan help{ + RPCHelpMan{ "listunspent", "\nReturns array of unspent transaction outputs\n" "with between minconf and maxconf (inclusive) confirmations.\n" @@ -2946,11 +2820,7 @@ static UniValue listunspent(const JSONRPCRequest& request) + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'") + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ") }, - }; - - if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { - throw std::runtime_error(help.ToString()); - } + }.Check(request); int nMinDepth = 1; if (!request.params[0].isNull()) { @@ -3016,9 +2886,11 @@ static UniValue listunspent(const JSONRPCRequest& request) { CCoinControl cctl; cctl.m_avoid_address_reuse = false; + cctl.m_min_depth = nMinDepth; + cctl.m_max_depth = nMaxDepth; auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); - pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth); + pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount); } LOCK(pwallet->cs_wallet); @@ -3219,7 +3091,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request) return NullUniValue; } - const RPCHelpMan help{"fundrawtransaction", + RPCHelpMan{"fundrawtransaction", "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n" "This will not modify existing inputs, and will add at most one change output to the outputs.\n" "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n" @@ -3283,11 +3155,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request) "\nSend the transaction\n" + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"") }, - }; - - if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { - throw std::runtime_error(help.ToString()); - } + }.Check(request); RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL}); @@ -3320,8 +3188,6 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) - throw std::runtime_error( RPCHelpMan{"signrawtransactionwithwallet", "\nSign inputs for raw transaction (serialized, hex-encoded).\n" "The second optional argument (may be null) is an array of previous transaction outputs that\n" @@ -3371,7 +3237,7 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"") }, - }.ToString()); + }.Check(request); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true); @@ -3404,18 +3270,16 @@ static UniValue bumpfee(const JSONRPCRequest& request) if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) return NullUniValue; - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { - throw std::runtime_error( RPCHelpMan{"bumpfee", "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n" "An opt-in RBF transaction with the given txid must be in the wallet.\n" "The command will pay the additional fee by reducing change outputs or adding inputs when necessary. It may add a new change output if one does not already exist.\n" - "If `totalFee` is given, adding inputs is not supported, so there must be a single change output that is big enough or it will fail.\n" + "If `totalFee` (DEPRECATED) is given, adding inputs is not supported, so there must be a single change output that is big enough or it will fail.\n" "All inputs in the original transaction will be included in the replacement transaction.\n" "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n" "By default, the new fee will be calculated automatically using estimatesmartfee.\n" "The user can specify a confirmation target for estimatesmartfee.\n" - "Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n" + "Alternatively, the user can specify totalFee (DEPRECATED), or use RPC settxfee to set a higher fee rate.\n" "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" "returned by getnetworkinfo) to enter the node's mempool.\n", { @@ -3423,7 +3287,7 @@ static UniValue bumpfee(const JSONRPCRequest& request) {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { {"confTarget", RPCArg::Type::NUM, /* default */ "fallback to wallet's default", "Confirmation target (in blocks)"}, - {"totalFee", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis.\n" + {"totalFee", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis. (DEPRECATED)\n" " In rare cases, the actual fee paid might be slightly higher than the specified\n" " totalFee if the tx change output has to be removed because it is too close to\n" " the dust threshold."}, @@ -3453,8 +3317,7 @@ static UniValue bumpfee(const JSONRPCRequest& request) "\nBump the fee, get the new transaction\'s txid\n" + HelpExampleCli("bumpfee", "<txid>") }, - }.ToString()); - } + }.Check(request); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ}); uint256 hash(ParseHashV(request.params[0], "txid")); @@ -3479,6 +3342,9 @@ static UniValue bumpfee(const JSONRPCRequest& request) } else if (options.exists("confTarget")) { // TODO: alias this to conf_target coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"], pwallet->chain().estimateMaxBlocks()); } else if (options.exists("totalFee")) { + if (!pwallet->chain().rpcEnableDeprecated("totalFee")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "totalFee argument has been deprecated and will be removed in 0.20. Please use -deprecatedrpc=totalFee to continue using this argument until removal."); + } totalFee = options["totalFee"].get_int64(); if (totalFee <= 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid totalFee %s (must be greater than 0)", FormatMoney(totalFee))); @@ -3567,8 +3433,6 @@ UniValue rescanblockchain(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 2) { - throw std::runtime_error( RPCHelpMan{"rescanblockchain", "\nRescan the local blockchain for wallet related transactions.\n" "Note: Use \"getwalletinfo\" to query the scanning progress.\n", @@ -3586,8 +3450,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request) HelpExampleCli("rescanblockchain", "100000 120000") + HelpExampleRpc("rescanblockchain", "100000, 120000") }, - }.ToString()); - } + }.Check(request); WalletRescanReserver reserver(pwallet); if (!reserver.reserve()) { @@ -3774,8 +3637,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 1) { - throw std::runtime_error( RPCHelpMan{"getaddressinfo", "\nReturn information about the given bitcoin address. Some information requires the address\n" "to be in the wallet.\n", @@ -3824,8 +3685,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request) HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + HelpExampleRpc("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") }, - }.ToString()); - } + }.Check(request); LOCK(pwallet->cs_wallet); @@ -3902,8 +3762,6 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 1) - throw std::runtime_error( RPCHelpMan{"getaddressesbylabel", "\nReturns the list of addresses assigned the specified label.\n", { @@ -3920,7 +3778,7 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request) HelpExampleCli("getaddressesbylabel", "\"tabby\"") + HelpExampleRpc("getaddressesbylabel", "\"tabby\"") }, - }.ToString()); + }.Check(request); LOCK(pwallet->cs_wallet); @@ -3961,8 +3819,6 @@ static UniValue listlabels(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 1) - throw std::runtime_error( RPCHelpMan{"listlabels", "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n", { @@ -3984,7 +3840,7 @@ static UniValue listlabels(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("listlabels", "receive") }, - }.ToString()); + }.Check(request); LOCK(pwallet->cs_wallet); @@ -4018,8 +3874,6 @@ UniValue sethdseed(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 2) { - throw std::runtime_error( RPCHelpMan{"sethdseed", "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n" "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n" @@ -4040,8 +3894,7 @@ UniValue sethdseed(const JSONRPCRequest& request) + HelpExampleCli("sethdseed", "true \"wifkey\"") + HelpExampleRpc("sethdseed", "true, \"wifkey\"") }, - }.ToString()); - } + }.Check(request); if (pwallet->chain().isInitialBlockDownload()) { throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download"); @@ -4097,8 +3950,6 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw std::runtime_error( RPCHelpMan{"walletprocesspsbt", "\nUpdate a PSBT with input information from our wallet and then sign inputs\n" "that we can sign for." + @@ -4125,7 +3976,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("walletprocesspsbt", "\"psbt\"") }, - }.ToString()); + }.Check(request); RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR}); @@ -4166,8 +4017,6 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) - throw std::runtime_error( RPCHelpMan{"walletcreatefundedpsbt", "\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n" "Implements the Creator and Updater roles.\n", @@ -4239,7 +4088,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) "\nCreate a transaction with no inputs\n" + HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") }, - }.ToString()); + }.Check(request); RPCTypeCheck(request.params, { UniValue::VARR, |