diff options
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r-- | src/wallet/rpcwallet.cpp | 644 |
1 files changed, 467 insertions, 177 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6849671dcf..8b95c56a5f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -16,6 +16,7 @@ #include <policy/policy.h> #include <policy/rbf.h> #include <rpc/mining.h> +#include <rpc/rawtransaction.h> #include <rpc/safemode.h> #include <rpc/server.h> #include <rpc/util.h> @@ -25,6 +26,7 @@ #include <utilmoneystr.h> #include <wallet/coincontrol.h> #include <wallet/feebumper.h> +#include <wallet/rpcwallet.h> #include <wallet/wallet.h> #include <wallet/walletdb.h> #include <wallet/walletutil.h> @@ -86,25 +88,25 @@ void EnsureWalletIsUnlocked(CWallet * const pwallet) void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) { int confirms = wtx.GetDepthInMainChain(); - entry.push_back(Pair("confirmations", confirms)); + entry.pushKV("confirmations", confirms); if (wtx.IsCoinBase()) - entry.push_back(Pair("generated", true)); + entry.pushKV("generated", true); if (confirms > 0) { - entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); - entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + entry.pushKV("blockhash", wtx.hashBlock.GetHex()); + entry.pushKV("blockindex", wtx.nIndex); + entry.pushKV("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()); } else { - entry.push_back(Pair("trusted", wtx.IsTrusted())); + entry.pushKV("trusted", wtx.IsTrusted()); } uint256 hash = wtx.GetHash(); - entry.push_back(Pair("txid", hash.GetHex())); + entry.pushKV("txid", hash.GetHex()); UniValue conflicts(UniValue::VARR); for (const uint256& conflict : wtx.GetConflicts()) conflicts.push_back(conflict.GetHex()); - entry.push_back(Pair("walletconflicts", conflicts)); - entry.push_back(Pair("time", wtx.GetTxTime())); - entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); + entry.pushKV("walletconflicts", conflicts); + entry.pushKV("time", wtx.GetTxTime()); + entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived); // Add opt-in RBF status std::string rbfStatus = "no"; @@ -116,10 +118,10 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125) rbfStatus = "yes"; } - entry.push_back(Pair("bip125-replaceable", rbfStatus)); + entry.pushKV("bip125-replaceable", rbfStatus); for (const std::pair<std::string, std::string>& item : wtx.mapValue) - entry.push_back(Pair(item.first, item.second)); + entry.pushKV(item.first, item.second); } std::string AccountFromValue(const UniValue& value) @@ -435,7 +437,7 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA } CValidationState state; if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) { - strError = strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()); + strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } } @@ -1155,7 +1157,7 @@ UniValue sendmany(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); CValidationState state; if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) { - strFailReason = strprintf("Transaction commit failed:: %s", state.GetRejectReason()); + strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } @@ -1169,9 +1171,8 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - { - std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" + if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) { + std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" \"address_type\" )\n" "\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" "This functionality is only intended for use with non-watchonly addresses.\n" @@ -1186,16 +1187,13 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) " ...,\n" " ]\n" "3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n" + "4. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n" "\nResult:\n" "{\n" " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n" " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n" "}\n" - "\nResult (DEPRECATED. To see this result in v0.16 instead, please start bitcoind with -deprecatedrpc=addmultisigaddress).\n" - " clients should transition to the new output api before upgrading to v0.17.\n" - "\"address\" (string) A bitcoin address associated with the keys.\n" - "\nExamples:\n" "\nAdd a multisig address from 2 addresses\n" + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + @@ -1224,17 +1222,20 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) } } + OutputType output_type = g_address_type; + if (!request.params[3].isNull()) { + output_type = ParseOutputType(request.params[3].get_str(), output_type); + if (output_type == OUTPUT_TYPE_NONE) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str())); + } + } + // Construct using pay-to-script-hash: CScript inner = CreateMultisigRedeemscript(required, pubkeys); pwallet->AddCScript(inner); - CTxDestination dest = pwallet->AddAndGetDestinationForScript(inner, g_address_type); + CTxDestination dest = pwallet->AddAndGetDestinationForScript(inner, output_type); pwallet->SetAddressBook(dest, strAccount, "send"); - // Return old style interface - if (IsDeprecatedRPCEnabled("addmultisigaddress")) { - return EncodeDestination(dest); - } - UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(dest)); result.pushKV("redeemScript", HexStr(inner.begin(), inner.end())); @@ -1464,13 +1465,13 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA { UniValue obj(UniValue::VOBJ); if(fIsWatchonly) - obj.push_back(Pair("involvesWatchonly", true)); - obj.push_back(Pair("address", EncodeDestination(dest))); - obj.push_back(Pair("account", strAccount)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); - obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf))); + obj.pushKV("involvesWatchonly", true); + obj.pushKV("address", EncodeDestination(dest)); + obj.pushKV("account", strAccount); + obj.pushKV("amount", ValueFromAmount(nAmount)); + obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); if (!fByAccounts) - obj.push_back(Pair("label", strAccount)); + obj.pushKV("label", strAccount); UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { @@ -1479,7 +1480,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA transactions.push_back(_item.GetHex()); } } - obj.push_back(Pair("txids", transactions)); + obj.pushKV("txids", transactions); ret.push_back(obj); } } @@ -1492,10 +1493,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA int nConf = entry.second.nConf; UniValue obj(UniValue::VOBJ); if (entry.second.fIsWatchonly) - obj.push_back(Pair("involvesWatchonly", true)); - obj.push_back(Pair("account", entry.first)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); - obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf))); + obj.pushKV("involvesWatchonly", true); + obj.pushKV("account", entry.first); + obj.pushKV("amount", ValueFromAmount(nAmount)); + obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); ret.push_back(obj); } } @@ -1601,7 +1602,7 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request) static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) { if (IsValidDestination(dest)) { - entry.push_back(Pair("address", EncodeDestination(dest))); + entry.pushKV("address", EncodeDestination(dest)); } } @@ -1635,20 +1636,20 @@ void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::s { UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) { - entry.push_back(Pair("involvesWatchonly", true)); + entry.pushKV("involvesWatchonly", true); } - entry.push_back(Pair("account", strSentAccount)); + entry.pushKV("account", strSentAccount); MaybePushAddress(entry, s.destination); - entry.push_back(Pair("category", "send")); - entry.push_back(Pair("amount", ValueFromAmount(-s.amount))); + entry.pushKV("category", "send"); + entry.pushKV("amount", ValueFromAmount(-s.amount)); if (pwallet->mapAddressBook.count(s.destination)) { - entry.push_back(Pair("label", pwallet->mapAddressBook[s.destination].name)); + entry.pushKV("label", pwallet->mapAddressBook[s.destination].name); } - entry.push_back(Pair("vout", s.vout)); - entry.push_back(Pair("fee", ValueFromAmount(-nFee))); + entry.pushKV("vout", s.vout); + entry.pushKV("fee", ValueFromAmount(-nFee)); if (fLong) WalletTxToJSON(wtx, entry); - entry.push_back(Pair("abandoned", wtx.isAbandoned())); + entry.pushKV("abandoned", wtx.isAbandoned()); ret.push_back(entry); } } @@ -1666,28 +1667,28 @@ void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::s { UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { - entry.push_back(Pair("involvesWatchonly", true)); + entry.pushKV("involvesWatchonly", true); } - entry.push_back(Pair("account", account)); + entry.pushKV("account", account); MaybePushAddress(entry, r.destination); if (wtx.IsCoinBase()) { if (wtx.GetDepthInMainChain() < 1) - entry.push_back(Pair("category", "orphan")); + entry.pushKV("category", "orphan"); else if (wtx.GetBlocksToMaturity() > 0) - entry.push_back(Pair("category", "immature")); + entry.pushKV("category", "immature"); else - entry.push_back(Pair("category", "generate")); + entry.pushKV("category", "generate"); } else { - entry.push_back(Pair("category", "receive")); + entry.pushKV("category", "receive"); } - entry.push_back(Pair("amount", ValueFromAmount(r.amount))); + entry.pushKV("amount", ValueFromAmount(r.amount)); if (pwallet->mapAddressBook.count(r.destination)) { - entry.push_back(Pair("label", account)); + entry.pushKV("label", account); } - entry.push_back(Pair("vout", r.vout)); + entry.pushKV("vout", r.vout); if (fLong) WalletTxToJSON(wtx, entry); ret.push_back(entry); @@ -1703,12 +1704,12 @@ void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccoun if (fAllAccounts || acentry.strAccount == strAccount) { UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("account", acentry.strAccount)); - entry.push_back(Pair("category", "move")); - entry.push_back(Pair("time", acentry.nTime)); - entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); - entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); - entry.push_back(Pair("comment", acentry.strComment)); + entry.pushKV("account", acentry.strAccount); + entry.pushKV("category", "move"); + entry.pushKV("time", acentry.nTime); + entry.pushKV("amount", ValueFromAmount(acentry.nCreditDebit)); + entry.pushKV("otheraccount", acentry.strOtherAccount); + entry.pushKV("comment", acentry.strComment); ret.push_back(entry); } } @@ -1786,8 +1787,6 @@ UniValue listtransactions(const JSONRPCRequest& request) // the user could have gotten from another RPC command prior to now pwallet->BlockUntilSyncedToCurrentChain(); - LOCK2(cs_main, pwallet->cs_wallet); - std::string strAccount = "*"; if (!request.params[0].isNull()) strAccount = request.params[0].get_str(); @@ -1809,20 +1808,25 @@ UniValue listtransactions(const JSONRPCRequest& request) UniValue ret(UniValue::VARR); - const CWallet::TxItems & txOrdered = pwallet->wtxOrdered; - - // iterate backwards until we have nCount items to return: - for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - CWalletTx *const pwtx = (*it).second.first; - if (pwtx != nullptr) - ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter); - CAccountingEntry *const pacentry = (*it).second.second; - if (pacentry != nullptr) - AcentryToJSON(*pacentry, strAccount, ret); + LOCK2(cs_main, pwallet->cs_wallet); - if ((int)ret.size() >= (nCount+nFrom)) break; + const CWallet::TxItems & txOrdered = pwallet->wtxOrdered; + + // iterate backwards until we have nCount items to return: + for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + { + CWalletTx *const pwtx = (*it).second.first; + if (pwtx != nullptr) + ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter); + CAccountingEntry *const pacentry = (*it).second.second; + if (pacentry != nullptr) + AcentryToJSON(*pacentry, strAccount, ret); + + if ((int)ret.size() >= (nCount+nFrom)) break; + } } + // ret is newest to oldest if (nFrom > (int)ret.size()) @@ -1932,7 +1936,7 @@ UniValue listaccounts(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); for (const std::pair<std::string, CAmount>& accountBalance : mapAccountBalances) { - ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); + ret.pushKV(accountBalance.first, ValueFromAmount(accountBalance.second)); } return ret; } @@ -2072,9 +2076,9 @@ UniValue listsinceblock(const JSONRPCRequest& request) uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); 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())); + ret.pushKV("transactions", transactions); + if (include_removed) ret.pushKV("removed", removed); + ret.pushKV("lastblock", lastblock.GetHex()); return ret; } @@ -2159,18 +2163,18 @@ UniValue gettransaction(const JSONRPCRequest& request) CAmount nNet = nCredit - nDebit; CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0); - entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); + entry.pushKV("amount", ValueFromAmount(nNet - nFee)); if (wtx.IsFromMe(filter)) - entry.push_back(Pair("fee", ValueFromAmount(nFee))); + entry.pushKV("fee", ValueFromAmount(nFee)); WalletTxToJSON(wtx, entry); UniValue details(UniValue::VARR); ListTransactions(pwallet, wtx, "*", 0, false, details, filter); - entry.push_back(Pair("details", details)); + entry.pushKV("details", details); std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); - entry.push_back(Pair("hex", strHex)); + entry.pushKV("hex", strHex); return entry; } @@ -2182,14 +2186,14 @@ UniValue abandontransaction(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 1) + if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( "abandontransaction \"txid\"\n" "\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" "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n" "It only works on transactions which are not included in a block and are not currently in the mempool.\n" - "It has no effect on transactions which are already conflicted or abandoned.\n" + "It has no effect on transactions which are already abandoned.\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "\nResult:\n" @@ -2197,6 +2201,7 @@ UniValue abandontransaction(const JSONRPCRequest& request) + HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") ); + } ObserveSafeMode(); @@ -2699,8 +2704,8 @@ UniValue listlockunspent(const JSONRPCRequest& request) for (COutPoint &outpt : vOutpts) { UniValue o(UniValue::VOBJ); - o.push_back(Pair("txid", outpt.hash.GetHex())); - o.push_back(Pair("vout", (int)outpt.n)); + o.pushKV("txid", outpt.hash.GetHex()); + o.pushKV("vout", (int)outpt.n); ret.push_back(o); } @@ -2760,7 +2765,7 @@ UniValue getwalletinfo(const JSONRPCRequest& request) " \"keypoolsize_hd_internal\": xxxx, (numeric) how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)\n" " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n" - " \"hdmasterkeyid\": \"<hash160>\" (string) the Hash160 of the HD master pubkey\n" + " \"hdmasterkeyid\": \"<hash160>\" (string, optional) the Hash160 of the HD master pubkey (only present when HD is enabled)\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") @@ -2778,24 +2783,24 @@ UniValue getwalletinfo(const JSONRPCRequest& request) 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()))); - obj.push_back(Pair("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance()))); - obj.push_back(Pair("txcount", (int)pwallet->mapWallet.size())); - obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", (int64_t)kpExternalSize)); + obj.pushKV("walletname", pwallet->GetName()); + obj.pushKV("walletversion", pwallet->GetVersion()); + obj.pushKV("balance", ValueFromAmount(pwallet->GetBalance())); + obj.pushKV("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance())); + obj.pushKV("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance())); + obj.pushKV("txcount", (int)pwallet->mapWallet.size()); + obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime()); + obj.pushKV("keypoolsize", (int64_t)kpExternalSize); CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID; if (!masterKeyID.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) { - obj.push_back(Pair("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize))); + obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize)); } if (pwallet->IsCrypted()) { - obj.push_back(Pair("unlocked_until", pwallet->nRelockTime)); + obj.pushKV("unlocked_until", pwallet->nRelockTime); } - obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); + obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())); if (!masterKeyID.IsNull()) - obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex())); + obj.pushKV("hdmasterkeyid", masterKeyID.GetHex()); return obj; } @@ -3000,31 +3005,31 @@ UniValue listunspent(const JSONRPCRequest& request) continue; UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); - entry.push_back(Pair("vout", out.i)); + entry.pushKV("txid", out.tx->GetHash().GetHex()); + entry.pushKV("vout", out.i); if (fValidAddress) { - entry.push_back(Pair("address", EncodeDestination(address))); + entry.pushKV("address", EncodeDestination(address)); if (pwallet->mapAddressBook.count(address)) { - entry.push_back(Pair("account", pwallet->mapAddressBook[address].name)); + entry.pushKV("account", pwallet->mapAddressBook[address].name); } if (scriptPubKey.IsPayToScriptHash()) { const CScriptID& hash = boost::get<CScriptID>(address); CScript redeemScript; if (pwallet->GetCScript(hash, redeemScript)) { - entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())); } } } - entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); - entry.push_back(Pair("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue))); - entry.push_back(Pair("confirmations", out.nDepth)); - entry.push_back(Pair("spendable", out.fSpendable)); - entry.push_back(Pair("solvable", out.fSolvable)); - entry.push_back(Pair("safe", out.fSafe)); + entry.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())); + entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue)); + entry.pushKV("confirmations", out.nDepth); + entry.pushKV("spendable", out.fSpendable); + entry.pushKV("solvable", out.fSolvable); + entry.pushKV("safe", out.fSafe); results.push_back(entry); } @@ -3057,6 +3062,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) " {\n" " \"changeAddress\" (string, optional, default pool address) The bitcoin address to receive the change\n" " \"changePosition\" (numeric, optional, default random) The index of the change output\n" + " \"change_type\" (string, optional) The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -changetype.\n" " \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n" " \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n" " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific fee rate in " + CURRENCY_UNIT + "/kB\n" @@ -3077,7 +3083,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) " for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n" "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction \n" " If iswitness is not present, heuristic tests will be used in decoding\n" - + "\nResult:\n" "{\n" " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n" @@ -3122,9 +3128,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) { {"changeAddress", UniValueType(UniValue::VSTR)}, {"changePosition", UniValueType(UniValue::VNUM)}, + {"change_type", UniValueType(UniValue::VSTR)}, {"includeWatching", UniValueType(UniValue::VBOOL)}, {"lockUnspents", 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)}, @@ -3146,6 +3152,16 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) if (options.exists("changePosition")) changePosition = options["changePosition"].get_int(); + if (options.exists("change_type")) { + if (options.exists("changeAddress")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options"); + } + coinControl.change_type = ParseOutputType(options["change_type"].get_str(), coinControl.change_type); + if (coinControl.change_type == OUTPUT_TYPE_NONE) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str())); + } + } + if (options.exists("includeWatching")) coinControl.fAllowWatchOnly = options["includeWatching"].get_bool(); @@ -3214,13 +3230,82 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) } UniValue result(UniValue::VOBJ); - result.push_back(Pair("hex", EncodeHexTx(tx))); - result.push_back(Pair("changepos", changePosition)); - result.push_back(Pair("fee", ValueFromAmount(nFeeOut))); + result.pushKV("hex", EncodeHexTx(tx)); + result.pushKV("changepos", changePosition); + result.pushKV("fee", ValueFromAmount(nFeeOut)); return result; } +UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) +{ + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) + throw std::runtime_error( + "signrawtransactionwithwallet \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] sighashtype )\n" + "\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" + "this transaction depends on but may not yet be in the block chain.\n" + + HelpRequiringPassphrase(pwallet) + "\n" + + "\nArguments:\n" + "1. \"hexstring\" (string, required) The transaction hex string\n" + "2. \"prevtxs\" (string, optional) An json array of previous dependent transaction outputs\n" + " [ (json array of json objects, or 'null' if none provided)\n" + " {\n" + " \"txid\":\"id\", (string, required) The transaction id\n" + " \"vout\":n, (numeric, required) The output number\n" + " \"scriptPubKey\": \"hex\", (string, required) script key\n" + " \"redeemScript\": \"hex\", (string, required for P2SH or P2WSH) redeem script\n" + " \"amount\": value (numeric, required) The amount spent\n" + " }\n" + " ,...\n" + " ]\n" + "3. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n" + " \"ALL\"\n" + " \"NONE\"\n" + " \"SINGLE\"\n" + " \"ALL|ANYONECANPAY\"\n" + " \"NONE|ANYONECANPAY\"\n" + " \"SINGLE|ANYONECANPAY\"\n" + + "\nResult:\n" + "{\n" + " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" + " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" + " \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n" + " {\n" + " \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n" + " \"vout\" : n, (numeric) The index of the output to spent and used as input\n" + " \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n" + " \"sequence\" : n, (numeric) Script sequence number\n" + " \"error\" : \"text\" (string) Verification or signing error related to the input\n" + " }\n" + " ,...\n" + " ]\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"") + ); + + RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true); + + CMutableTransaction mtx; + if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + } + + // Sign the transaction + LOCK2(cs_main, pwallet->cs_wallet); + return SignTransaction(mtx, request.params[1], pwallet, false, request.params[2]); +} + UniValue bumpfee(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); @@ -3237,8 +3322,8 @@ UniValue bumpfee(const JSONRPCRequest& request) "If the change output is not big enough to cover the increased fee, the command will currently fail\n" "instead of adding new inputs to compensate. (A future implementation could improve this.)\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 estimatefee.\n" - "The user can specify a confirmation target for estimatefee.\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" "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" @@ -3358,14 +3443,14 @@ UniValue bumpfee(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, errors[0]); } UniValue result(UniValue::VOBJ); - result.push_back(Pair("txid", txid.GetHex())); - result.push_back(Pair("origfee", ValueFromAmount(old_fee))); - result.push_back(Pair("fee", ValueFromAmount(new_fee))); + result.pushKV("txid", txid.GetHex()); + result.pushKV("origfee", ValueFromAmount(old_fee)); + result.pushKV("fee", ValueFromAmount(new_fee)); UniValue result_errors(UniValue::VARR); for (const std::string& error : errors) { result_errors.push_back(error); } - result.push_back(Pair("errors", result_errors)); + result.pushKV("errors", result_errors); return result; } @@ -3500,6 +3585,209 @@ UniValue rescanblockchain(const JSONRPCRequest& request) return response; } +class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue> +{ +public: + CWallet * const pwallet; + + void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const + { + // Always present: script type and redeemscript + txnouttype which_type; + std::vector<std::vector<unsigned char>> solutions_data; + Solver(subscript, which_type, solutions_data); + obj.pushKV("script", GetTxnOutputType(which_type)); + obj.pushKV("hex", HexStr(subscript.begin(), subscript.end())); + + CTxDestination embedded; + UniValue a(UniValue::VARR); + if (ExtractDestination(subscript, embedded)) { + // Only when the script corresponds to an address. + UniValue subobj(UniValue::VOBJ); + UniValue detail = DescribeAddress(embedded); + subobj.pushKVs(detail); + UniValue wallet_detail = boost::apply_visitor(*this, embedded); + subobj.pushKVs(wallet_detail); + subobj.pushKV("address", EncodeDestination(embedded)); + subobj.pushKV("scriptPubKey", HexStr(subscript.begin(), subscript.end())); + // Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works. + if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]); + obj.pushKV("embedded", std::move(subobj)); + if (include_addresses) a.push_back(EncodeDestination(embedded)); + } else if (which_type == TX_MULTISIG) { + // Also report some information on multisig scripts (which do not have a corresponding address). + // TODO: abstract out the common functionality between this logic and ExtractDestinations. + obj.pushKV("sigsrequired", solutions_data[0][0]); + UniValue pubkeys(UniValue::VARR); + for (size_t i = 1; i < solutions_data.size() - 1; ++i) { + CPubKey key(solutions_data[i].begin(), solutions_data[i].end()); + if (include_addresses) a.push_back(EncodeDestination(key.GetID())); + pubkeys.push_back(HexStr(key.begin(), key.end())); + } + obj.pushKV("pubkeys", std::move(pubkeys)); + } + + // The "addresses" field is confusing because it refers to public keys using their P2PKH address. + // For that reason, only add the 'addresses' field when needed for backward compatibility. New applications + // can use the 'embedded'->'address' field for P2SH or P2WSH wrapped addresses, and 'pubkeys' for + // inspecting multisig participants. + if (include_addresses) obj.pushKV("addresses", std::move(a)); + } + + explicit DescribeWalletAddressVisitor(CWallet* _pwallet) : pwallet(_pwallet) {} + + UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); } + + UniValue operator()(const CKeyID& keyID) const + { + UniValue obj(UniValue::VOBJ); + CPubKey vchPubKey; + if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) { + obj.pushKV("pubkey", HexStr(vchPubKey)); + obj.pushKV("iscompressed", vchPubKey.IsCompressed()); + } + return obj; + } + + UniValue operator()(const CScriptID& scriptID) const + { + UniValue obj(UniValue::VOBJ); + CScript subscript; + if (pwallet && pwallet->GetCScript(scriptID, subscript)) { + ProcessSubScript(subscript, obj, IsDeprecatedRPCEnabled("validateaddress")); + } + return obj; + } + + UniValue operator()(const WitnessV0KeyHash& id) const + { + UniValue obj(UniValue::VOBJ); + CPubKey pubkey; + if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) { + obj.pushKV("pubkey", HexStr(pubkey)); + } + return obj; + } + + UniValue operator()(const WitnessV0ScriptHash& id) const + { + UniValue obj(UniValue::VOBJ); + CScript subscript; + CRIPEMD160 hasher; + uint160 hash; + hasher.Write(id.begin(), 32).Finalize(hash.begin()); + if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) { + ProcessSubScript(subscript, obj); + } + return obj; + } + + UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); } +}; + +UniValue DescribeWalletAddress(CWallet* pwallet, const CTxDestination& dest) +{ + UniValue ret(UniValue::VOBJ); + UniValue detail = DescribeAddress(dest); + ret.pushKVs(detail); + ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(pwallet), dest)); + return ret; +} + +UniValue getaddressinfo(const JSONRPCRequest& request) +{ + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + if (request.fHelp || request.params.size() != 1) { + throw std::runtime_error( + "getaddressinfo \"address\"\n" + "\nReturn information about the given bitcoin address. Some information requires the address\n" + "to be in the wallet.\n" + "\nArguments:\n" + "1. \"address\" (string, required) The bitcoin address to get the information of.\n" + "\nResult:\n" + "{\n" + " \"address\" : \"address\", (string) The bitcoin address validated\n" + " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" + " \"ismine\" : true|false, (boolean) If the address is yours or not\n" + " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n" + " \"isscript\" : true|false, (boolean) If the key is a script\n" + " \"iswitness\" : true|false, (boolean) If the address is a witness address\n" + " \"witness_version\" : version (numeric, optional) The version number of the witness program\n" + " \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n" + " \"script\" : \"type\" (string, optional) The output script type. Only if \"isscript\" is true and the redeemscript is known. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash, witness_unknown\n" + " \"hex\" : \"hex\", (string, optional) The redeemscript for the p2sh address\n" + " \"pubkeys\" (string, optional) Array of pubkeys associated with the known redeemscript (only if \"script\" is \"multisig\")\n" + " [\n" + " \"pubkey\"\n" + " ,...\n" + " ]\n" + " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n" + " \"pubkey\" : \"publickeyhex\", (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n" + " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdmasterkeyid\") and relation to the wallet (\"ismine\", \"iswatchonly\", \"account\").\n" + " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" + " \"account\" : \"account\" (string) The account associated with the address, \"\" is the default account\n" + " \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n" + " \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n" + " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + + HelpExampleRpc("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + ); + } + + LOCK(pwallet->cs_wallet); + + UniValue ret(UniValue::VOBJ); + CTxDestination dest = DecodeDestination(request.params[0].get_str()); + + // Make sure the destination is valid + if (!IsValidDestination(dest)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + std::string currentAddress = EncodeDestination(dest); + ret.pushKV("address", currentAddress); + + CScript scriptPubKey = GetScriptForDestination(dest); + ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())); + + isminetype mine = IsMine(*pwallet, dest); + ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); + ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)); + UniValue detail = DescribeWalletAddress(pwallet, dest); + ret.pushKVs(detail); + if (pwallet->mapAddressBook.count(dest)) { + ret.pushKV("account", pwallet->mapAddressBook[dest].name); + } + const CKeyMetadata* meta = nullptr; + CKeyID key_id = GetKeyForDestination(*pwallet, dest); + if (!key_id.IsNull()) { + auto it = pwallet->mapKeyMetadata.find(key_id); + if (it != pwallet->mapKeyMetadata.end()) { + meta = &it->second; + } + } + if (!meta) { + auto it = pwallet->m_script_metadata.find(CScriptID(scriptPubKey)); + if (it != pwallet->m_script_metadata.end()) { + meta = &it->second; + } + } + if (meta) { + ret.pushKV("timestamp", meta->nCreateTime); + if (!meta->hdKeypath.empty()) { + ret.pushKV("hdkeypath", meta->hdKeypath); + ret.pushKV("hdmasterkeyid", meta->hdMasterKeyID.GetHex()); + } + } + return ret; +} + extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp extern UniValue importprivkey(const JSONRPCRequest& request); @@ -3513,61 +3801,63 @@ extern UniValue importmulti(const JSONRPCRequest& request); extern UniValue rescanblockchain(const JSONRPCRequest& request); static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, - { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, - { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, - { "wallet", "abortrescan", &abortrescan, {} }, - { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} }, - { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, - { "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","address_type"} }, - { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} }, - { "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"} }, - { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, - - { "generating", "generate", &generate, {"nblocks","maxtries"} }, +{ // category name actor (function) argNames + // --------------------- ------------------------ ----------------------- ---------- + { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, + { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, + { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, + { "wallet", "abortrescan", &abortrescan, {} }, + { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account","address_type"} }, + { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, + { "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", "getaddressinfo", &getaddressinfo, {"address"} }, + { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} }, + { "wallet", "getnewaddress", &getnewaddress, {"account","address_type"} }, + { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} }, + { "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", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} }, + { "wallet", "walletlock", &walletlock, {} }, + { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, + { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} }, + { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, + { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, + + { "generating", "generate", &generate, {"nblocks","maxtries"} }, }; void RegisterWalletRPCCommands(CRPCTable &t) |