Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/rpcwallet.cpp
Show First 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | static UniValue getnewaddress(const Config &config, | ||||
pwallet->LearnRelatedScripts(newKey, output_type); | pwallet->LearnRelatedScripts(newKey, output_type); | ||||
CTxDestination dest = GetDestinationForKey(newKey, output_type); | CTxDestination dest = GetDestinationForKey(newKey, output_type); | ||||
pwallet->SetAddressBook(dest, label, "receive"); | pwallet->SetAddressBook(dest, label, "receive"); | ||||
return EncodeDestination(dest, config); | return EncodeDestination(dest, config); | ||||
} | } | ||||
static CTxDestination GetLabelDestination(CWallet *const pwallet, | |||||
const std::string &label, | |||||
bool bForceNew = false) | |||||
EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) { | |||||
CTxDestination dest; | |||||
if (!pwallet->GetLabelDestination(dest, label, bForceNew)) { | |||||
throw JSONRPCError( | |||||
RPC_WALLET_KEYPOOL_RAN_OUT, | |||||
"Error: Keypool ran out, please call keypoolrefill first"); | |||||
} | |||||
return dest; | |||||
} | |||||
static UniValue getaccountaddress(const Config &config, | |||||
const JSONRPCRequest &request) { | |||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | |||||
CWallet *const pwallet = wallet.get(); | |||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | |||||
return NullUniValue; | |||||
} | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"getaccountaddress (Deprecated, will be removed in v0.21. To " | |||||
"use this command, start bitcoind with " | |||||
"-deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"getaccountaddress is deprecated and will be removed in v0.21. To " | |||||
"use this command, start bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() != 1) { | |||||
throw std::runtime_error( | |||||
"getaccountaddress \"account\"\n" | |||||
"\n\nDEPRECATED. Returns the current Bitcoin address for receiving" | |||||
"payments to this account.\n" | |||||
"\nArguments:\n" | |||||
"1. \"account\" (string, required) The account for the " | |||||
"address. It can also be set to the empty string \"\" to represent " | |||||
"the default account. The account does not need to exist, it will " | |||||
"be created and a new address created if there is no account by " | |||||
"the given name.\n" | |||||
"\nResult:\n" | |||||
"\"address\" (string) The account bitcoin address\n" | |||||
"\nExamples:\n" + | |||||
HelpExampleCli("getaccountaddress", "") + | |||||
HelpExampleCli("getaccountaddress", "\"\"") + | |||||
HelpExampleCli("getaccountaddress", "\"myaccount\"") + | |||||
HelpExampleRpc("getaccountaddress", "\"myaccount\"")); | |||||
} | |||||
auto locked_chain = pwallet->chain().lock(); | |||||
LOCK(pwallet->cs_wallet); | |||||
// Parse the account first so we don't generate a key if there's an error | |||||
std::string account = LabelFromValue(request.params[0]); | |||||
UniValue ret(UniValue::VSTR); | |||||
ret = EncodeDestination(GetLabelDestination(pwallet, account), config); | |||||
return ret; | |||||
} | |||||
static UniValue getrawchangeaddress(const Config &config, | static UniValue getrawchangeaddress(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
static UniValue setlabel(const Config &config, const JSONRPCRequest &request) { | static UniValue setlabel(const Config &config, const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts") && | |||||
request.strMethod == "setaccount") { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"setaccount (Deprecated, will be removed in v0.21. To use this " | |||||
"command, start bitcoind with -deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"setaccount is deprecated and will be removed in v0.21. To use " | |||||
"this command, start bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() != 2) { | if (request.fHelp || request.params.size() != 2) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"setlabel \"address\" \"label\"\n" | "setlabel \"address\" \"label\"\n" | ||||
"\nSets the label associated with the given address.\n" | "\nSets the label associated with the given address.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"address\" (string, required) The bitcoin address to " | "1. \"address\" (string, required) The bitcoin address to " | ||||
"be associated with a label.\n" | "be associated with a label.\n" | ||||
"2. \"label\" (string, required) The label to assign to " | "2. \"label\" (string, required) The label to assign to " | ||||
Show All 14 Lines | if (!IsValidDestination(dest)) { | ||||
"Invalid Bitcoin address"); | "Invalid Bitcoin address"); | ||||
} | } | ||||
std::string old_label = pwallet->mapAddressBook[dest].name; | std::string old_label = pwallet->mapAddressBook[dest].name; | ||||
std::string label = LabelFromValue(request.params[1]); | std::string label = LabelFromValue(request.params[1]); | ||||
if (IsMine(*pwallet, dest)) { | if (IsMine(*pwallet, dest)) { | ||||
pwallet->SetAddressBook(dest, label, "receive"); | pwallet->SetAddressBook(dest, label, "receive"); | ||||
if (request.strMethod == "setaccount" && old_label != label && | |||||
dest == GetLabelDestination(pwallet, old_label)) { | |||||
// for setaccount, call GetLabelDestination so a new receive address | |||||
// is created for the old account | |||||
GetLabelDestination(pwallet, old_label, true); | |||||
} | |||||
} else { | } else { | ||||
pwallet->SetAddressBook(dest, label, "send"); | pwallet->SetAddressBook(dest, label, "send"); | ||||
} | } | ||||
// Detect when there are no addresses using this label. | // Detect when there are no addresses using this label. | ||||
// If so, delete the account record for it. Labels, unlike addresses, can be | // If so, delete the account record for it. Labels, unlike addresses, can be | ||||
// deleted, and if we wouldn't do this, the record would stick around | // deleted, and if we wouldn't do this, the record would stick around | ||||
// forever. | // forever. | ||||
bool found_address = false; | bool found_address = false; | ||||
for (const std::pair<const CTxDestination, CAddressBookData> &item : | for (const std::pair<const CTxDestination, CAddressBookData> &item : | ||||
pwallet->mapAddressBook) { | pwallet->mapAddressBook) { | ||||
if (item.second.name == label) { | if (item.second.name == label) { | ||||
found_address = true; | found_address = true; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (!found_address) { | if (!found_address) { | ||||
pwallet->DeleteLabel(old_label); | pwallet->DeleteLabel(old_label); | ||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
static UniValue getaccount(const Config &config, | |||||
const JSONRPCRequest &request) { | |||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | |||||
CWallet *const pwallet = wallet.get(); | |||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | |||||
return NullUniValue; | |||||
} | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"getaccount (Deprecated, will be removed in v0.21. To use this " | |||||
"command, start bitcoind with -deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"getaccount is deprecated and will be removed in v0.21. To use " | |||||
"this command, start bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() != 1) { | |||||
throw std::runtime_error( | |||||
"getaccount \"address\"\n" | |||||
"\nDEPRECATED. Returns the account associated with the given " | |||||
"address.\n" | |||||
"\nArguments:\n" | |||||
"1. \"address\" (string, required) The bitcoin address for " | |||||
"account lookup.\n" | |||||
"\nResult:\n" | |||||
"\"accountname\" (string) the account address\n" | |||||
"\nExamples:\n" + | |||||
HelpExampleCli("getaccount", | |||||
"\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") + | |||||
HelpExampleRpc("getaccount", | |||||
"\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"")); | |||||
} | |||||
auto locked_chain = pwallet->chain().lock(); | |||||
LOCK(pwallet->cs_wallet); | |||||
CTxDestination dest = | |||||
DecodeDestination(request.params[0].get_str(), config.GetChainParams()); | |||||
if (!IsValidDestination(dest)) { | |||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | |||||
"Invalid Bitcoin address"); | |||||
} | |||||
std::string strAccount; | |||||
std::map<CTxDestination, CAddressBookData>::iterator mi = | |||||
pwallet->mapAddressBook.find(dest); | |||||
if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) { | |||||
strAccount = (*mi).second.name; | |||||
} | |||||
return strAccount; | |||||
} | |||||
static UniValue getaddressesbyaccount(const Config &config, | |||||
const JSONRPCRequest &request) { | |||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | |||||
CWallet *const pwallet = wallet.get(); | |||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | |||||
return NullUniValue; | |||||
} | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"getaddressbyaccount (Deprecated, will be removed in v0.21. To " | |||||
"use this command, start bitcoind with " | |||||
"-deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError(RPC_METHOD_DEPRECATED, | |||||
"getaddressesbyaccount is deprecated and will be " | |||||
"removed in v0.21. To use this command, start " | |||||
"bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() != 1) { | |||||
throw std::runtime_error( | |||||
"getaddressesbyaccount \"account\"\n" | |||||
"\nDEPRECATED. Returns the list of addresses for the given " | |||||
"account.\n" | |||||
"\nArguments:\n" | |||||
"1. \"account\" (string, required) The account name.\n" | |||||
"\nResult:\n" | |||||
"[ (json array of string)\n" | |||||
" \"address\" (string) a bitcoin address associated with " | |||||
"the given account\n" | |||||
" ,...\n" | |||||
"]\n" | |||||
"\nExamples:\n" + | |||||
HelpExampleCli("getaddressesbyaccount", "\"tabby\"") + | |||||
HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")); | |||||
} | |||||
auto locked_chain = pwallet->chain().lock(); | |||||
LOCK(pwallet->cs_wallet); | |||||
std::string strAccount = LabelFromValue(request.params[0]); | |||||
// Find all addresses that have the given account | |||||
UniValue ret(UniValue::VARR); | |||||
for (const std::pair<const CTxDestination, CAddressBookData> &item : | |||||
pwallet->mapAddressBook) { | |||||
const CTxDestination &dest = item.first; | |||||
const std::string &strName = item.second.name; | |||||
if (strName == strAccount) { | |||||
ret.push_back(EncodeDestination(dest, config)); | |||||
} | |||||
} | |||||
return ret; | |||||
} | |||||
static CTransactionRef SendMoney(interfaces::Chain::Lock &locked_chain, | static CTransactionRef SendMoney(interfaces::Chain::Lock &locked_chain, | ||||
CWallet *const pwallet, | CWallet *const pwallet, | ||||
const CTxDestination &address, Amount nValue, | const CTxDestination &address, Amount nValue, | ||||
bool fSubtractFeeFromAmount, | bool fSubtractFeeFromAmount, | ||||
mapValue_t mapValue, std::string fromAccount) { | mapValue_t mapValue) { | ||||
Amount curBalance = pwallet->GetBalance(); | Amount curBalance = pwallet->GetBalance(); | ||||
// Check amount | // Check amount | ||||
if (nValue <= Amount::zero()) { | if (nValue <= Amount::zero()) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); | ||||
} | } | ||||
if (nValue > curBalance) { | if (nValue > curBalance) { | ||||
Show All 27 Lines | if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, reservekey, | ||||
strError = strprintf("Error: This transaction requires a " | strError = strprintf("Error: This transaction requires a " | ||||
"transaction fee of at least %s", | "transaction fee of at least %s", | ||||
FormatMoney(nFeeRequired)); | FormatMoney(nFeeRequired)); | ||||
} | } | ||||
throw JSONRPCError(RPC_WALLET_ERROR, strError); | throw JSONRPCError(RPC_WALLET_ERROR, strError); | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, | if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, | ||||
std::move(fromAccount), reservekey, | "" /* account */, reservekey, | ||||
g_connman.get(), state)) { | g_connman.get(), state)) { | ||||
strError = | strError = | ||||
strprintf("Error: The transaction was rejected! Reason given: %s", | strprintf("Error: The transaction was rejected! Reason given: %s", | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
throw JSONRPCError(RPC_WALLET_ERROR, strError); | throw JSONRPCError(RPC_WALLET_ERROR, strError); | ||||
} | } | ||||
return tx; | return tx; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | static UniValue sendtoaddress(const Config &config, | ||||
bool fSubtractFeeFromAmount = false; | bool fSubtractFeeFromAmount = false; | ||||
if (!request.params[4].isNull()) { | if (!request.params[4].isNull()) { | ||||
fSubtractFeeFromAmount = request.params[4].get_bool(); | fSubtractFeeFromAmount = request.params[4].get_bool(); | ||||
} | } | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
CTransactionRef tx = | CTransactionRef tx = SendMoney(*locked_chain, pwallet, dest, nAmount, | ||||
SendMoney(*locked_chain, pwallet, dest, nAmount, fSubtractFeeFromAmount, | fSubtractFeeFromAmount, std::move(mapValue)); | ||||
std::move(mapValue), {} /* fromAccount */); | |||||
return tx->GetId().GetHex(); | return tx->GetId().GetHex(); | ||||
} | } | ||||
static UniValue listaddressgroupings(const Config &config, | static UniValue listaddressgroupings(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
▲ Show 20 Lines • Show All 230 Lines • ▼ Show 20 Lines | static UniValue getreceivedbylabel(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts") && | |||||
request.strMethod == "getreceivedbyaccount") { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"getreceivedbyaccount (Deprecated, will be removed in v0.21. " | |||||
"To use this command, start bitcoind with " | |||||
"-deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError(RPC_METHOD_DEPRECATED, | |||||
"getreceivedbyaccount is deprecated and will be " | |||||
"removed in v0.21. To use this command, start " | |||||
"bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() < 1 || | if (request.fHelp || request.params.size() < 1 || | ||||
request.params.size() > 2) { | request.params.size() > 2) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"getreceivedbylabel \"label\" ( minconf )\n" | "getreceivedbylabel \"label\" ( minconf )\n" | ||||
"\nReturns the total amount received by addresses with <label> in " | "\nReturns the total amount received by addresses with <label> in " | ||||
"transactions with at least [minconf] confirmations.\n" | "transactions with at least [minconf] confirmations.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"label\" (string, required) The selected label, may be " | "1. \"label\" (string, required) The selected label, may be " | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | static UniValue getbalance(const Config &config, | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (request.fHelp || (request.params.size() > 3)) { | if (request.fHelp || (request.params.size() > 3)) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
(IsDeprecatedRPCEnabled(gArgs, "accounts") | |||||
? std::string( | |||||
"getbalance ( \"account\" minconf include_watchonly )\n" | |||||
"\nIf account is not specified, returns the server's " | |||||
"total available balance.\n" | |||||
"The available balance is what the wallet considers " | |||||
"currently spendable,\nand is thus affected by options " | |||||
"which limit spendability such as " | |||||
"-spendzeroconfchange.\n" | |||||
"If account is specified (DEPRECATED), returns the " | |||||
"balance in the account.\n" | |||||
"Note that the account \"\" is not the same as leaving " | |||||
"the parameter out.\nThe server total may be different " | |||||
"to the balance in the default " | |||||
"\"\" account.\n" | |||||
"\nArguments:\n" | |||||
"1. \"account\" (string, optional) DEPRECATED. " | |||||
"This argument will be removed in v0.21. \n" | |||||
" To use this deprecated argument, " | |||||
"start bitcoind with -deprecatedrpc=accounts. The " | |||||
"account string may be given as a\n" | |||||
" specific account name to find the " | |||||
"balance associated with wallet keys in\n" | |||||
" a named account, or as the empty " | |||||
"string (\"\") to find the balance\n" | |||||
" associated with wallet keys not " | |||||
"in any named account, or as \"*\" to find\n" | |||||
" the balance associated with all " | |||||
"wallet keys regardless of account.\n" | |||||
" When this option is specified, it " | |||||
"calculates the balance in a different\n" | |||||
" way than when it is not " | |||||
"specified, and which can count spends twice when\n" | |||||
" there are conflicting pending " | |||||
"transactions temporarily resulting in low\n" | |||||
" or even negative balances.\n" | |||||
" In general, account balance " | |||||
"calculation is not considered reliable and\n" | |||||
" has resulted in confusing " | |||||
"outcomes, so it is recommended to avoid passing\n" | |||||
" this argument.\n" | |||||
"2. minconf (numeric, optional) Only include " | |||||
"transactions confirmed at least this many times. \n" | |||||
" The default is 1 if an account is " | |||||
"provided or 0 if no account is provided\n") | |||||
: std::string( | |||||
"getbalance ( \"dummy\" minconf include_watchonly )\n" | "getbalance ( \"dummy\" minconf include_watchonly )\n" | ||||
"\nReturns the total available balance.\n" | "\nReturns the total available balance.\n" | ||||
"The available balance is what the wallet considers " | "The available balance is what the wallet considers " | ||||
"currently spendable, and is\n" | "currently spendable, and is\n" | ||||
"thus affected by options which limit spendability such " | "thus affected by options which limit spendability such " | ||||
"as -spendzeroconfchange.\n" | "as -spendzeroconfchange.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. (dummy) (string, optional) Remains for " | "1. (dummy) (string, optional) Remains for " | ||||
"backward compatibility. Must be excluded or set to " | "backward compatibility. Must be excluded or set to " | ||||
"\"*\".\n" | "\"*\".\n" | ||||
"2. minconf (numeric, optional, default=0) " | "2. minconf (numeric, optional, default=0) " | ||||
"Only include transactions confirmed at least this many " | "Only include transactions confirmed at least this many " | ||||
"times.\n")) + | "times.\n" | ||||
"3. include_watchonly (bool, optional, default=false) Also include " | "3. include_watchonly (bool, optional, default=false) Also include " | ||||
"balance in watch-only addresses (see 'importaddress')\n" | "balance in watch-only addresses (see 'importaddress')\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"amount (numeric) The total amount in " + | "amount (numeric) The total amount in " + | ||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
" received for this account.\n" | " received for this wallet.\n" | ||||
"\nExamples:\n" | "\nExamples:\n" | ||||
"\nThe total amount in the wallet with 1 or more confirmations\n" + | "\nThe total amount in the wallet with 1 or more confirmations\n" + | ||||
HelpExampleCli("getbalance", "") + | HelpExampleCli("getbalance", "") + | ||||
"\nThe total amount in the wallet at least 6 blocks confirmed\n" + | "\nThe total amount in the wallet at least 6 blocks confirmed\n" + | ||||
HelpExampleCli("getbalance", "\"*\" 6") + "\nAs a json rpc call\n" + | HelpExampleCli("getbalance", "\"*\" 6") + "\nAs a json rpc call\n" + | ||||
HelpExampleRpc("getbalance", "\"*\", 6")); | HelpExampleRpc("getbalance", "\"*\", 6")); | ||||
} | } | ||||
// Make sure the results are valid at least up to the most recent block | // 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 | // the user could have gotten from another RPC command prior to now | ||||
pwallet->BlockUntilSyncedToCurrentChain(); | pwallet->BlockUntilSyncedToCurrentChain(); | ||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
const UniValue &account_value = request.params[0]; | const UniValue &dummy_value = request.params[0]; | ||||
if (!dummy_value.isNull() && dummy_value.get_str() != "*") { | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"dummy first argument must be excluded or set to \"*\"."); | |||||
} | |||||
int min_depth = 0; | int min_depth = 0; | ||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts") && !account_value.isNull()) { | |||||
// Default min_depth to 1 when an account is provided. | |||||
min_depth = 1; | |||||
} | |||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
min_depth = request.params[1].get_int(); | min_depth = request.params[1].get_int(); | ||||
} | } | ||||
isminefilter filter = ISMINE_SPENDABLE; | isminefilter filter = ISMINE_SPENDABLE; | ||||
if (!request.params[2].isNull() && request.params[2].get_bool()) { | if (!request.params[2].isNull() && request.params[2].get_bool()) { | ||||
filter = filter | ISMINE_WATCH_ONLY; | filter = filter | ISMINE_WATCH_ONLY; | ||||
} | } | ||||
if (!account_value.isNull()) { | |||||
const std::string &account_param = account_value.get_str(); | |||||
const std::string *account = | |||||
account_param != "*" ? &account_param : nullptr; | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts") && | |||||
account_param != "*") { | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"dummy first argument must be excluded or set to \"*\"."); | |||||
} else if (IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
return ValueFromAmount( | |||||
pwallet->GetLegacyBalance(filter, min_depth, account)); | |||||
} | |||||
} | |||||
return ValueFromAmount(pwallet->GetBalance(filter, min_depth)); | return ValueFromAmount(pwallet->GetBalance(filter, min_depth)); | ||||
} | } | ||||
static UniValue getunconfirmedbalance(const Config &config, | static UniValue getunconfirmedbalance(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
Show All 12 Lines | static UniValue getunconfirmedbalance(const Config &config, | ||||
pwallet->BlockUntilSyncedToCurrentChain(); | pwallet->BlockUntilSyncedToCurrentChain(); | ||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
return ValueFromAmount(pwallet->GetUnconfirmedBalance()); | return ValueFromAmount(pwallet->GetUnconfirmedBalance()); | ||||
} | } | ||||
static UniValue movecmd(const Config &config, const JSONRPCRequest &request) { | static UniValue sendmany(const Config &config, const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | if (request.fHelp || request.params.size() < 2 || | ||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"move (Deprecated, will be removed in v0.21. To use this " | |||||
"command, start bitcoind with -deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"move is deprecated and will be removed in v0.21. To use this " | |||||
"command, start bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() < 3 || | |||||
request.params.size() > 5) { | request.params.size() > 5) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" " | "sendmany \"dummy\" {\"address\":amount,...} ( minconf \"comment\" " | ||||
")\n" | "[\"address\",...] )\n" | ||||
"\nDEPRECATED. Move a specified amount from one account in your " | |||||
"wallet to another.\n" | |||||
"\nArguments:\n" | |||||
"1. \"fromaccount\" (string, required) The name of the account " | |||||
"to move funds from. May be the default account using \"\".\n" | |||||
"2. \"toaccount\" (string, required) The name of the account " | |||||
"to move funds to. May be the default account using \"\".\n" | |||||
"3. amount (numeric) Quantity of " + | |||||
CURRENCY_UNIT + | |||||
" to move between accounts.\n" | |||||
"4. (dummy) (numeric, optional) Ignored. Remains for " | |||||
"backward compatibility.\n" | |||||
"5. \"comment\" (string, optional) An optional comment, " | |||||
"stored in the wallet only.\n" | |||||
"\nResult:\n" | |||||
"true|false (boolean) true if successful.\n" | |||||
"\nExamples:\n" | |||||
"\nMove 0.01 " + | |||||
CURRENCY_UNIT + | |||||
" from the default account to the account named tabby\n" + | |||||
HelpExampleCli("move", "\"\" \"tabby\" 0.01") + "\nMove 0.01 " + | |||||
CURRENCY_UNIT + | |||||
" timotei to akiko with a comment and funds have 6 " | |||||
"confirmations\n" + | |||||
HelpExampleCli("move", | |||||
"\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") + | |||||
"\nAs a json rpc call\n" + | |||||
HelpExampleRpc( | |||||
"move", | |||||
"\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")); | |||||
} | |||||
auto locked_chain = pwallet->chain().lock(); | |||||
LOCK(pwallet->cs_wallet); | |||||
std::string strFrom = LabelFromValue(request.params[0]); | |||||
std::string strTo = LabelFromValue(request.params[1]); | |||||
Amount nAmount = AmountFromValue(request.params[2]); | |||||
if (nAmount <= Amount::zero()) { | |||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); | |||||
} | |||||
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[4].isNull()) { | |||||
strComment = request.params[4].get_str(); | |||||
} | |||||
if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) { | |||||
throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); | |||||
} | |||||
return true; | |||||
} | |||||
static UniValue sendfrom(const Config &config, const JSONRPCRequest &request) { | |||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | |||||
CWallet *const pwallet = wallet.get(); | |||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | |||||
return NullUniValue; | |||||
} | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"sendfrom (Deprecated, will be removed in V0.21. To use this " | |||||
"command, start bitcoind with -deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"sendfrom is deprecated and will be removed in V0.21. To use this " | |||||
"command, start bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() < 3 || | |||||
request.params.size() > 6) { | |||||
throw std::runtime_error( | |||||
"sendfrom \"fromaccount\" \"toaddress\" amount ( minconf " | |||||
"\"comment\" \"comment_to\" )\n" | |||||
"\nDEPRECATED (use sendtoaddress). Sent an amount from an account " | |||||
"to a bitcoin address." + | |||||
HelpRequiringPassphrase(pwallet) + | |||||
"\n" | |||||
"\nArguments:\n" | |||||
"1. \"fromaccount\" (string, required) The name of the " | |||||
"account to send funds from. May be the default account using " | |||||
"\"\".\n" | |||||
" Specifying an account does not influence " | |||||
"coin selection, but it does associate the newly created\n" | |||||
" transaction with the account, so the " | |||||
"account's balance computation and transaction history can " | |||||
"reflect\n" | |||||
" the spend.\n" | |||||
"2. \"toaddress\" (string, required) The bitcoin address " | |||||
"to send funds to.\n" | |||||
"3. amount (numeric or string, required) The amount " | |||||
"in " + | |||||
CURRENCY_UNIT + | |||||
" (transaction fee is added on top).\n" | |||||
"4. minconf (numeric, optional, default=1) Only use " | |||||
"funds with at least this many confirmations.\n" | |||||
"5. \"comment\" (string, optional) A comment used to " | |||||
"store what the transaction is for. \n" | |||||
" This is not part of the " | |||||
"transaction, just kept in your wallet.\n" | |||||
"6. \"comment_to\" (string, optional) An optional comment " | |||||
"to store the name of the person or organization \n" | |||||
" to which you're sending the " | |||||
"transaction. This is not part of the transaction, \n" | |||||
" it is just kept in your " | |||||
"wallet.\n" | |||||
"\nResult:\n" | |||||
"\"txid\" (string) The transaction id.\n" | |||||
"\nExamples:\n" | |||||
"\nSend 0.01 " + | |||||
CURRENCY_UNIT + | |||||
" from the default account to the address, must have at least 1 " | |||||
"confirmation\n" + | |||||
HelpExampleCli("sendfrom", | |||||
"\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") + | |||||
"\nSend 0.01 from the tabby account to the given address, funds " | |||||
"must have at least 6 confirmations\n" + | |||||
HelpExampleCli("sendfrom", | |||||
"\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" " | |||||
"0.01 6 \"donation\" \"seans outpost\"") + | |||||
"\nAs a json rpc call\n" + | |||||
HelpExampleRpc("sendfrom", | |||||
"\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", " | |||||
"0.01, 6, \"donation\", \"seans outpost\"")); | |||||
} | |||||
// 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 | |||||
pwallet->BlockUntilSyncedToCurrentChain(); | |||||
auto locked_chain = pwallet->chain().lock(); | |||||
LOCK(pwallet->cs_wallet); | |||||
std::string label = LabelFromValue(request.params[0]); | |||||
CTxDestination dest = | |||||
DecodeDestination(request.params[1].get_str(), config.GetChainParams()); | |||||
if (!IsValidDestination(dest)) { | |||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | |||||
"Invalid Bitcoin address"); | |||||
} | |||||
Amount nAmount = AmountFromValue(request.params[2]); | |||||
if (nAmount <= Amount::zero()) { | |||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); | |||||
} | |||||
int nMinDepth = 1; | |||||
if (!request.params[3].isNull()) { | |||||
nMinDepth = request.params[3].get_int(); | |||||
} | |||||
mapValue_t mapValue; | |||||
if (!request.params[4].isNull() && !request.params[4].get_str().empty()) { | |||||
mapValue["comment"] = request.params[4].get_str(); | |||||
} | |||||
if (!request.params[5].isNull() && !request.params[5].get_str().empty()) { | |||||
mapValue["to"] = request.params[5].get_str(); | |||||
} | |||||
EnsureWalletIsUnlocked(pwallet); | |||||
// Check funds | |||||
Amount nBalance = | |||||
pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &label); | |||||
if (nAmount > nBalance) { | |||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, | |||||
"Account has insufficient funds"); | |||||
} | |||||
CTransactionRef tx = SendMoney(*locked_chain, pwallet, dest, nAmount, false, | |||||
std::move(mapValue), std::move(label)); | |||||
return tx->GetId().GetHex(); | |||||
} | |||||
static UniValue sendmany(const Config &config, const JSONRPCRequest &request) { | |||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | |||||
CWallet *const pwallet = wallet.get(); | |||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | |||||
return NullUniValue; | |||||
} | |||||
std::string help_text; | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
help_text = | |||||
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf " | |||||
"\"comment\" [\"address\",...] )\n" | |||||
"\nSend multiple times. Amounts are double-precision floating " | "\nSend multiple times. Amounts are double-precision floating " | ||||
"point numbers.\n" | "point numbers.\n" + | ||||
"Note that the \"fromaccount\" argument has been removed in V0.20. " | |||||
"To use this RPC with a \"fromaccount\" argument, restart\n" | |||||
"bitcoind with -deprecatedrpc=accounts\n" + | |||||
HelpRequiringPassphrase(pwallet) + | HelpRequiringPassphrase(pwallet) + | ||||
"\n" | "\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"dummy\" (string, required) Must be set to \"\" " | "1. \"dummy\" (string, required) Must be set to \"\" " | ||||
"for backwards compatibility.\n" | "for backwards compatibility.\n" | ||||
"2. \"amounts\" (string, required) A json object with " | "2. \"amounts\" (string, required) A json object with " | ||||
"addresses and amounts\n" | "addresses and amounts\n" | ||||
" {\n" | " {\n" | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() < 2 || | ||||
"1 \"\" " | "1 \"\" " | ||||
"\"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\"," | "\"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\"," | ||||
"\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") + | "\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") + | ||||
"\nAs a json rpc call\n" + | "\nAs a json rpc call\n" + | ||||
HelpExampleRpc("sendmany", | HelpExampleRpc("sendmany", | ||||
"\"\", " | "\"\", " | ||||
"\"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01," | "\"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01," | ||||
"\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"," | "\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"," | ||||
" 6, \"testing\""); | " 6, \"testing\"")); | ||||
} else { | |||||
help_text = | |||||
"sendmany \"\" \"fromaccount\" {\"address\":amount,...} ( " | |||||
"minconf \"comment\" [\"address\",...])\n" | |||||
"\nSend multiple times. Amounts are double-precision floating " | |||||
"point numbers." + | |||||
HelpRequiringPassphrase(pwallet) + | |||||
"\n" | |||||
"\nArguments:\n" | |||||
"1. \"fromaccount\" (string, required) DEPRECATED. The " | |||||
"account to send the funds from. Should be \"\" for the default " | |||||
"account\n" | |||||
"2. \"amounts\" (string, required) A json object with " | |||||
"addresses and amounts\n" | |||||
" {\n" | |||||
" \"address\":amount (numeric or string) The bitcoin " | |||||
"address is the key, the numeric amount (can be string) in " + | |||||
CURRENCY_UNIT + | |||||
" is the value\n" | |||||
" ,...\n" | |||||
" }\n" | |||||
"3. minconf (numeric, optional, default=1) Only " | |||||
"use the balance confirmed at least this many times.\n" | |||||
"4. \"comment\" (string, optional) A comment\n" | |||||
"5. subtractfeefrom (array, optional) A json array with " | |||||
"addresses.\n" | |||||
" The fee will be equally deducted from " | |||||
"the amount of each selected address.\n" | |||||
" Those recipients will receive less " | |||||
"bitcoins than you enter in their corresponding amount field.\n" | |||||
" If no addresses are specified here, " | |||||
"the sender pays the fee.\n" | |||||
" [\n" | |||||
" \"address\" (string) Subtract fee from this " | |||||
"address\n" | |||||
" ,...\n" | |||||
" ]\n" | |||||
"\nResult:\n" | |||||
"\"txid\" (string) The transaction id for the " | |||||
"send. Only 1 transaction is created regardless of \n" | |||||
" the number of addresses.\n" | |||||
"\nExamples:\n" | |||||
"\nSend two amounts to two different addresses:\n" + | |||||
HelpExampleCli("sendmany", | |||||
"\"\" " | |||||
"\"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01," | |||||
"\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}" | |||||
"\"") + | |||||
"\nSend two amounts to two different addresses setting the " | |||||
"confirmation and comment:\n" + | |||||
HelpExampleCli("sendmany", | |||||
"\"\" " | |||||
"\"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01," | |||||
"\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" " | |||||
"6 \"testing\"") + | |||||
"\nSend two amounts to two different addresses, subtract fee from " | |||||
"amount:\n" + | |||||
HelpExampleCli("sendmany", | |||||
"\"\" " | |||||
"\"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01," | |||||
"\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" " | |||||
"1 \"\" " | |||||
"\"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\"," | |||||
"\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") + | |||||
"\nAs a json rpc call\n" + | |||||
HelpExampleRpc("sendmany", | |||||
"\"\", " | |||||
"\"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01," | |||||
"\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"," | |||||
" 6, \"testing\""); | |||||
} | |||||
if (request.fHelp || request.params.size() < 2 || | |||||
request.params.size() > 5) { | |||||
throw std::runtime_error(help_text); | |||||
} | } | ||||
// Make sure the results are valid at least up to the most recent block | // 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 | // the user could have gotten from another RPC command prior to now | ||||
pwallet->BlockUntilSyncedToCurrentChain(); | pwallet->BlockUntilSyncedToCurrentChain(); | ||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
if (pwallet->GetBroadcastTransactions() && !g_connman) { | if (pwallet->GetBroadcastTransactions() && !g_connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts") && | if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { | ||||
!request.params[0].get_str().empty()) { | |||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"Dummy value must be set to \"\""); | "Dummy value must be set to \"\""); | ||||
} | } | ||||
std::string strAccount = LabelFromValue(request.params[0]); | |||||
UniValue sendTo = request.params[1].get_obj(); | UniValue sendTo = request.params[1].get_obj(); | ||||
int nMinDepth = 1; | int nMinDepth = 1; | ||||
if (!request.params[2].isNull()) { | if (!request.params[2].isNull()) { | ||||
nMinDepth = request.params[2].get_int(); | nMinDepth = request.params[2].get_int(); | ||||
} | } | ||||
mapValue_t mapValue; | mapValue_t mapValue; | ||||
if (!request.params[3].isNull() && !request.params[3].get_str().empty()) { | if (!request.params[3].isNull() && !request.params[3].get_str().empty()) { | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | for (const std::string &name_ : keys) { | ||||
CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount}; | CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount}; | ||||
vecSend.push_back(recipient); | vecSend.push_back(recipient); | ||||
} | } | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
// Check funds | // Check funds | ||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts") && | if (totalAmount > | ||||
totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, | pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, nullptr)) { | ||||
&strAccount)) { | |||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, | |||||
"Account has insufficient funds"); | |||||
} else if (!IsDeprecatedRPCEnabled(gArgs, "accounts") && | |||||
totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, | |||||
nMinDepth, nullptr)) { | |||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, | throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, | ||||
"Wallet has insufficient funds"); | "Wallet has insufficient funds"); | ||||
} | } | ||||
// Shuffle recipient list | // Shuffle recipient list | ||||
std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext()); | std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext()); | ||||
// Send | // Send | ||||
CReserveKey keyChange(pwallet); | CReserveKey keyChange(pwallet); | ||||
Amount nFeeRequired = Amount::zero(); | Amount nFeeRequired = Amount::zero(); | ||||
int nChangePosRet = -1; | int nChangePosRet = -1; | ||||
std::string strFailReason; | std::string strFailReason; | ||||
CTransactionRef tx; | CTransactionRef tx; | ||||
CCoinControl coinControl; | CCoinControl coinControl; | ||||
bool fCreated = pwallet->CreateTransaction( | bool fCreated = pwallet->CreateTransaction( | ||||
*locked_chain, vecSend, tx, keyChange, nFeeRequired, nChangePosRet, | *locked_chain, vecSend, tx, keyChange, nFeeRequired, nChangePosRet, | ||||
strFailReason, coinControl); | strFailReason, coinControl); | ||||
if (!fCreated) { | if (!fCreated) { | ||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); | throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, | if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, | ||||
std::move(strAccount), keyChange, | "" /* account */, keyChange, | ||||
g_connman.get(), state)) { | g_connman.get(), state)) { | ||||
strFailReason = strprintf("Transaction commit failed:: %s", | strFailReason = strprintf("Transaction commit failed:: %s", | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); | throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); | ||||
} | } | ||||
return tx->GetId().GetHex(); | return tx->GetId().GetHex(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | for (auto item_it = start; item_it != end; ++item_it) { | ||||
_item.nConf = std::min(_item.nConf, nConf); | _item.nConf = std::min(_item.nConf, nConf); | ||||
_item.fIsWatchonly = fIsWatchonly; | _item.fIsWatchonly = fIsWatchonly; | ||||
} else { | } else { | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
if (fIsWatchonly) { | if (fIsWatchonly) { | ||||
obj.pushKV("involvesWatchonly", true); | obj.pushKV("involvesWatchonly", true); | ||||
} | } | ||||
obj.pushKV("address", EncodeDestination(address, config)); | obj.pushKV("address", EncodeDestination(address, config)); | ||||
obj.pushKV("account", label); | |||||
obj.pushKV("amount", ValueFromAmount(nAmount)); | obj.pushKV("amount", ValueFromAmount(nAmount)); | ||||
obj.pushKV("confirmations", | obj.pushKV("confirmations", | ||||
(nConf == std::numeric_limits<int>::max() ? 0 : nConf)); | (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); | ||||
obj.pushKV("label", label); | obj.pushKV("label", label); | ||||
UniValue transactions(UniValue::VARR); | UniValue transactions(UniValue::VARR); | ||||
if (it != mapTally.end()) { | if (it != mapTally.end()) { | ||||
for (const uint256 &_item : (*it).second.txids) { | for (const uint256 &_item : (*it).second.txids) { | ||||
transactions.push_back(_item.GetHex()); | transactions.push_back(_item.GetHex()); | ||||
} | } | ||||
} | } | ||||
obj.pushKV("txids", transactions); | obj.pushKV("txids", transactions); | ||||
ret.push_back(obj); | ret.push_back(obj); | ||||
} | } | ||||
} | } | ||||
if (by_label) { | if (by_label) { | ||||
for (const auto &entry : label_tally) { | for (const auto &entry : label_tally) { | ||||
Amount nAmount = entry.second.nAmount; | Amount nAmount = entry.second.nAmount; | ||||
int nConf = entry.second.nConf; | int nConf = entry.second.nConf; | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
if (entry.second.fIsWatchonly) { | if (entry.second.fIsWatchonly) { | ||||
obj.pushKV("involvesWatchonly", true); | obj.pushKV("involvesWatchonly", true); | ||||
} | } | ||||
obj.pushKV("account", entry.first); | |||||
obj.pushKV("amount", ValueFromAmount(nAmount)); | obj.pushKV("amount", ValueFromAmount(nAmount)); | ||||
obj.pushKV("confirmations", | obj.pushKV("confirmations", | ||||
(nConf == std::numeric_limits<int>::max() ? 0 : nConf)); | (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); | ||||
obj.pushKV("label", entry.first); | obj.pushKV("label", entry.first); | ||||
ret.push_back(obj); | ret.push_back(obj); | ||||
} | } | ||||
} | } | ||||
Show All 25 Lines | if (request.fHelp || request.params.size() > 4) { | ||||
"information on this address.\n" | "information on this address.\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"[\n" | "[\n" | ||||
" {\n" | " {\n" | ||||
" \"involvesWatchonly\" : true, (bool) Only returned if " | " \"involvesWatchonly\" : true, (bool) Only returned if " | ||||
"imported addresses were involved in transaction\n" | "imported addresses were involved in transaction\n" | ||||
" \"address\" : \"receivingaddress\", (string) The receiving " | " \"address\" : \"receivingaddress\", (string) The receiving " | ||||
"address\n" | "address\n" | ||||
" \"account\" : \"accountname\", (string) DEPRECATED. " | |||||
"Backwards compatible alias for label.\n \"\".\n" | |||||
" \"amount\" : x.xxx, (numeric) The total " | " \"amount\" : x.xxx, (numeric) The total " | ||||
"amount in " + | "amount in " + | ||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
" received by the address\n" | " received by the address\n" | ||||
" \"confirmations\" : n, (numeric) The number of " | " \"confirmations\" : n, (numeric) The number of " | ||||
"confirmations of the most recent transaction included\n" | "confirmations of the most recent transaction included\n" | ||||
" \"label\" : \"label\", (string) The label of " | " \"label\" : \"label\", (string) The label of " | ||||
"the receiving address. The default label is \"\".\n" | "the receiving address. The default label is \"\".\n" | ||||
Show All 29 Lines | static UniValue listreceivedbylabel(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts") && | |||||
request.strMethod == "listreceivedbyaccount") { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"listreceivedbyaccount (Deprecated, will be removed in v0.21. " | |||||
"To use this command, start bitcoind with " | |||||
"-deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError(RPC_METHOD_DEPRECATED, | |||||
"listreceivedbyaccount is deprecated and will be " | |||||
"removed in v0.21. To use this command, start " | |||||
"bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() > 3) { | if (request.fHelp || request.params.size() > 3) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"listreceivedbylabel ( minconf include_empty include_watchonly)\n" | "listreceivedbylabel ( minconf include_empty include_watchonly)\n" | ||||
"\nList received transactions by label.\n" | "\nList received transactions by label.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. minconf (numeric, optional, default=1) The minimum " | "1. minconf (numeric, optional, default=1) The minimum " | ||||
"number of confirmations before payments are included.\n" | "number of confirmations before payments are included.\n" | ||||
"2. include_empty (bool, optional, default=false) Whether to " | "2. include_empty (bool, optional, default=false) Whether to " | ||||
"include labels that haven't received any payments.\n" | "include labels that haven't received any payments.\n" | ||||
"3. include_watchonly (bool, optional, default=false) Whether to " | "3. include_watchonly (bool, optional, default=false) Whether to " | ||||
"include watch-only addresses (see 'importaddress').\n" | "include watch-only addresses (see 'importaddress').\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"[\n" | "[\n" | ||||
" {\n" | " {\n" | ||||
" \"involvesWatchonly\" : true, (bool) Only returned if " | " \"involvesWatchonly\" : true, (bool) Only returned if " | ||||
"imported addresses were involved in transaction\n" | "imported addresses were involved in transaction\n" | ||||
" \"account\" : \"accountname\", (string) DEPRECATED. " | |||||
"Backwards compatible alias for label.\n" | |||||
" \"amount\" : x.xxx, (numeric) The total amount " | " \"amount\" : x.xxx, (numeric) The total amount " | ||||
"received by addresses with this label\n" | "received by addresses with this label\n" | ||||
" \"confirmations\" : n, (numeric) The number of " | " \"confirmations\" : n, (numeric) The number of " | ||||
"confirmations of the most recent transaction included\n" | "confirmations of the most recent transaction included\n" | ||||
" \"label\" : \"label\" (string) The label of the " | " \"label\" : \"label\" (string) The label of the " | ||||
"receiving address. The default label is \"\".\n" | "receiving address. The default label is \"\".\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
Show All 21 Lines | static void MaybePushAddress(UniValue &entry, const CTxDestination &dest) { | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* List transactions based on the given criteria. | * List transactions based on the given criteria. | ||||
* | * | ||||
* @param pwallet The wallet. | * @param pwallet The wallet. | ||||
* @param wtx The wallet transaction. | * @param wtx The wallet transaction. | ||||
* @param strAccount The account, if any, or "*" for all. | |||||
* @param nMinDepth The minimum confirmation depth. | * @param nMinDepth The minimum confirmation depth. | ||||
* @param fLong Whether to include the JSON version of the transaction. | * @param fLong Whether to include the JSON version of the transaction. | ||||
* @param ret The UniValue into which the result is stored. | * @param ret The UniValue into which the result is stored. | ||||
* @param filter The "is mine" filter bool. | * @param filter The "is mine" filter bool. | ||||
*/ | */ | ||||
static void ListTransactions(interfaces::Chain::Lock &locked_chain, | static void ListTransactions(interfaces::Chain::Lock &locked_chain, | ||||
CWallet *const pwallet, const CWalletTx &wtx, | CWallet *const pwallet, const CWalletTx &wtx, | ||||
const std::string &strAccount, int nMinDepth, | int nMinDepth, bool fLong, UniValue &ret, | ||||
bool fLong, UniValue &ret, | |||||
const isminefilter &filter) { | const isminefilter &filter) { | ||||
Amount nFee; | Amount nFee; | ||||
std::string strSentAccount; | std::string dummy_account; | ||||
std::list<COutputEntry> listReceived; | std::list<COutputEntry> listReceived; | ||||
std::list<COutputEntry> listSent; | std::list<COutputEntry> listSent; | ||||
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter); | wtx.GetAmounts(listReceived, listSent, nFee, dummy_account, filter); | ||||
bool fAllAccounts = (strAccount == std::string("*")); | |||||
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); | bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); | ||||
// Sent | // Sent | ||||
if ((!listSent.empty() || nFee != Amount::zero()) && | if (!listSent.empty() || nFee != Amount::zero()) { | ||||
(fAllAccounts || strAccount == strSentAccount)) { | |||||
for (const COutputEntry &s : listSent) { | for (const COutputEntry &s : listSent) { | ||||
UniValue entry(UniValue::VOBJ); | UniValue entry(UniValue::VOBJ); | ||||
if (involvesWatchonly || | if (involvesWatchonly || | ||||
(::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) { | (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) { | ||||
entry.pushKV("involvesWatchonly", true); | entry.pushKV("involvesWatchonly", true); | ||||
} | } | ||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
entry.pushKV("account", strSentAccount); | |||||
} | |||||
MaybePushAddress(entry, s.destination); | MaybePushAddress(entry, s.destination); | ||||
entry.pushKV("category", "send"); | entry.pushKV("category", "send"); | ||||
entry.pushKV("amount", ValueFromAmount(-s.amount)); | entry.pushKV("amount", ValueFromAmount(-s.amount)); | ||||
if (pwallet->mapAddressBook.count(s.destination)) { | if (pwallet->mapAddressBook.count(s.destination)) { | ||||
entry.pushKV("label", | entry.pushKV("label", | ||||
pwallet->mapAddressBook[s.destination].name); | pwallet->mapAddressBook[s.destination].name); | ||||
} | } | ||||
entry.pushKV("vout", s.vout); | entry.pushKV("vout", s.vout); | ||||
entry.pushKV("fee", ValueFromAmount(-1 * nFee)); | entry.pushKV("fee", ValueFromAmount(-1 * nFee)); | ||||
if (fLong) { | if (fLong) { | ||||
WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry); | WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry); | ||||
} | } | ||||
entry.pushKV("abandoned", wtx.isAbandoned()); | entry.pushKV("abandoned", wtx.isAbandoned()); | ||||
ret.push_back(entry); | ret.push_back(entry); | ||||
} | } | ||||
} | } | ||||
// Received | // Received | ||||
if (listReceived.size() > 0 && | if (listReceived.size() > 0 && | ||||
wtx.GetDepthInMainChain(locked_chain) >= nMinDepth) { | wtx.GetDepthInMainChain(locked_chain) >= nMinDepth) { | ||||
for (const COutputEntry &r : listReceived) { | for (const COutputEntry &r : listReceived) { | ||||
std::string account; | std::string label; | ||||
if (pwallet->mapAddressBook.count(r.destination)) { | if (pwallet->mapAddressBook.count(r.destination)) { | ||||
account = pwallet->mapAddressBook[r.destination].name; | label = pwallet->mapAddressBook[r.destination].name; | ||||
} | } | ||||
if (fAllAccounts || (account == strAccount)) { | |||||
UniValue entry(UniValue::VOBJ); | UniValue entry(UniValue::VOBJ); | ||||
if (involvesWatchonly || | if (involvesWatchonly || | ||||
(::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { | (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) { | ||||
entry.pushKV("involvesWatchonly", true); | entry.pushKV("involvesWatchonly", true); | ||||
} | } | ||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
entry.pushKV("account", account); | |||||
} | |||||
MaybePushAddress(entry, r.destination); | MaybePushAddress(entry, r.destination); | ||||
if (wtx.IsCoinBase()) { | if (wtx.IsCoinBase()) { | ||||
if (wtx.GetDepthInMainChain(locked_chain) < 1) { | if (wtx.GetDepthInMainChain(locked_chain) < 1) { | ||||
entry.pushKV("category", "orphan"); | entry.pushKV("category", "orphan"); | ||||
} else if (wtx.IsImmatureCoinBase(locked_chain)) { | } else if (wtx.IsImmatureCoinBase(locked_chain)) { | ||||
entry.pushKV("category", "immature"); | entry.pushKV("category", "immature"); | ||||
} else { | } else { | ||||
entry.pushKV("category", "generate"); | entry.pushKV("category", "generate"); | ||||
} | } | ||||
} else { | } else { | ||||
entry.pushKV("category", "receive"); | entry.pushKV("category", "receive"); | ||||
} | } | ||||
entry.pushKV("amount", ValueFromAmount(r.amount)); | entry.pushKV("amount", ValueFromAmount(r.amount)); | ||||
if (pwallet->mapAddressBook.count(r.destination)) { | if (pwallet->mapAddressBook.count(r.destination)) { | ||||
entry.pushKV("label", account); | entry.pushKV("label", label); | ||||
} | } | ||||
entry.pushKV("vout", r.vout); | entry.pushKV("vout", r.vout); | ||||
if (fLong) { | if (fLong) { | ||||
WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry); | WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry); | ||||
} | } | ||||
ret.push_back(entry); | ret.push_back(entry); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
static void AcentryToJSON(const CAccountingEntry &acentry, | |||||
const std::string &strAccount, UniValue &ret) { | |||||
bool fAllAccounts = (strAccount == std::string("*")); | |||||
if (fAllAccounts || acentry.strAccount == strAccount) { | |||||
UniValue entry(UniValue::VOBJ); | |||||
entry.pushKV("account", acentry.strAccount); | |||||
entry.pushKV("category", "move"); | |||||
entry.pushKV("time", acentry.nTime); | |||||
entry.pushKV("amount", ValueFromAmount(acentry.nCreditDebit)); | |||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
entry.pushKV("otheraccount", acentry.strOtherAccount); | |||||
} | |||||
entry.pushKV("comment", acentry.strComment); | |||||
ret.push_back(entry); | |||||
} | |||||
} | |||||
UniValue listtransactions(const Config &config, const JSONRPCRequest &request) { | UniValue listtransactions(const Config &config, const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
std::string help_text{}; | if (request.fHelp || request.params.size() > 4) { | ||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | throw std::runtime_error( | ||||
help_text = | |||||
"listtransactions ( \"dummy\" count skip include_watchonly)\n" | "listtransactions ( \"dummy\" count skip include_watchonly)\n" | ||||
"\nReturns up to 'count' most recent transactions skipping the " | "\nReturns up to 'count' most recent transactions skipping the " | ||||
"first 'from' transactions for account 'account'.\n" | "first 'from' transactions.\n" | ||||
"Note that the \"account\" argument and \"otheraccount\" return " | |||||
"value have been removed in V0.20. To use this RPC with an " | |||||
"\"account\" argument, restart\n" | |||||
"bitcoind with -deprecatedrpc=accounts\n" | |||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"dummy\" (string, optional) If set, should be \"*\" for " | "1. \"dummy\" (string, optional) If set, should be \"*\" for " | ||||
"backwards compatibility.\n" | "backwards compatibility.\n" | ||||
"2. count (numeric, optional, default=10) The number of " | "2. count (numeric, optional, default=10) The number of " | ||||
"transactions to return\n" | "transactions to return\n" | ||||
"3. skip (numeric, optional, default=0) The number of " | "3. skip (numeric, optional, default=0) The number of " | ||||
"transactions to skip\n" | "transactions to skip\n" | ||||
"4. include_watchonly (bool, optional, default=false) Include " | "4. include_watchonly (bool, optional, default=false) Include " | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() > 4) { | ||||
"]\n" | "]\n" | ||||
"\nExamples:\n" | "\nExamples:\n" | ||||
"\nList the most recent 10 transactions in the systems\n" + | "\nList the most recent 10 transactions in the systems\n" + | ||||
HelpExampleCli("listtransactions", "") + | HelpExampleCli("listtransactions", "") + | ||||
"\nList transactions 100 to 120\n" + | "\nList transactions 100 to 120\n" + | ||||
HelpExampleCli("listtransactions", "\"*\" 20 100") + | HelpExampleCli("listtransactions", "\"*\" 20 100") + | ||||
"\nAs a json rpc call\n" + | "\nAs a json rpc call\n" + | ||||
HelpExampleRpc("listtransactions", "\"*\", 20, 100"); | HelpExampleRpc("listtransactions", "\"*\", 20, 100")); | ||||
} else { | |||||
help_text = | |||||
"listtransactions ( \"account\" count skip include_watchonly)\n" | |||||
"\nReturns up to 'count' most recent transactions skipping the " | |||||
"first 'from' transactions for account 'account'.\n" | |||||
"\nArguments:\n" | |||||
"1. \"account\" (string, optional) DEPRECATED. This argument " | |||||
"will be removed in V0.21. The account name. Should be \"*\".\n" | |||||
"2. count (numeric, optional, default=10) The number of " | |||||
"transactions to return\n" | |||||
"3. skip (numeric, optional, default=0) The number of " | |||||
"transactions to skip\n" | |||||
"4. include_watchonly (bool, optional, default=false) Include " | |||||
"transactions to watch-only addresses (see 'importaddress')\n" | |||||
"\nResult:\n" | |||||
"[\n" | |||||
" {\n" | |||||
" \"account\":\"accountname\", (string) DEPRECATED. This " | |||||
"field will be removed in V0.21. The account name associated with " | |||||
"the transaction. \n" | |||||
" It will be \"\" " | |||||
"for the default account.\n" | |||||
" \"address\":\"address\", (string) The bitcoin address of " | |||||
"the transaction. Not present for \n" | |||||
" move transactions " | |||||
"(category = move).\n" | |||||
" \"category\":\"send|receive|move\", (string) The transaction " | |||||
"category. 'move' is a local (off blockchain)\n" | |||||
" transaction " | |||||
"between accounts, and not associated with an address,\n" | |||||
" transaction id or " | |||||
"block. 'send' and 'receive' transactions are \n" | |||||
" associated with " | |||||
"an address, transaction id and block details\n" | |||||
" \"amount\": x.xxx, (numeric) The amount in " + | |||||
CURRENCY_UNIT + | |||||
". This is negative for the 'send' category, and for the\n" | |||||
" 'move' category for " | |||||
"moves outbound. It is positive for the 'receive' category,\n" | |||||
" and for the 'move' " | |||||
"category for inbound funds.\n" | |||||
" \"label\": \"label\", (string) A comment for the " | |||||
"address/transaction, if any\n" | |||||
" \"vout\": n, (numeric) the vout value\n" | |||||
" \"fee\": x.xxx, (numeric) The amount of the fee " | |||||
"in " + | |||||
CURRENCY_UNIT + | |||||
". This is negative and only available for the \n" | |||||
" 'send' category of " | |||||
"transactions.\n" | |||||
" \"confirmations\": n, (numeric) The number of " | |||||
"confirmations for the transaction. Available for 'send' and \n" | |||||
" 'receive' category of " | |||||
"transactions. Negative confirmations indicate the\n" | |||||
" transaction conflicts " | |||||
"with the block chain\n" | |||||
" \"trusted\": xxx, (bool) Whether we consider the " | |||||
"outputs of this unconfirmed transaction safe to spend.\n" | |||||
" \"blockhash\": \"hashvalue\", (string) The block hash " | |||||
"containing the transaction. Available for 'send' and 'receive'\n" | |||||
" category of " | |||||
"transactions.\n" | |||||
" \"blockindex\": n, (numeric) The index of the " | |||||
"transaction in the block that includes it. Available for 'send' " | |||||
"and 'receive'\n" | |||||
" category of " | |||||
"transactions.\n" | |||||
" \"blocktime\": xxx, (numeric) The block time in " | |||||
"seconds since epoch (1 Jan 1970 GMT).\n" | |||||
" \"txid\": \"transactionid\", (string) The transaction id. " | |||||
"Available for 'send' and 'receive' category of transactions.\n" | |||||
" \"time\": xxx, (numeric) The transaction time in " | |||||
"seconds since epoch (midnight Jan 1 1970 GMT).\n" | |||||
" \"timereceived\": xxx, (numeric) The time received in " | |||||
"seconds since epoch (midnight Jan 1 1970 GMT). Available \n" | |||||
" for 'send' and " | |||||
"'receive' category of transactions.\n" | |||||
" \"comment\": \"...\", (string) If a comment is " | |||||
"associated with the transaction.\n" | |||||
" \"otheraccount\": \"accountname\", (string) DEPRECATED. This " | |||||
"field will be removed in V0.21. For the 'move' category of " | |||||
"transactions, the account the funds came \n" | |||||
" from (for receiving " | |||||
"funds, positive amounts), or went to (for sending funds,\n" | |||||
" negative amounts).\n" | |||||
" \"abandoned\": xxx (bool) 'true' if the transaction " | |||||
"has been abandoned (inputs are respendable). Only available for " | |||||
"the \n" | |||||
" 'send' category of " | |||||
"transactions.\n" | |||||
" }\n" | |||||
"]\n" | |||||
"\nExamples:\n" | |||||
"\nList the most recent 10 transactions in the systems\n" + | |||||
HelpExampleCli("listtransactions", "") + | |||||
"\nList transactions 100 to 120\n" + | |||||
HelpExampleCli("listtransactions", "\"*\" 20 100") + | |||||
"\nAs a json rpc call\n" + | |||||
HelpExampleRpc("listtransactions", "\"*\", 20, 100"); | |||||
} | |||||
if (request.fHelp || request.params.size() > 4) { | |||||
throw std::runtime_error(help_text); | |||||
} | } | ||||
// Make sure the results are valid at least up to the most recent block | // 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 | // the user could have gotten from another RPC command prior to now | ||||
pwallet->BlockUntilSyncedToCurrentChain(); | pwallet->BlockUntilSyncedToCurrentChain(); | ||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
std::string strAccount = "*"; | if (!request.params[0].isNull() && request.params[0].get_str() != "*") { | ||||
if (!request.params[0].isNull()) { | |||||
strAccount = request.params[0].get_str(); | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts") && strAccount != "*") { | |||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"Dummy value must be set to \"*\""); | "Dummy value must be set to \"*\""); | ||||
} | } | ||||
} | |||||
int nCount = 10; | int nCount = 10; | ||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
nCount = request.params[1].get_int(); | nCount = request.params[1].get_int(); | ||||
} | } | ||||
int nFrom = 0; | int nFrom = 0; | ||||
if (!request.params[2].isNull()) { | if (!request.params[2].isNull()) { | ||||
nFrom = request.params[2].get_int(); | nFrom = request.params[2].get_int(); | ||||
Show All 14 Lines | UniValue listtransactions(const Config &config, const JSONRPCRequest &request) { | ||||
const CWallet::TxItems &txOrdered = pwallet->wtxOrdered; | const CWallet::TxItems &txOrdered = pwallet->wtxOrdered; | ||||
// iterate backwards until we have nCount items to return: | // iterate backwards until we have nCount items to return: | ||||
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); | for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); | ||||
it != txOrdered.rend(); ++it) { | it != txOrdered.rend(); ++it) { | ||||
CWalletTx *const pwtx = (*it).second.first; | CWalletTx *const pwtx = (*it).second.first; | ||||
if (pwtx != nullptr) { | if (pwtx != nullptr) { | ||||
ListTransactions(*locked_chain, pwallet, *pwtx, strAccount, 0, true, | ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, | ||||
ret, filter); | filter); | ||||
} | |||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
CAccountingEntry *const pacentry = (*it).second.second; | |||||
if (pacentry != nullptr) { | |||||
AcentryToJSON(*pacentry, strAccount, ret); | |||||
} | |||||
} | } | ||||
if ((int)ret.size() >= (nCount + nFrom)) { | if ((int)ret.size() >= (nCount + nFrom)) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// ret is newest to oldest | // ret is newest to oldest | ||||
Show All 24 Lines | UniValue listtransactions(const Config &config, const JSONRPCRequest &request) { | ||||
ret.clear(); | ret.clear(); | ||||
ret.setArray(); | ret.setArray(); | ||||
ret.push_backV(arrTmp); | ret.push_backV(arrTmp); | ||||
return ret; | return ret; | ||||
} | } | ||||
static UniValue listaccounts(const Config &config, | |||||
const JSONRPCRequest &request) { | |||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | |||||
CWallet *const pwallet = wallet.get(); | |||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | |||||
return NullUniValue; | |||||
} | |||||
if (!IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
if (request.fHelp) { | |||||
throw std::runtime_error( | |||||
"listaccounts (Deprecated, will be removed in v0.21. To use " | |||||
"this command, start bitcoind with -deprecatedrpc=accounts)"); | |||||
} | |||||
throw JSONRPCError( | |||||
RPC_METHOD_DEPRECATED, | |||||
"listaccounts is deprecated and will be removed in v0.21. To use " | |||||
"this command, start bitcoind with -deprecatedrpc=accounts."); | |||||
} | |||||
if (request.fHelp || request.params.size() > 2) { | |||||
throw std::runtime_error( | |||||
"listaccounts ( minconf include_watchonly)\n" | |||||
"\nDEPRECATED. Returns Object that has account names as keys, " | |||||
"account balances as values.\n" | |||||
"\nArguments:\n" | |||||
"1. minconf (numeric, optional, default=1) Only " | |||||
"include transactions with at least this many confirmations\n" | |||||
"2. include_watchonly (bool, optional, default=false) Include " | |||||
"balances in watch-only addresses (see 'importaddress')\n" | |||||
"\nResult:\n" | |||||
"{ (json object where keys are account names, " | |||||
"and values are numeric balances\n" | |||||
" \"account\": x.xxx, (numeric) The property name is the account " | |||||
"name, and the value is the total balance for the account.\n" | |||||
" ...\n" | |||||
"}\n" | |||||
"\nExamples:\n" | |||||
"\nList account balances where there at least 1 confirmation\n" + | |||||
HelpExampleCli("listaccounts", "") + | |||||
"\nList account balances including zero confirmation " | |||||
"transactions\n" + | |||||
HelpExampleCli("listaccounts", "0") + | |||||
"\nList account balances for 6 or more confirmations\n" + | |||||
HelpExampleCli("listaccounts", "6") + "\nAs json rpc call\n" + | |||||
HelpExampleRpc("listaccounts", "6")); | |||||
} | |||||
// 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 | |||||
pwallet->BlockUntilSyncedToCurrentChain(); | |||||
auto locked_chain = pwallet->chain().lock(); | |||||
LOCK(pwallet->cs_wallet); | |||||
int nMinDepth = 1; | |||||
if (!request.params[0].isNull()) { | |||||
nMinDepth = request.params[0].get_int(); | |||||
} | |||||
isminefilter includeWatchonly = ISMINE_SPENDABLE; | |||||
if (!request.params[1].isNull() && request.params[1].get_bool()) { | |||||
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; | |||||
} | |||||
std::map<std::string, Amount> mapAccountBalances; | |||||
for (const std::pair<const CTxDestination, CAddressBookData> &entry : | |||||
pwallet->mapAddressBook) { | |||||
// This address belongs to me | |||||
if (IsMine(*pwallet, entry.first) & includeWatchonly) { | |||||
mapAccountBalances[entry.second.name] = Amount::zero(); | |||||
} | |||||
} | |||||
for (const std::pair<const TxId, CWalletTx> &pairWtx : pwallet->mapWallet) { | |||||
const CWalletTx &wtx = pairWtx.second; | |||||
Amount nFee; | |||||
std::string strSentAccount; | |||||
std::list<COutputEntry> listReceived; | |||||
std::list<COutputEntry> listSent; | |||||
int nDepth = wtx.GetDepthInMainChain(*locked_chain); | |||||
if (wtx.IsImmatureCoinBase(*locked_chain) || nDepth < 0) { | |||||
continue; | |||||
} | |||||
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, | |||||
includeWatchonly); | |||||
mapAccountBalances[strSentAccount] -= nFee; | |||||
for (const COutputEntry &s : listSent) { | |||||
mapAccountBalances[strSentAccount] -= s.amount; | |||||
} | |||||
if (nDepth >= nMinDepth) { | |||||
for (const COutputEntry &r : listReceived) { | |||||
if (pwallet->mapAddressBook.count(r.destination)) { | |||||
mapAccountBalances[pwallet->mapAddressBook[r.destination] | |||||
.name] += r.amount; | |||||
} else { | |||||
mapAccountBalances[""] += r.amount; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
const std::list<CAccountingEntry> &acentries = pwallet->laccentries; | |||||
for (const CAccountingEntry &entry : acentries) { | |||||
mapAccountBalances[entry.strAccount] += entry.nCreditDebit; | |||||
} | |||||
UniValue ret(UniValue::VOBJ); | |||||
for (const std::pair<const std::string, Amount> &accountBalance : | |||||
mapAccountBalances) { | |||||
ret.pushKV(accountBalance.first, | |||||
ValueFromAmount(accountBalance.second)); | |||||
} | |||||
return ret; | |||||
} | |||||
static UniValue listsinceblock(const Config &config, | static UniValue listsinceblock(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
Show All 22 Lines | if (request.fHelp || request.params.size() > 4) { | ||||
"4. include_removed: (bool, optional, default=true) Show " | "4. include_removed: (bool, optional, default=true) Show " | ||||
"transactions that were removed due to a reorg in the \"removed\" " | "transactions that were removed due to a reorg in the \"removed\" " | ||||
"array\n" | "array\n" | ||||
" (not " | " (not " | ||||
"guaranteed to work on pruned nodes)\n" | "guaranteed to work on pruned nodes)\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"{\n" | "{\n" | ||||
" \"transactions\": [\n" | " \"transactions\": [\n" | ||||
" \"account\":\"accountname\", (string) DEPRECATED. This " | |||||
"field will be removed in V0.21. To see this deprecated field, " | |||||
"start bitcoind with -deprecatedrpc=accounts. The " | |||||
"account name associated with the transaction. Will be \"\" for " | |||||
"the default account.\n" | |||||
" \"address\":\"address\", (string) The bitcoin address of " | " \"address\":\"address\", (string) The bitcoin address of " | ||||
"the transaction. Not present for move transactions (category = " | "the transaction. Not present for move transactions (category = " | ||||
"move).\n" | "move).\n" | ||||
" \"category\":\"send|receive\", (string) The transaction " | " \"category\":\"send|receive\", (string) The transaction " | ||||
"category. 'send' has negative amounts, 'receive' has positive " | "category. 'send' has negative amounts, 'receive' has positive " | ||||
"amounts.\n" | "amounts.\n" | ||||
" \"amount\": x.xxx, (numeric) The amount in " + | " \"amount\": x.xxx, (numeric) The amount in " + | ||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | static UniValue listsinceblock(const Config &config, | ||||
int depth = pindex ? (1 + ::ChainActive().Height() - pindex->nHeight) : -1; | int depth = pindex ? (1 + ::ChainActive().Height() - pindex->nHeight) : -1; | ||||
UniValue transactions(UniValue::VARR); | UniValue transactions(UniValue::VARR); | ||||
for (const std::pair<const TxId, CWalletTx> &pairWtx : pwallet->mapWallet) { | for (const std::pair<const TxId, CWalletTx> &pairWtx : pwallet->mapWallet) { | ||||
CWalletTx tx = pairWtx.second; | CWalletTx tx = pairWtx.second; | ||||
if (depth == -1 || tx.GetDepthInMainChain(*locked_chain) < depth) { | if (depth == -1 || tx.GetDepthInMainChain(*locked_chain) < depth) { | ||||
ListTransactions(*locked_chain, pwallet, tx, "*", 0, true, | ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, | ||||
transactions, filter); | filter); | ||||
} | } | ||||
} | } | ||||
const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); | const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); | ||||
// when a reorg'd block is requested, we also list any relevant transactions | // when a reorg'd block is requested, we also list any relevant transactions | ||||
// in the blocks of the chain that was detached | // in the blocks of the chain that was detached | ||||
UniValue removed(UniValue::VARR); | UniValue removed(UniValue::VARR); | ||||
while (include_removed && paltindex && paltindex != pindex) { | while (include_removed && paltindex && paltindex != pindex) { | ||||
CBlock block; | CBlock block; | ||||
if (!ReadBlockFromDisk(block, paltindex, params)) { | if (!ReadBlockFromDisk(block, paltindex, params)) { | ||||
throw JSONRPCError(RPC_INTERNAL_ERROR, | throw JSONRPCError(RPC_INTERNAL_ERROR, | ||||
"Can't read block from disk"); | "Can't read block from disk"); | ||||
} | } | ||||
for (const CTransactionRef &tx : block.vtx) { | for (const CTransactionRef &tx : block.vtx) { | ||||
auto it = pwallet->mapWallet.find(tx->GetId()); | auto it = pwallet->mapWallet.find(tx->GetId()); | ||||
if (it != pwallet->mapWallet.end()) { | if (it != pwallet->mapWallet.end()) { | ||||
// We want all transactions regardless of confirmation count to | // We want all transactions regardless of confirmation count to | ||||
// appear here, even negative confirmation ones, hence the big | // appear here, even negative confirmation ones, hence the big | ||||
// negative. | // negative. | ||||
ListTransactions(*locked_chain, pwallet, it->second, "*", | ListTransactions(*locked_chain, pwallet, it->second, -100000000, | ||||
-100000000, true, removed, filter); | true, removed, filter); | ||||
} | } | ||||
} | } | ||||
paltindex = paltindex->pprev; | paltindex = paltindex->pprev; | ||||
} | } | ||||
CBlockIndex *pblockLast = | CBlockIndex *pblockLast = | ||||
::ChainActive()[::ChainActive().Height() + 1 - target_confirms]; | ::ChainActive()[::ChainActive().Height() + 1 - target_confirms]; | ||||
uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); | uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256(); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() < 1 || | ||||
"seconds since epoch (1 Jan 1970 GMT)\n" | "seconds since epoch (1 Jan 1970 GMT)\n" | ||||
" \"bip125-replaceable\": \"yes|no|unknown\", (string) Whether " | " \"bip125-replaceable\": \"yes|no|unknown\", (string) Whether " | ||||
"this transaction could be replaced due to BIP125 " | "this transaction could be replaced due to BIP125 " | ||||
"(replace-by-fee);\n" | "(replace-by-fee);\n" | ||||
" may be unknown " | " may be unknown " | ||||
"for unconfirmed transactions not in the mempool\n" | "for unconfirmed transactions not in the mempool\n" | ||||
" \"details\" : [\n" | " \"details\" : [\n" | ||||
" {\n" | " {\n" | ||||
" \"account\" : \"accountname\", (string) DEPRECATED. " | |||||
"This field will be removed in a V0.21. To see this deprecated " | |||||
"field, start bitcoind with -deprecatedrpc=accounts. The account " | |||||
"name involved in the transaction, can be \"\" for the default " | |||||
"account.\n" | |||||
" \"address\" : \"address\", (string) The bitcoin " | " \"address\" : \"address\", (string) The bitcoin " | ||||
"address involved in the transaction\n" | "address involved in the transaction\n" | ||||
" \"category\" : \"send|receive\", (string) The category, " | " \"category\" : \"send|receive\", (string) The category, " | ||||
"either 'send' or 'receive'\n" | "either 'send' or 'receive'\n" | ||||
" \"amount\" : x.xxx, (numeric) The amount " | " \"amount\" : x.xxx, (numeric) The amount " | ||||
"in " + | "in " + | ||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
"\n" | "\n" | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | static UniValue gettransaction(const Config &config, | ||||
entry.pushKV("amount", ValueFromAmount(nNet - nFee)); | entry.pushKV("amount", ValueFromAmount(nNet - nFee)); | ||||
if (wtx.IsFromMe(filter)) { | if (wtx.IsFromMe(filter)) { | ||||
entry.pushKV("fee", ValueFromAmount(nFee)); | entry.pushKV("fee", ValueFromAmount(nFee)); | ||||
} | } | ||||
WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry); | WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry); | ||||
UniValue details(UniValue::VARR); | UniValue details(UniValue::VARR); | ||||
ListTransactions(*locked_chain, pwallet, wtx, "*", 0, false, details, | ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter); | ||||
filter); | |||||
entry.pushKV("details", details); | entry.pushKV("details", details); | ||||
std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); | std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags()); | ||||
entry.pushKV("hex", strHex); | entry.pushKV("hex", strHex); | ||||
return entry; | return entry; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,139 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() > 5) { | ||||
"\nResult\n" | "\nResult\n" | ||||
"[ (array of json object)\n" | "[ (array of json object)\n" | ||||
" {\n" | " {\n" | ||||
" \"txid\" : \"txid\", (string) the transaction id \n" | " \"txid\" : \"txid\", (string) the transaction id \n" | ||||
" \"vout\" : n, (numeric) the vout value\n" | " \"vout\" : n, (numeric) the vout value\n" | ||||
" \"address\" : \"address\", (string) the bitcoin address\n" | " \"address\" : \"address\", (string) the bitcoin address\n" | ||||
" \"label\" : \"label\", (string) The associated label, " | " \"label\" : \"label\", (string) The associated label, " | ||||
"or \"\" for the default label\n" | "or \"\" for the default label\n" | ||||
" \"account\" : \"account\", (string) DEPRECATED. This field " | |||||
"will be removed in v0.21. To see this deprecated field, start " | |||||
"bitcoind with -deprecatedrpc=accounts. The associated account, or " | |||||
"\"\" for the default account\n" | |||||
" \"scriptPubKey\" : \"key\", (string) the script key\n" | " \"scriptPubKey\" : \"key\", (string) the script key\n" | ||||
" \"amount\" : x.xxx, (numeric) the transaction output " | " \"amount\" : x.xxx, (numeric) the transaction output " | ||||
"amount in " + | "amount in " + | ||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
"\n" | "\n" | ||||
" \"confirmations\" : n, (numeric) The number of " | " \"confirmations\" : n, (numeric) The number of " | ||||
"confirmations\n" | "confirmations\n" | ||||
" \"redeemScript\" : n (string) The redeemScript if " | " \"redeemScript\" : n (string) The redeemScript if " | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | for (const COutput &out : vecOutputs) { | ||||
entry.pushKV("vout", out.i); | entry.pushKV("vout", out.i); | ||||
if (fValidAddress) { | if (fValidAddress) { | ||||
entry.pushKV("address", EncodeDestination(address, config)); | entry.pushKV("address", EncodeDestination(address, config)); | ||||
auto i = pwallet->mapAddressBook.find(address); | auto i = pwallet->mapAddressBook.find(address); | ||||
if (i != pwallet->mapAddressBook.end()) { | if (i != pwallet->mapAddressBook.end()) { | ||||
entry.pushKV("label", i->second.name); | entry.pushKV("label", i->second.name); | ||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
entry.pushKV("account", i->second.name); | |||||
} | |||||
} | } | ||||
if (scriptPubKey.IsPayToScriptHash()) { | if (scriptPubKey.IsPayToScriptHash()) { | ||||
const CScriptID &hash = boost::get<CScriptID>(address); | const CScriptID &hash = boost::get<CScriptID>(address); | ||||
CScript redeemScript; | CScript redeemScript; | ||||
if (pwallet->GetCScript(hash, redeemScript)) { | if (pwallet->GetCScript(hash, redeemScript)) { | ||||
entry.pushKV("redeemScript", HexStr(redeemScript.begin(), | entry.pushKV("redeemScript", HexStr(redeemScript.begin(), | ||||
redeemScript.end())); | redeemScript.end())); | ||||
▲ Show 20 Lines • Show All 660 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() != 1) { | ||||
" \"pubkey\" : \"publickeyhex\", (string, optional) The hex " | " \"pubkey\" : \"publickeyhex\", (string, optional) The hex " | ||||
"value of the raw public key, for single-key addresses (possibly " | "value of the raw public key, for single-key addresses (possibly " | ||||
"embedded in P2SH or P2WSH)\n" | "embedded in P2SH or P2WSH)\n" | ||||
" \"embedded\" : {...}, (object, optional) Information " | " \"embedded\" : {...}, (object, optional) Information " | ||||
"about the address embedded in P2SH or P2WSH, if relevant and " | "about the address embedded in P2SH or P2WSH, if relevant and " | ||||
"known. It includes all getaddressinfo output fields for the " | "known. It includes all getaddressinfo output fields for the " | ||||
"embedded address, excluding metadata (\"timestamp\", " | "embedded address, excluding metadata (\"timestamp\", " | ||||
"\"hdkeypath\", \"hdseedid\") and relation to the wallet " | "\"hdkeypath\", \"hdseedid\") and relation to the wallet " | ||||
"(\"ismine\", \"iswatchonly\", \"account\").\n" | "(\"ismine\", \"iswatchonly\").\n" | ||||
" \"iscompressed\" : true|false, (boolean) If the address is " | " \"iscompressed\" : true|false, (boolean) If the address is " | ||||
"compressed\n" | "compressed\n" | ||||
" \"label\" : \"label\" (string) The label associated " | " \"label\" : \"label\" (string) The label associated " | ||||
"with the address, \"\" is the default account\n" | "with the address, \"\" is the default label\n" | ||||
" \"account\" : \"account\" (string) DEPRECATED. This " | |||||
"field will be removed in V0.21. To see this deprecated field, " | |||||
"start bitcoind with -deprecatedrpc=accounts. The account " | |||||
"associated with the address, \"\" is the default account\n" | |||||
" \"timestamp\" : timestamp, (number, optional) The creation " | " \"timestamp\" : timestamp, (number, optional) The creation " | ||||
"time of the key if available in seconds since epoch (Jan 1 1970 " | "time of the key if available in seconds since epoch (Jan 1 1970 " | ||||
"GMT)\n" | "GMT)\n" | ||||
" \"hdkeypath\" : \"keypath\" (string, optional) The HD " | " \"hdkeypath\" : \"keypath\" (string, optional) The HD " | ||||
"keypath if the key is HD and available\n" | "keypath if the key is HD and available\n" | ||||
" \"hdseedid\" : \"<hash160>\" (string, optional) The " | " \"hdseedid\" : \"<hash160>\" (string, optional) The " | ||||
"Hash160 of the HD seed\n" | "Hash160 of the HD seed\n" | ||||
" \"hdmasterkeyid\" : \"<hash160>\" (string, optional) alias for " | " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) alias for " | ||||
Show All 37 Lines | UniValue getaddressinfo(const Config &config, const JSONRPCRequest &request) { | ||||
isminetype mine = IsMine(*pwallet, dest); | isminetype mine = IsMine(*pwallet, dest); | ||||
ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); | ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); | ||||
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)); | ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)); | ||||
UniValue detail = DescribeWalletAddress(pwallet, dest); | UniValue detail = DescribeWalletAddress(pwallet, dest); | ||||
ret.pushKVs(detail); | ret.pushKVs(detail); | ||||
if (pwallet->mapAddressBook.count(dest)) { | if (pwallet->mapAddressBook.count(dest)) { | ||||
ret.pushKV("label", pwallet->mapAddressBook[dest].name); | ret.pushKV("label", pwallet->mapAddressBook[dest].name); | ||||
if (IsDeprecatedRPCEnabled(gArgs, "accounts")) { | |||||
ret.pushKV("account", pwallet->mapAddressBook[dest].name); | |||||
} | |||||
} | } | ||||
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey)); | ret.pushKV("ischange", pwallet->IsChange(scriptPubKey)); | ||||
const CKeyMetadata *meta = nullptr; | const CKeyMetadata *meta = nullptr; | ||||
CKeyID key_id = GetKeyForDestination(*pwallet, dest); | CKeyID key_id = GetKeyForDestination(*pwallet, dest); | ||||
if (!key_id.IsNull()) { | if (!key_id.IsNull()) { | ||||
auto it = pwallet->mapKeyMetadata.find(key_id); | auto it = pwallet->mapKeyMetadata.find(key_id); | ||||
if (it != pwallet->mapKeyMetadata.end()) { | if (it != pwallet->mapKeyMetadata.end()) { | ||||
meta = &it->second; | meta = &it->second; | ||||
▲ Show 20 Lines • Show All 566 Lines • ▼ Show 20 Lines | static UniValue walletcreatefundedpsbt(const Config &config, | ||||
result.pushKV("changepos", change_position); | result.pushKV("changepos", change_position); | ||||
return result; | return result; | ||||
} | } | ||||
// clang-format off | // clang-format off | ||||
static const ContextFreeRPCCommand commands[] = { | static const ContextFreeRPCCommand commands[] = { | ||||
// category name actor (function) argNames | // category name actor (function) argNames | ||||
// ------------------- ------------------------ ---------------------- ---------- | // ------------------- ------------------------ ---------------------- ---------- | ||||
{ "rawtransactions", "fundrawtransaction", fundrawtransaction, {"hexstring","options"} }, | { "generating", "generate", generate, {"nblocks","maxtries"} }, | ||||
{ "wallet", "walletprocesspsbt", walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} }, | |||||
{ "wallet", "walletcreatefundedpsbt", walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} }, | |||||
{ "hidden", "resendwallettransactions", resendwallettransactions, {} }, | { "hidden", "resendwallettransactions", resendwallettransactions, {} }, | ||||
{ "rawtransactions", "fundrawtransaction", fundrawtransaction, {"hexstring","options"} }, | |||||
{ "wallet", "abandontransaction", abandontransaction, {"txid"} }, | { "wallet", "abandontransaction", abandontransaction, {"txid"} }, | ||||
{ "wallet", "addmultisigaddress", addmultisigaddress, {"nrequired","keys","label|account"} }, | { "wallet", "addmultisigaddress", addmultisigaddress, {"nrequired","keys","label"} }, | ||||
{ "wallet", "backupwallet", backupwallet, {"destination"} }, | { "wallet", "backupwallet", backupwallet, {"destination"} }, | ||||
{ "wallet", "createwallet", createwallet, {"wallet_name", "disable_private_keys", "blank"} }, | { "wallet", "createwallet", createwallet, {"wallet_name", "disable_private_keys", "blank"} }, | ||||
{ "wallet", "encryptwallet", encryptwallet, {"passphrase"} }, | { "wallet", "encryptwallet", encryptwallet, {"passphrase"} }, | ||||
{ "wallet", "getaddressesbylabel", getaddressesbylabel, {"label"} }, | |||||
{ "wallet", "getaddressinfo", getaddressinfo, {"address"} }, | { "wallet", "getaddressinfo", getaddressinfo, {"address"} }, | ||||
{ "wallet", "getbalance", getbalance, {"account|dummy","minconf","include_watchonly"} }, | { "wallet", "getbalance", getbalance, {"dummy","minconf","include_watchonly"} }, | ||||
{ "wallet", "getnewaddress", getnewaddress, {"label|account", "address_type"} }, | { "wallet", "getnewaddress", getnewaddress, {"label", "address_type"} }, | ||||
{ "wallet", "getrawchangeaddress", getrawchangeaddress, {"address_type"} }, | { "wallet", "getrawchangeaddress", getrawchangeaddress, {"address_type"} }, | ||||
{ "wallet", "getreceivedbyaddress", getreceivedbyaddress, {"address","minconf"} }, | { "wallet", "getreceivedbyaddress", getreceivedbyaddress, {"address","minconf"} }, | ||||
{ "wallet", "getreceivedbylabel", getreceivedbylabel, {"label","minconf"} }, | |||||
{ "wallet", "gettransaction", gettransaction, {"txid","include_watchonly"} }, | { "wallet", "gettransaction", gettransaction, {"txid","include_watchonly"} }, | ||||
{ "wallet", "getunconfirmedbalance", getunconfirmedbalance, {} }, | { "wallet", "getunconfirmedbalance", getunconfirmedbalance, {} }, | ||||
{ "wallet", "getwalletinfo", getwalletinfo, {} }, | { "wallet", "getwalletinfo", getwalletinfo, {} }, | ||||
{ "wallet", "keypoolrefill", keypoolrefill, {"newsize"} }, | { "wallet", "keypoolrefill", keypoolrefill, {"newsize"} }, | ||||
{ "wallet", "listaddressgroupings", listaddressgroupings, {} }, | { "wallet", "listaddressgroupings", listaddressgroupings, {} }, | ||||
{ "wallet", "listlabels", listlabels, {"purpose"} }, | |||||
{ "wallet", "listlockunspent", listlockunspent, {} }, | { "wallet", "listlockunspent", listlockunspent, {} }, | ||||
{ "wallet", "listreceivedbyaddress", listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, | { "wallet", "listreceivedbyaddress", listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, | ||||
{ "wallet", "listreceivedbylabel", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | |||||
{ "wallet", "listsinceblock", listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, | { "wallet", "listsinceblock", listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, | ||||
{ "wallet", "listtransactions", listtransactions, {"account|dummy","count","skip","include_watchonly"} }, | { "wallet", "listtransactions", listtransactions, {"dummy","count","skip","include_watchonly"} }, | ||||
{ "wallet", "listunspent", listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, | { "wallet", "listunspent", listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, | ||||
{ "wallet", "listwallets", listwallets, {} }, | { "wallet", "listwallets", listwallets, {} }, | ||||
{ "wallet", "loadwallet", loadwallet, {"filename"} }, | { "wallet", "loadwallet", loadwallet, {"filename"} }, | ||||
{ "wallet", "lockunspent", lockunspent, {"unlock","transactions"} }, | { "wallet", "lockunspent", lockunspent, {"unlock","transactions"} }, | ||||
{ "wallet", "rescanblockchain", rescanblockchain, {"start_height", "stop_height"} }, | { "wallet", "rescanblockchain", rescanblockchain, {"start_height", "stop_height"} }, | ||||
{ "wallet", "sethdseed", sethdseed, {"newkeypool","seed"} }, | { "wallet", "sendmany", sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom"} }, | ||||
{ "wallet", "sendmany", sendmany, {"fromaccount|dummy","amounts","minconf","comment","subtractfeefrom"} }, | |||||
{ "wallet", "sendtoaddress", sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount"} }, | { "wallet", "sendtoaddress", sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount"} }, | ||||
{ "wallet", "sethdseed", sethdseed, {"newkeypool","seed"} }, | |||||
{ "wallet", "setlabel", setlabel, {"address","label"} }, | |||||
{ "wallet", "settxfee", settxfee, {"amount"} }, | { "wallet", "settxfee", settxfee, {"amount"} }, | ||||
{ "wallet", "signmessage", signmessage, {"address","message"} }, | { "wallet", "signmessage", signmessage, {"address","message"} }, | ||||
{ "wallet", "signrawtransactionwithwallet", signrawtransactionwithwallet, {"hextring","prevtxs","sighashtype"} }, | { "wallet", "signrawtransactionwithwallet", signrawtransactionwithwallet, {"hextring","prevtxs","sighashtype"} }, | ||||
{ "wallet", "unloadwallet", unloadwallet, {"wallet_name"} }, | { "wallet", "unloadwallet", unloadwallet, {"wallet_name"} }, | ||||
{ "wallet", "walletcreatefundedpsbt", walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} }, | |||||
{ "wallet", "walletlock", walletlock, {} }, | { "wallet", "walletlock", walletlock, {} }, | ||||
{ "wallet", "walletpassphrasechange", walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, | |||||
{ "wallet", "walletpassphrase", walletpassphrase, {"passphrase","timeout"} }, | { "wallet", "walletpassphrase", walletpassphrase, {"passphrase","timeout"} }, | ||||
{ "wallet", "walletpassphrasechange", walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, | |||||
/** Account functions (deprecated) */ | { "wallet", "walletprocesspsbt", walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} }, | ||||
{ "wallet", "getaccountaddress", getaccountaddress, {"account"} }, | |||||
{ "wallet", "getaccount", getaccount, {"address"} }, | |||||
{ "wallet", "getaddressesbyaccount", getaddressesbyaccount, {"account"} }, | |||||
{ "wallet", "getreceivedbyaccount", getreceivedbylabel, {"account","minconf"} }, | |||||
{ "wallet", "listaccounts", listaccounts, {"minconf","include_watchonly"} }, | |||||
{ "wallet", "listreceivedbyaccount", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | |||||
{ "wallet", "setaccount", setlabel, {"address","account"} }, | |||||
{ "wallet", "sendfrom", sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, | |||||
{ "wallet", "move", movecmd, {"fromaccount","toaccount","amount","minconf","comment"} }, | |||||
/** Label functions (to replace non-balance account functions) */ | |||||
{ "wallet", "getaddressesbylabel", getaddressesbylabel, {"label"} }, | |||||
{ "wallet", "getreceivedbylabel", getreceivedbylabel, {"label","minconf"} }, | |||||
{ "wallet", "listlabels", listlabels, {"purpose"} }, | |||||
{ "wallet", "listreceivedbylabel", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, | |||||
{ "wallet", "setlabel", setlabel, {"address","label"} }, | |||||
{ "generating", "generate", generate, {"nblocks","maxtries"} }, | |||||
}; | }; | ||||
// clang-format on | // clang-format on | ||||
void RegisterWalletRPCCommands(CRPCTable &t) { | void RegisterWalletRPCCommands(CRPCTable &t) { | ||||
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { | for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { | ||||
t.appendCommand(commands[vcidx].name, &commands[vcidx]); | t.appendCommand(commands[vcidx].name, &commands[vcidx]); | ||||
} | } | ||||
} | } |