aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/rpcwallet.cpp
diff options
context:
space:
mode:
authorSamuel Dobson <dobsonsa68@gmail.com>2020-07-12 14:31:46 +1200
committerSamuel Dobson <dobsonsa68@gmail.com>2020-07-12 14:42:35 +1200
commit4db44acf2d5d3b40943c94b3960f42838255b7ad (patch)
tree7bc20aa15a8878c2ad0ee82b8ec2e08c31098b7a /src/wallet/rpcwallet.cpp
parent32302e5c88ef990b2eca0561bb6be38cdbc11ec3 (diff)
parent08fc6f6cfc3b06fd170452a766696d7b833113fa (diff)
downloadbitcoin-4db44acf2d5d3b40943c94b3960f42838255b7ad.tar.xz
Merge #18202: refactor: consolidate sendmany and sendtoaddress code
08fc6f6cfc3b06fd170452a766696d7b833113fa [rpc] refactor: consolidate sendmany and sendtoaddress code (Sjors Provoost) Pull request description: I consolidated code between these two RPC calls, since `sendtoaddress` is essentially `sendmany` with 1 destination. Unless I overlooked something, the only behaviour change is that some `sendtoaddress` error codes changed from `-4` to `-6`. The release note mentions this. Salvaged from #18201. ACKs for top commit: fjahr: Code review ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa jonatack: ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa meshcollider: Code review & functional test run ACK 08fc6f6cfc3b06fd170452a766696d7b833113fa Tree-SHA512: 7b66c52fa0444a4d02fc3f81d9c2a386794d447616026a30111eda35fb46510475eea6506a9ceda00bb4e0230ebb758da5d236b3ac05c954c044fa68a1e3e909
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r--src/wallet/rpcwallet.cpp132
1 files changed, 54 insertions, 78 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 3304d4ad0b..9d334063c4 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -359,36 +359,54 @@ static UniValue setlabel(const JSONRPCRequest& request)
return NullUniValue;
}
+void ParseRecipients(const UniValue& address_amounts, const UniValue& subtract_fee_outputs, std::vector<CRecipient> &recipients) {
+ std::set<CTxDestination> destinations;
+ int i = 0;
+ for (const std::string& address: address_amounts.getKeys()) {
+ CTxDestination dest = DecodeDestination(address);
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + address);
+ }
-static CTransactionRef SendMoney(CWallet* const pwallet, const CTxDestination& address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
-{
- CAmount curBalance = pwallet->GetBalance(0, coin_control.m_avoid_address_reuse).m_mine_trusted;
+ if (destinations.count(dest)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + address);
+ }
+ destinations.insert(dest);
- // Check amount
- if (nValue <= 0)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
+ CScript script_pub_key = GetScriptForDestination(dest);
+ CAmount amount = AmountFromValue(address_amounts[i++]);
- if (nValue > curBalance)
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
+ bool subtract_fee = false;
+ for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); idx++) {
+ const UniValue& addr = subtract_fee_outputs[idx];
+ if (addr.get_str() == address) {
+ subtract_fee = true;
+ }
+ }
- // Parse Bitcoin address
- CScript scriptPubKey = GetScriptForDestination(address);
+ CRecipient recipient = {script_pub_key, amount, subtract_fee};
+ recipients.push_back(recipient);
+ }
+}
+
+UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value)
+{
+ EnsureWalletIsUnlocked(pwallet);
- // Create and send the transaction
+ // Shuffle recipient list
+ std::shuffle(recipients.begin(), recipients.end(), FastRandomContext());
+
+ // Send
CAmount nFeeRequired = 0;
- bilingual_str error;
- std::vector<CRecipient> vecSend;
int nChangePosRet = -1;
- CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
- vecSend.push_back(recipient);
+ bilingual_str error;
CTransactionRef tx;
- if (!pwallet->CreateTransaction(vecSend, tx, nFeeRequired, nChangePosRet, error, coin_control)) {
- if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
- error = strprintf(Untranslated("Error: This transaction requires a transaction fee of at least %s"), FormatMoney(nFeeRequired));
- throw JSONRPCError(RPC_WALLET_ERROR, error.original);
+ bool fCreated = pwallet->CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+ if (!fCreated) {
+ throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
}
- pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
- return tx;
+ pwallet->CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
+ return tx->GetHash().GetHex();
}
static UniValue sendtoaddress(const JSONRPCRequest& request)
@@ -436,16 +454,6 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
LOCK(pwallet->cs_wallet);
- CTxDestination dest = DecodeDestination(request.params[0].get_str());
- if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
- }
-
- // Amount
- CAmount nAmount = AmountFromValue(request.params[1]);
- if (nAmount <= 0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
-
// Wallet comments
mapValue_t mapValue;
if (!request.params[2].isNull() && !request.params[2].get_str().empty())
@@ -471,8 +479,18 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue));
- return tx->GetHash().GetHex();
+ UniValue address_amounts(UniValue::VOBJ);
+ const std::string address = request.params[0].get_str();
+ address_amounts.pushKV(address, request.params[1]);
+ UniValue subtractFeeFromAmount(UniValue::VARR);
+ if (fSubtractFeeFromAmount) {
+ subtractFeeFromAmount.push_back(address);
+ }
+
+ std::vector<CRecipient> recipients;
+ ParseRecipients(address_amounts, subtractFeeFromAmount, recipients);
+
+ return SendMoney(pwallet, coin_control, recipients, mapValue);
}
static UniValue listaddressgroupings(const JSONRPCRequest& request)
@@ -860,52 +878,10 @@ static UniValue sendmany(const JSONRPCRequest& request)
SetFeeEstimateMode(pwallet, coin_control, request.params[7], request.params[6]);
- std::set<CTxDestination> destinations;
- std::vector<CRecipient> vecSend;
+ std::vector<CRecipient> recipients;
+ ParseRecipients(sendTo, subtractFeeFromAmount, recipients);
- std::vector<std::string> keys = sendTo.getKeys();
- for (const std::string& name_ : keys) {
- CTxDestination dest = DecodeDestination(name_);
- if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
- }
-
- if (destinations.count(dest)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
- }
- destinations.insert(dest);
-
- CScript scriptPubKey = GetScriptForDestination(dest);
- CAmount nAmount = AmountFromValue(sendTo[name_]);
- if (nAmount <= 0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
-
- bool fSubtractFeeFromAmount = false;
- for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
- const UniValue& addr = subtractFeeFromAmount[idx];
- if (addr.get_str() == name_)
- fSubtractFeeFromAmount = true;
- }
-
- CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
- vecSend.push_back(recipient);
- }
-
- EnsureWalletIsUnlocked(pwallet);
-
- // Shuffle recipient list
- std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
-
- // Send
- CAmount nFeeRequired = 0;
- int nChangePosRet = -1;
- bilingual_str error;
- CTransactionRef tx;
- bool fCreated = pwallet->CreateTransaction(vecSend, tx, nFeeRequired, nChangePosRet, error, coin_control);
- if (!fCreated)
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
- pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
- return tx->GetHash().GetHex();
+ return SendMoney(pwallet, coin_control, recipients, std::move(mapValue));
}
static UniValue addmultisigaddress(const JSONRPCRequest& request)