diff options
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r-- | src/wallet/rpcwallet.cpp | 334 |
1 files changed, 181 insertions, 153 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8b95c56a5f..365dedfceb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4,12 +4,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <amount.h> -#include <base58.h> #include <chain.h> #include <consensus/validation.h> #include <core_io.h> #include <httpserver.h> #include <validation.h> +#include <key_io.h> #include <net.h> #include <policy/feerate.h> #include <policy/fees.h> @@ -95,7 +95,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) { entry.pushKV("blockhash", wtx.hashBlock.GetHex()); entry.pushKV("blockindex", wtx.nIndex); - entry.pushKV("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()); + entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime()); } else { entry.pushKV("trusted", wtx.IsTrusted()); } @@ -124,12 +124,12 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.pushKV(item.first, item.second); } -std::string AccountFromValue(const UniValue& value) +std::string LabelFromValue(const UniValue& value) { - std::string strAccount = value.get_str(); - if (strAccount == "*") - throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); - return strAccount; + std::string label = value.get_str(); + if (label == "*") + throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name"); + return label; } UniValue getnewaddress(const JSONRPCRequest& request) @@ -141,12 +141,12 @@ UniValue getnewaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 2) throw std::runtime_error( - "getnewaddress ( \"account\" \"address_type\" )\n" + "getnewaddress ( \"label\" \"address_type\" )\n" "\nReturns a new Bitcoin address for receiving payments.\n" - "If 'account' is specified (DEPRECATED), it is added to the address book \n" - "so payments received with the address will be credited to 'account'.\n" + "If 'label' is specified, it is added to the address book \n" + "so payments received with the address will be associated with 'label'.\n" "\nArguments:\n" - "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. 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 if there is no account by the given name.\n" + "1. \"label\" (string, optional) The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n" "2. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n" "\nResult:\n" "\"address\" (string) The new bitcoin address\n" @@ -157,15 +157,15 @@ UniValue getnewaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - // Parse the account first so we don't generate a key if there's an error - std::string strAccount; + // Parse the label first so we don't generate a key if there's an error + std::string label; if (!request.params[0].isNull()) - strAccount = AccountFromValue(request.params[0]); + label = LabelFromValue(request.params[0]); - OutputType output_type = g_address_type; + OutputType output_type = pwallet->m_default_address_type; if (!request.params[1].isNull()) { - output_type = ParseOutputType(request.params[1].get_str(), g_address_type); - if (output_type == OUTPUT_TYPE_NONE) { + output_type = ParseOutputType(request.params[1].get_str(), pwallet->m_default_address_type); + if (output_type == OutputType::NONE) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str())); } } @@ -182,23 +182,23 @@ UniValue getnewaddress(const JSONRPCRequest& request) pwallet->LearnRelatedScripts(newKey, output_type); CTxDestination dest = GetDestinationForKey(newKey, output_type); - pwallet->SetAddressBook(dest, strAccount, "receive"); + pwallet->SetAddressBook(dest, label, "receive"); return EncodeDestination(dest); } -CTxDestination GetAccountDestination(CWallet* const pwallet, std::string strAccount, bool bForceNew=false) +CTxDestination GetLabelDestination(CWallet* const pwallet, const std::string& label, bool bForceNew=false) { CTxDestination dest; - if (!pwallet->GetAccountDestination(dest, strAccount, bForceNew)) { + if (!pwallet->GetLabelDestination(dest, label, bForceNew)) { throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } return dest; } -UniValue getaccountaddress(const JSONRPCRequest& request) +UniValue getlabeladdress(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { @@ -207,27 +207,27 @@ UniValue getaccountaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "getaccountaddress \"account\"\n" - "\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n" + "getlabeladdress \"label\"\n" + "\nReturns the current Bitcoin address for receiving payments to this label.\n" "\nArguments:\n" - "1. \"account\" (string, required) The account name 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" + "1. \"label\" (string, required) The label name for the address. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created and a new address created if there is no label by the given name.\n" "\nResult:\n" - "\"address\" (string) The account bitcoin address\n" + "\"address\" (string) The label bitcoin address\n" "\nExamples:\n" - + HelpExampleCli("getaccountaddress", "") - + HelpExampleCli("getaccountaddress", "\"\"") - + HelpExampleCli("getaccountaddress", "\"myaccount\"") - + HelpExampleRpc("getaccountaddress", "\"myaccount\"") + + HelpExampleCli("getlabeladdress", "") + + HelpExampleCli("getlabeladdress", "\"\"") + + HelpExampleCli("getlabeladdress", "\"mylabel\"") + + HelpExampleRpc("getlabeladdress", "\"mylabel\"") ); LOCK2(cs_main, pwallet->cs_wallet); - // Parse the account first so we don't generate a key if there's an error - std::string strAccount = AccountFromValue(request.params[0]); + // Parse the label first so we don't generate a key if there's an error + std::string label = LabelFromValue(request.params[0]); UniValue ret(UniValue::VSTR); - ret = EncodeDestination(GetAccountDestination(pwallet, strAccount)); + ret = EncodeDestination(GetLabelDestination(pwallet, label)); return ret; } @@ -259,10 +259,10 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) pwallet->TopUpKeyPool(); } - OutputType output_type = g_change_type != OUTPUT_TYPE_NONE ? g_change_type : g_address_type; + OutputType output_type = pwallet->m_default_change_type != OutputType::NONE ? pwallet->m_default_change_type : pwallet->m_default_address_type; if (!request.params[0].isNull()) { output_type = ParseOutputType(request.params[0].get_str(), output_type); - if (output_type == OUTPUT_TYPE_NONE) { + if (output_type == OutputType::NONE) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str())); } } @@ -281,7 +281,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) } -UniValue setaccount(const JSONRPCRequest& request) +UniValue setlabel(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { @@ -290,14 +290,14 @@ UniValue setaccount(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "setaccount \"address\" \"account\"\n" - "\nDEPRECATED. Sets the account associated with the given address.\n" + "setlabel \"address\" \"label\"\n" + "\nSets the label associated with the given address.\n" "\nArguments:\n" - "1. \"address\" (string, required) The bitcoin address to be associated with an account.\n" - "2. \"account\" (string, required) The account to assign the address to.\n" + "1. \"address\" (string, required) The bitcoin address to be associated with a label.\n" + "2. \"label\" (string, required) The label to assign the address to.\n" "\nExamples:\n" - + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") - + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") + + HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") + + HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") ); LOCK2(cs_main, pwallet->cs_wallet); @@ -307,23 +307,23 @@ UniValue setaccount(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); } - std::string strAccount; + std::string label; if (!request.params[1].isNull()) - strAccount = AccountFromValue(request.params[1]); + label = LabelFromValue(request.params[1]); - // Only add the account if the address is yours. + // Only add the label if the address is yours. if (IsMine(*pwallet, dest)) { - // Detect when changing the account of an address that is the 'unused current key' of another account: + // Detect when changing the label of an address that is the 'unused current key' of another label: if (pwallet->mapAddressBook.count(dest)) { - std::string strOldAccount = pwallet->mapAddressBook[dest].name; - if (dest == GetAccountDestination(pwallet, strOldAccount)) { - GetAccountDestination(pwallet, strOldAccount, true); + std::string old_label = pwallet->mapAddressBook[dest].name; + if (dest == GetLabelDestination(pwallet, old_label)) { + GetLabelDestination(pwallet, old_label, true); } } - pwallet->SetAddressBook(dest, strAccount, "receive"); + pwallet->SetAddressBook(dest, label, "receive"); } else - throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); + throw JSONRPCError(RPC_MISC_ERROR, "setlabel can only be used with own address"); return NullUniValue; } @@ -390,7 +390,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - std::string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = LabelFromValue(request.params[0]); // Find all addresses that have the given account UniValue ret(UniValue::VARR); @@ -404,7 +404,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) return ret; } -static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control) +static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount) { CAmount curBalance = pwallet->GetBalance(); @@ -430,16 +430,18 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA int nChangePosRet = -1; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; vecSend.push_back(recipient); - if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) { + CTransactionRef tx; + if (!pwallet->CreateTransaction(vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) { if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } CValidationState state; - if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) { + if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(fromAccount), reservekey, g_connman.get(), state)) { strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strError); } + return tx; } UniValue sendtoaddress(const JSONRPCRequest& request) @@ -498,11 +500,11 @@ UniValue sendtoaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); // Wallet comments - CWalletTx wtx; + mapValue_t mapValue; if (!request.params[2].isNull() && !request.params[2].get_str().empty()) - wtx.mapValue["comment"] = request.params[2].get_str(); + mapValue["comment"] = request.params[2].get_str(); if (!request.params[3].isNull() && !request.params[3].get_str().empty()) - wtx.mapValue["to"] = request.params[3].get_str(); + mapValue["to"] = request.params[3].get_str(); bool fSubtractFeeFromAmount = false; if (!request.params[4].isNull()) { @@ -527,9 +529,8 @@ UniValue sendtoaddress(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control); - - return wtx.GetHash().GetHex(); + CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue), {} /* fromAccount */); + return tx->GetHash().GetHex(); } UniValue listaddressgroupings(const JSONRPCRequest& request) @@ -551,7 +552,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) " [\n" " \"address\", (string) The bitcoin address\n" " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n" - " \"account\" (string, optional) DEPRECATED. The account\n" + " \"label\" (string, optional) The label\n" " ]\n" " ,...\n" " ]\n" @@ -719,7 +720,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) } -UniValue getreceivedbyaccount(const JSONRPCRequest& request) +UniValue getreceivedbylabel(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { @@ -728,22 +729,22 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "getreceivedbyaccount \"account\" ( minconf )\n" - "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n" + "getreceivedbylabel \"label\" ( minconf )\n" + "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n" "\nArguments:\n" - "1. \"account\" (string, required) The selected account, may be the default account using \"\".\n" + "1. \"label\" (string, required) The selected label, may be the default label using \"\".\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" "\nResult:\n" - "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n" + "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this label.\n" "\nExamples:\n" - "\nAmount received by the default account with at least 1 confirmation\n" - + HelpExampleCli("getreceivedbyaccount", "\"\"") + - "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n" - + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") + + "\nAmount received by the default label with at least 1 confirmation\n" + + HelpExampleCli("getreceivedbylabel", "\"\"") + + "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n" + + HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") + "\nThe amount with at least 6 confirmations\n" - + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") + + + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") + "\nAs a json rpc call\n" - + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6") + + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6") ); ObserveSafeMode(); @@ -759,9 +760,9 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) if (!request.params[1].isNull()) nMinDepth = request.params[1].get_int(); - // Get the set of pub keys assigned to account - std::string strAccount = AccountFromValue(request.params[0]); - std::set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount); + // Get the set of pub keys assigned to label + std::string label = LabelFromValue(request.params[0]); + std::set<CTxDestination> setAddress = pwallet->GetLabelAddresses(label); // Tally CAmount nAmount = 0; @@ -919,8 +920,8 @@ UniValue movecmd(const JSONRPCRequest& request) ObserveSafeMode(); LOCK2(cs_main, pwallet->cs_wallet); - std::string strFrom = AccountFromValue(request.params[0]); - std::string strTo = AccountFromValue(request.params[1]); + std::string strFrom = LabelFromValue(request.params[0]); + std::string strTo = LabelFromValue(request.params[1]); CAmount nAmount = AmountFromValue(request.params[2]); if (nAmount <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); @@ -983,7 +984,7 @@ UniValue sendfrom(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - std::string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = LabelFromValue(request.params[0]); CTxDestination dest = DecodeDestination(request.params[1].get_str()); if (!IsValidDestination(dest)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); @@ -995,12 +996,11 @@ UniValue sendfrom(const JSONRPCRequest& request) if (!request.params[3].isNull()) nMinDepth = request.params[3].get_int(); - CWalletTx wtx; - wtx.strFromAccount = strAccount; + mapValue_t mapValue; if (!request.params[4].isNull() && !request.params[4].get_str().empty()) - wtx.mapValue["comment"] = request.params[4].get_str(); + mapValue["comment"] = request.params[4].get_str(); if (!request.params[5].isNull() && !request.params[5].get_str().empty()) - wtx.mapValue["to"] = request.params[5].get_str(); + mapValue["to"] = request.params[5].get_str(); EnsureWalletIsUnlocked(pwallet); @@ -1010,9 +1010,8 @@ UniValue sendfrom(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); CCoinControl no_coin_control; // This is a deprecated API - SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control); - - return wtx.GetHash().GetHex(); + CTransactionRef tx = SendMoney(pwallet, dest, nAmount, false, no_coin_control, std::move(mapValue), std::move(strAccount)); + return tx->GetHash().GetHex(); } @@ -1077,16 +1076,15 @@ UniValue sendmany(const JSONRPCRequest& request) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - std::string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = LabelFromValue(request.params[0]); UniValue sendTo = request.params[1].get_obj(); int nMinDepth = 1; if (!request.params[2].isNull()) nMinDepth = request.params[2].get_int(); - CWalletTx wtx; - wtx.strFromAccount = strAccount; + mapValue_t mapValue; if (!request.params[3].isNull() && !request.params[3].get_str().empty()) - wtx.mapValue["comment"] = request.params[3].get_str(); + mapValue["comment"] = request.params[3].get_str(); UniValue subtractFeeFromAmount(UniValue::VARR); if (!request.params[4].isNull()) @@ -1147,21 +1145,25 @@ UniValue sendmany(const JSONRPCRequest& request) if (totalAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + // Shuffle recipient list + std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext()); + // Send CReserveKey keyChange(pwallet); CAmount nFeeRequired = 0; int nChangePosRet = -1; std::string strFailReason; - bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control); + CTransactionRef tx; + bool fCreated = pwallet->CreateTransaction(vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); CValidationState state; - if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) { + if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(strAccount), keyChange, g_connman.get(), state)) { strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state)); throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } - return wtx.GetHash().GetHex(); + return tx->GetHash().GetHex(); } UniValue addmultisigaddress(const JSONRPCRequest& request) @@ -1172,12 +1174,12 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) { - std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" \"address_type\" )\n" + std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"label\" \"address_type\" )\n" "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n" "Each key is a Bitcoin address or hex-encoded public key.\n" "This functionality is only intended for use with non-watchonly addresses.\n" "See `importaddress` for watchonly p2sh address support.\n" - "If 'account' is specified (DEPRECATED), assign address to that account.\n" + "If 'label' is specified, assign address to that label.\n" "\nArguments:\n" "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" @@ -1186,7 +1188,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) " \"address\" (string) bitcoin address or hex-encoded public key\n" " ...,\n" " ]\n" - "3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n" + "3. \"label\" (string, optional) A label to assign the addresses to.\n" "4. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n" "\nResult:\n" @@ -1205,9 +1207,9 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - std::string strAccount; + std::string label; if (!request.params[2].isNull()) - strAccount = AccountFromValue(request.params[2]); + label = LabelFromValue(request.params[2]); int required = request.params[0].get_int(); @@ -1222,10 +1224,10 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) } } - OutputType output_type = g_address_type; + OutputType output_type = pwallet->m_default_address_type; if (!request.params[3].isNull()) { output_type = ParseOutputType(request.params[3].get_str(), output_type); - if (output_type == OUTPUT_TYPE_NONE) { + if (output_type == OutputType::NONE) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str())); } } @@ -1234,7 +1236,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) CScript inner = CreateMultisigRedeemscript(required, pubkeys); pwallet->AddCScript(inner); CTxDestination dest = pwallet->AddAndGetDestinationForScript(inner, output_type); - pwallet->SetAddressBook(dest, strAccount, "send"); + pwallet->SetAddressBook(dest, label, "send"); UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(dest)); @@ -1386,14 +1388,14 @@ struct tallyitem } }; -UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByAccounts) +UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label) { // Minimum confirmations int nMinDepth = 1; if (!params[0].isNull()) nMinDepth = params[0].get_int(); - // Whether to include empty accounts + // Whether to include empty labels bool fIncludeEmpty = false; if (!params[1].isNull()) fIncludeEmpty = params[1].get_bool(); @@ -1403,6 +1405,16 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA if(params[2].get_bool()) filter = filter | ISMINE_WATCH_ONLY; + bool has_filtered_address = false; + CTxDestination filtered_address = CNoDestination(); + if (!by_label && params.size() > 3) { + if (!IsValidDestinationString(params[3].get_str())) { + throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid"); + } + filtered_address = DecodeDestination(params[3].get_str()); + has_filtered_address = true; + } + // Tally std::map<CTxDestination, tallyitem> mapTally; for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { @@ -1421,6 +1433,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA if (!ExtractDestination(txout.scriptPubKey, address)) continue; + if (has_filtered_address && !(filtered_address == address)) { + continue; + } + isminefilter mine = IsMine(*pwallet, address); if(!(mine & filter)) continue; @@ -1436,11 +1452,25 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA // Reply UniValue ret(UniValue::VARR); - std::map<std::string, tallyitem> mapAccountTally; - for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) { - const CTxDestination& dest = item.first; - const std::string& strAccount = item.second.name; - std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest); + std::map<std::string, tallyitem> label_tally; + + // Create mapAddressBook iterator + // If we aren't filtering, go from begin() to end() + auto start = pwallet->mapAddressBook.begin(); + auto end = pwallet->mapAddressBook.end(); + // If we are filtering, find() the applicable entry + if (has_filtered_address) { + start = pwallet->mapAddressBook.find(filtered_address); + if (start != end) { + end = std::next(start); + } + } + + for (auto item_it = start; item_it != end; ++item_it) + { + const CTxDestination& address = item_it->first; + const std::string& label = item_it->second.name; + auto it = mapTally.find(address); if (it == mapTally.end() && !fIncludeEmpty) continue; @@ -1454,9 +1484,9 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA fIsWatchonly = (*it).second.fIsWatchonly; } - if (fByAccounts) + if (by_label) { - tallyitem& _item = mapAccountTally[strAccount]; + tallyitem& _item = label_tally[label]; _item.nAmount += nAmount; _item.nConf = std::min(_item.nConf, nConf); _item.fIsWatchonly = fIsWatchonly; @@ -1466,12 +1496,11 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA UniValue obj(UniValue::VOBJ); if(fIsWatchonly) obj.pushKV("involvesWatchonly", true); - obj.pushKV("address", EncodeDestination(dest)); - obj.pushKV("account", strAccount); + obj.pushKV("address", EncodeDestination(address)); + obj.pushKV("account", label); obj.pushKV("amount", ValueFromAmount(nAmount)); obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); - if (!fByAccounts) - obj.pushKV("label", strAccount); + obj.pushKV("label", label); UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { @@ -1485,9 +1514,9 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA } } - if (fByAccounts) + if (by_label) { - for (const auto& entry : mapAccountTally) + for (const auto& entry : label_tally) { CAmount nAmount = entry.second.nAmount; int nConf = entry.second.nConf; @@ -1497,6 +1526,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA obj.pushKV("account", entry.first); obj.pushKV("amount", ValueFromAmount(nAmount)); obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)); + obj.pushKV("label", entry.first); ret.push_back(obj); } } @@ -1511,24 +1541,24 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() > 3) + if (request.fHelp || request.params.size() > 4) throw std::runtime_error( - "listreceivedbyaddress ( minconf include_empty include_watchonly)\n" + "listreceivedbyaddress ( minconf include_empty include_watchonly address_filter )\n" "\nList balances by receiving address.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" "2. include_empty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n" "3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n" - + "4. address_filter (string, optional) If present, only return information on this address.\n" "\nResult:\n" "[\n" " {\n" " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" " \"address\" : \"receivingaddress\", (string) The receiving address\n" - " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n" + " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n" " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n" " \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n" - " \"label\" : \"label\", (string) A comment for the address/transaction, if any\n" + " \"label\" : \"label\", (string) The label of the receiving address. The default label is \"\".\n" " \"txids\": [\n" " n, (numeric) The ids of transactions received with the address \n" " ...\n" @@ -1541,6 +1571,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) + HelpExampleCli("listreceivedbyaddress", "") + HelpExampleCli("listreceivedbyaddress", "6 true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true") + + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"") ); ObserveSafeMode(); @@ -1554,7 +1585,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) return ListReceived(pwallet, request.params, false); } -UniValue listreceivedbyaccount(const JSONRPCRequest& request) +UniValue listreceivedbylabel(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { @@ -1563,29 +1594,29 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 3) throw std::runtime_error( - "listreceivedbyaccount ( minconf include_empty include_watchonly)\n" - "\nDEPRECATED. List balances by account.\n" + "listreceivedbylabel ( minconf include_empty include_watchonly)\n" + "\nList received transactions by label.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" - "2. include_empty (bool, optional, default=false) Whether to include accounts that haven't received any payments.\n" + "2. include_empty (bool, optional, default=false) Whether to include labels that haven't received any payments.\n" "3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n" "\nResult:\n" "[\n" " {\n" " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" - " \"account\" : \"accountname\", (string) The account name of the receiving account\n" - " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n" + " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n" + " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this label\n" " \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n" - " \"label\" : \"label\" (string) A comment for the address/transaction, if any\n" + " \"label\" : \"label\" (string) The label of the receiving address. The default label is \"\".\n" " }\n" " ,...\n" "]\n" "\nExamples:\n" - + HelpExampleCli("listreceivedbyaccount", "") - + HelpExampleCli("listreceivedbyaccount", "6 true") - + HelpExampleRpc("listreceivedbyaccount", "6, true, true") + + HelpExampleCli("listreceivedbylabel", "") + + HelpExampleCli("listreceivedbylabel", "6 true") + + HelpExampleRpc("listreceivedbylabel", "6, true, true") ); ObserveSafeMode(); @@ -1987,7 +2018,7 @@ UniValue listsinceblock(const JSONRPCRequest& request) " ],\n" " \"removed\": [\n" " <structure is the same as \"transactions\" above, only present if include_removed=true>\n" - " Note: transactions that were readded in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n" + " Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n" " ],\n" " \"lastblock\": \"lastblockhash\" (string) The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones\n" "}\n" @@ -2014,11 +2045,10 @@ UniValue listsinceblock(const JSONRPCRequest& request) uint256 blockId; blockId.SetHex(request.params[0].get_str()); - BlockMap::iterator it = mapBlockIndex.find(blockId); - if (it == mapBlockIndex.end()) { + paltindex = pindex = LookupBlockIndex(blockId); + if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - paltindex = pindex = it->second; if (chainActive[pindex->nHeight] != pindex) { // the block being asked for is a part of a deactivated chain; // we don't want to depend on its perceived height in the block @@ -2336,8 +2366,6 @@ UniValue walletpassphrase(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - if (request.fHelp) - return true; if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); } @@ -2402,8 +2430,6 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - if (request.fHelp) - return true; if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); } @@ -2458,8 +2484,6 @@ UniValue walletlock(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - if (request.fHelp) - return true; if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called."); } @@ -2505,8 +2529,6 @@ UniValue encryptwallet(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - if (request.fHelp) - return true; if (pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called."); } @@ -2908,7 +2930,8 @@ UniValue listunspent(const JSONRPCRequest& request) " \"txid\" : \"txid\", (string) the transaction id \n" " \"vout\" : n, (numeric) the vout value\n" " \"address\" : \"address\", (string) the bitcoin address\n" - " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n" + " \"label\" : \"label\", (string) The associated label, or \"\" for the default label\n" + " \"account\" : \"account\", (string) DEPRECATED. Backwards compatible alias for label.\n" " \"scriptPubKey\" : \"key\", (string) the script key\n" " \"amount\" : x.xxx, (numeric) the transaction output amount in " + CURRENCY_UNIT + "\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" @@ -3012,6 +3035,7 @@ UniValue listunspent(const JSONRPCRequest& request) entry.pushKV("address", EncodeDestination(address)); if (pwallet->mapAddressBook.count(address)) { + entry.pushKV("label", pwallet->mapAddressBook[address].name); entry.pushKV("account", pwallet->mapAddressBook[address].name); } @@ -3156,8 +3180,8 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) if (options.exists("changeAddress")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options"); } - coinControl.change_type = ParseOutputType(options["change_type"].get_str(), coinControl.change_type); - if (coinControl.change_type == OUTPUT_TYPE_NONE) { + coinControl.m_change_type = ParseOutputType(options["change_type"].get_str(), pwallet->m_default_change_type); + if (coinControl.m_change_type == OutputType::NONE) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str())); } } @@ -3551,7 +3575,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height"); } else if (pindexStop->nHeight < pindexStart->nHeight) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater then start_height"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height"); } } } @@ -3807,21 +3831,23 @@ static const CRPCCommand commands[] = { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, { "wallet", "abortrescan", &abortrescan, {} }, - { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account","address_type"} }, + { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label|account","address_type"} }, { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, { "wallet", "backupwallet", &backupwallet, {"destination"} }, { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, - { "wallet", "getaccountaddress", &getaccountaddress, {"account"} }, + { "wallet", "getlabeladdress", &getlabeladdress, {"label"} }, + { "wallet", "getaccountaddress", &getlabeladdress, {"account"} }, { "wallet", "getaccount", &getaccount, {"address"} }, { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} }, { "wallet", "getaddressinfo", &getaddressinfo, {"address"} }, { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} }, - { "wallet", "getnewaddress", &getnewaddress, {"account","address_type"} }, + { "wallet", "getnewaddress", &getnewaddress, {"label|account","address_type"} }, { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} }, - { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} }, + { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} }, + { "wallet", "getreceivedbyaccount", &getreceivedbylabel, {"account","minconf"} }, { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} }, { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} }, { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} }, @@ -3836,8 +3862,9 @@ static const CRPCCommand commands[] = { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} }, { "wallet", "listaddressgroupings", &listaddressgroupings, {} }, { "wallet", "listlockunspent", &listlockunspent, {} }, - { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} }, - { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly"} }, + { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, + { "wallet", "listreceivedbyaccount", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, + { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} }, { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, @@ -3847,7 +3874,8 @@ static const CRPCCommand commands[] = { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} }, - { "wallet", "setaccount", &setaccount, {"address","account"} }, + { "wallet", "setlabel", &setlabel, {"address","label"} }, + { "wallet", "setaccount", &setlabel, {"address","account"} }, { "wallet", "settxfee", &settxfee, {"amount"} }, { "wallet", "signmessage", &signmessage, {"address","message"} }, { "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} }, |