diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/rpcwallet.cpp | 213 | ||||
-rw-r--r-- | src/wallet/test/coinselector_tests.cpp | 16 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 43 | ||||
-rw-r--r-- | src/wallet/wallet.h | 27 |
4 files changed, 161 insertions, 138 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fd13d8c542..365dedfceb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -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,10 +157,10 @@ 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 = pwallet->m_default_address_type; if (!request.params[1].isNull()) { @@ -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; } @@ -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); @@ -552,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" @@ -720,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)) { @@ -729,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(); @@ -760,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; @@ -920,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"); @@ -984,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"); @@ -1076,7 +1076,7 @@ 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()) @@ -1145,6 +1145,9 @@ 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; @@ -1171,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" @@ -1185,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" @@ -1204,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(); @@ -1233,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)); @@ -1385,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(); @@ -1404,7 +1407,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA bool has_filtered_address = false; CTxDestination filtered_address = CNoDestination(); - if (!fByAccounts && params.size() > 3) { + if (!by_label && params.size() > 3) { if (!IsValidDestinationString(params[3].get_str())) { throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid"); } @@ -1449,7 +1452,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA // Reply UniValue ret(UniValue::VARR); - std::map<std::string, tallyitem> mapAccountTally; + std::map<std::string, tallyitem> label_tally; // Create mapAddressBook iterator // If we aren't filtering, go from begin() to end() @@ -1466,7 +1469,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA for (auto item_it = start; item_it != end; ++item_it) { const CTxDestination& address = item_it->first; - const std::string& strAccount = item_it->second.name; + const std::string& label = item_it->second.name; auto it = mapTally.find(address); if (it == mapTally.end() && !fIncludeEmpty) continue; @@ -1481,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; @@ -1494,11 +1497,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA if(fIsWatchonly) obj.pushKV("involvesWatchonly", true); obj.pushKV("address", EncodeDestination(address)); - obj.pushKV("account", strAccount); + 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()) { @@ -1512,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; @@ -1524,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); } } @@ -1552,10 +1555,10 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) " {\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" @@ -1582,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)) { @@ -1591,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(); @@ -2015,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" @@ -2927,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" @@ -3031,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); } @@ -3570,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"); } } } @@ -3826,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, {} }, @@ -3855,7 +3862,8 @@ 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", "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"} }, @@ -3866,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"} }, diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index f05c81cd4c..6c36e2e965 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -4,6 +4,7 @@ #include "wallet/wallet.h" #include "wallet/coinselection.h" +#include "wallet/coincontrol.h" #include "amount.h" #include "primitives/transaction.h" #include "random.h" @@ -27,7 +28,7 @@ std::vector<std::unique_ptr<CWalletTx>> wtxn; typedef std::set<CInputCoin> CoinSet; static std::vector<COutput> vCoins; -static const CWallet testWallet("dummy", CWalletDBWrapper::CreateDummy()); +static CWallet testWallet("dummy", CWalletDBWrapper::CreateDummy()); static CAmount balance = 0; CoinEligibilityFilter filter_standard(1, 6, 0); @@ -72,6 +73,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa } COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */); vCoins.push_back(output); + testWallet.AddToWallet(*wtx.get()); wtxn.emplace_back(std::move(wtx)); } @@ -222,6 +224,18 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(1); vCoins.at(0).nInputBytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail BOOST_CHECK(!testWallet.SelectCoinsMinConf( 1 * CENT, filter_standard, vCoins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used)); + + // Make sure that we aren't using BnB when there are preset inputs + empty_wallet(); + add_coin(5 * CENT); + add_coin(3 * CENT); + add_coin(2 * CENT); + CCoinControl coin_control; + coin_control.fAllowOtherInputs = true; + coin_control.Select(COutPoint(vCoins.at(0).tx->GetHash(), vCoins.at(0).i)); + BOOST_CHECK(testWallet.SelectCoins(vCoins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb, bnb_used)); + BOOST_CHECK(!bnb_used); + BOOST_CHECK(!coin_selection_params_bnb.use_bnb); } BOOST_AUTO_TEST_CASE(knapsack_solver_test) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5472062a20..a80875e7ed 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -809,12 +809,12 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun return true; } -bool CWallet::GetAccountDestination(CTxDestination &dest, std::string strAccount, bool bForceNew) +bool CWallet::GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew) { CWalletDB walletdb(*dbw); CAccount account; - walletdb.ReadAccount(strAccount, account); + walletdb.ReadAccount(label, account); if (!bForceNew) { if (!account.vchPubKey.IsValid()) @@ -840,8 +840,8 @@ bool CWallet::GetAccountDestination(CTxDestination &dest, std::string strAccount LearnRelatedScripts(account.vchPubKey, m_default_address_type); dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); - SetAddressBook(dest, strAccount, "receive"); - walletdb.WriteAccount(strAccount, account); + SetAddressBook(dest, label, "receive"); + walletdb.WriteAccount(label, account); } else { dest = GetDestinationForKey(account.vchPubKey, m_default_address_type); } @@ -1267,7 +1267,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() { // chainActive.Tip()... // We could also take cs_wallet here, and call m_last_block_processed // protected by cs_wallet instead of cs_main, but as long as we need - // cs_main here anyway, its easier to just call it cs_main-protected. + // cs_main here anyway, it's easier to just call it cs_main-protected. LOCK(cs_main); const CBlockIndex* initialChainTip = chainActive.Tip(); @@ -2220,7 +2220,7 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons for (const CTxOut& out : wtx.tx->vout) { if (outgoing && IsChange(out)) { debit -= out.nValue; - } else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetAccountName(out.scriptPubKey))) { + } else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetLabelName(out.scriptPubKey))) { balance += out.nValue; } } @@ -2425,21 +2425,21 @@ const CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int out return ptx->vout[n]; } -bool CWallet::OutputEligibleForSpending(const COutput& output, const CoinEligibilityFilter& eligibilty_filter) const +bool CWallet::OutputEligibleForSpending(const COutput& output, const CoinEligibilityFilter& eligibility_filter) const { if (!output.fSpendable) return false; - if (output.nDepth < (output.tx->IsFromMe(ISMINE_ALL) ? eligibilty_filter.conf_mine : eligibilty_filter.conf_theirs)) + if (output.nDepth < (output.tx->IsFromMe(ISMINE_ALL) ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs)) return false; - if (!mempool.TransactionWithinChainLimit(output.tx->GetHash(), eligibilty_filter.max_ancestors)) + if (!mempool.TransactionWithinChainLimit(output.tx->GetHash(), eligibility_filter.max_ancestors)) return false; return true; } -bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibilty_filter, std::vector<COutput> vCoins, +bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> vCoins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const { setCoinsRet.clear(); @@ -2460,7 +2460,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil // Filter by the min conf specs and add to utxo_pool and calculate effective value for (const COutput &output : vCoins) { - if (!OutputEligibleForSpending(output, eligibilty_filter)) + if (!OutputEligibleForSpending(output, eligibility_filter)) continue; CInputCoin coin(output.tx->tx, output.i); @@ -2480,7 +2480,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil // Filter by the min conf specs and add to utxo_pool for (const COutput &output : vCoins) { - if (!OutputEligibleForSpending(output, eligibilty_filter)) + if (!OutputEligibleForSpending(output, eligibility_filter)) continue; CInputCoin coin = CInputCoin(output.tx->tx, output.i); @@ -2491,7 +2491,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil } } -bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const +bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const { std::vector<COutput> vCoins(vAvailableCoins); @@ -2521,6 +2521,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm { // For now, don't use BnB if preset inputs are selected. TODO: Enable this later bnb_used = false; + coin_selection_params.use_bnb = false; std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash); if (it != mapWallet.end()) @@ -3260,7 +3261,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address) return CWalletDB(*dbw).EraseName(EncodeDestination(address)); } -const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const +const std::string& CWallet::GetLabelName(const CScript& scriptPubKey) const { CTxDestination address; if (ExtractDestination(scriptPubKey, address) && !scriptPubKey.IsUnspendable()) { @@ -3270,9 +3271,9 @@ const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const } } // A scriptPubKey that doesn't have an entry in the address book is - // associated with the default account (""). - const static std::string DEFAULT_ACCOUNT_NAME; - return DEFAULT_ACCOUNT_NAME; + // associated with the default label (""). + const static std::string DEFAULT_LABEL_NAME; + return DEFAULT_LABEL_NAME; } /** @@ -3628,7 +3629,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() return ret; } -std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const +std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) const { LOCK(cs_wallet); std::set<CTxDestination> result; @@ -3636,7 +3637,7 @@ std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAcco { const CTxDestination& address = item.first; const std::string& strName = item.second.name; - if (strName == strAccount) + if (strName == label) result.insert(address); } return result; @@ -4206,8 +4207,8 @@ bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& // We must set fInMempool here - while it will be re-set to true by the // entered-mempool callback, if we did not there would be a race where a // user could call sendmoney in a loop and hit spurious out of funds errors - // because we think that the transaction they just generated's change is - // unavailable as we're not yet aware its in mempool. + // because we think that this newly generated transaction's change is + // unavailable as we're not yet aware that it is in the mempool. bool ret = ::AcceptToMemoryPool(mempool, state, tx, nullptr /* pfMissingInputs */, nullptr /* plTxnReplaced */, false /* bypass_limits */, nAbsurdFee); fInMempool |= ret; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5ac8457eb4..3ef5bfbb65 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -665,15 +665,6 @@ private: std::mutex mutexScanning; friend class WalletRescanReserver; - - /** - * Select a set of coins such that nValueRet >= nTargetValue and at least - * all coins from coinControl are selected; Never select unconfirmed coins - * if they are not ours - */ - bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, - const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const; - CWalletDB *pwalletdbEncryption; //! the current wallet version: clients below this version are not able to load the wallet @@ -766,6 +757,14 @@ public: return *dbw; } + /** + * Select a set of coins such that nValueRet >= nTargetValue and at least + * all coins from coinControl are selected; Never select unconfirmed coins + * if they are not ours + */ + bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, + const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const; + /** Get a name for this wallet for logging/debugging purposes. */ const std::string& GetName() const { return m_name; } @@ -853,7 +852,7 @@ public: * completion the coin set and corresponding actual target value is * assembled */ - bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibilty_filter, std::vector<COutput> vCoins, + bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> vCoins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const; bool IsSpent(const uint256& hash, unsigned int n) const; @@ -929,7 +928,7 @@ public: int64_t IncOrderPosNext(CWalletDB *pwalletdb = nullptr); DBErrors ReorderTransactions(); bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = ""); - bool GetAccountDestination(CTxDestination &dest, std::string strAccount, bool bForceNew = false); + bool GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew = false); void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true); @@ -1007,7 +1006,7 @@ public: std::set< std::set<CTxDestination> > GetAddressGroupings(); std::map<CTxDestination, CAmount> GetAddressBalances(); - std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const; + std::set<CTxDestination> GetLabelAddresses(const std::string& label) const; isminetype IsMine(const CTxIn& txin) const; /** @@ -1037,7 +1036,7 @@ public: bool DelAddressBook(const CTxDestination& address); - const std::string& GetAccountName(const CScript& scriptPubKey) const; + const std::string& GetLabelName(const CScript& scriptPubKey) const; void Inventory(const uint256 &hash) override { @@ -1167,7 +1166,7 @@ public: CTxDestination AddAndGetDestinationForScript(const CScript& script, OutputType); /** Whether a given output is spendable by this wallet */ - bool OutputEligibleForSpending(const COutput& output, const CoinEligibilityFilter& eligibilty_filter) const; + bool OutputEligibleForSpending(const COutput& output, const CoinEligibilityFilter& eligibility_filter) const; }; /** A key allocated from the key pool. */ |