aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorfurszy <matiasfurszyfer@protonmail.com>2022-11-22 11:51:33 -0300
committerfurszy <matiasfurszyfer@protonmail.com>2022-12-02 12:39:15 -0300
commitc4e3b7d6a154e82cdb902fd7bcb7b725aebde5ea (patch)
treee675087c7edfe2b57d071702e51b66cd0bfd6770 /src/wallet
parentcac2725fd0f5baeb741dfe079a87332784c2adc7 (diff)
downloadbitcoin-c4e3b7d6a154e82cdb902fd7bcb7b725aebde5ea.tar.xz
wallet: SelectCoins, return early if wallet's UTXOs cannot cover the target
The CoinsResult class will now count the raw total amount and the effective total amount internally (inside the 'CoinsResult::Add' and 'CoinsResult::Erase' methods). So there is no discrepancy between what we add/erase and the total values. (which is what was happening on the coinselector_test because the 'CoinsResult' object is manually created there, and we were not keeping the total amount in sync with the outputs being added/removed).
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/coinselection.h2
-rw-r--r--src/wallet/spend.cpp23
-rw-r--r--src/wallet/spend.h4
3 files changed, 25 insertions, 4 deletions
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index b23dd10867..b02e006435 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -110,6 +110,8 @@ public:
assert(effective_value.has_value());
return effective_value.value();
}
+
+ bool HasEffectiveValue() const { return effective_value.has_value(); }
};
/** Parameters for one iteration of Coin Selection. */
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 5f4e3e79c7..19f9048dbf 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -106,7 +106,13 @@ void CoinsResult::Erase(const std::unordered_set<COutPoint, SaltedOutpointHasher
{
for (auto& [type, vec] : coins) {
auto remove_it = std::remove_if(vec.begin(), vec.end(), [&](const COutput& coin) {
- return coins_to_remove.count(coin.outpoint) == 1;
+ // remove it if it's on the set
+ if (coins_to_remove.count(coin.outpoint) == 0) return false;
+
+ // update cached amounts
+ total_amount -= coin.txout.nValue;
+ if (coin.HasEffectiveValue()) total_effective_amount = *total_effective_amount - coin.GetEffectiveValue();
+ return true;
});
vec.erase(remove_it, vec.end());
}
@@ -122,6 +128,11 @@ void CoinsResult::Shuffle(FastRandomContext& rng_fast)
void CoinsResult::Add(OutputType type, const COutput& out)
{
coins[type].emplace_back(out);
+ total_amount += out.txout.nValue;
+ if (out.HasEffectiveValue()) {
+ total_effective_amount = total_effective_amount.has_value() ?
+ *total_effective_amount + out.GetEffectiveValue() : out.GetEffectiveValue();
+ }
}
static OutputType GetOutputType(TxoutType type, bool is_from_p2sh)
@@ -319,8 +330,6 @@ CoinsResult AvailableCoins(const CWallet& wallet,
result.Add(GetOutputType(type, is_from_p2sh),
COutput(outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime(), tx_from_me, feerate));
- // Cache total amount as we go
- result.total_amount += output.nValue;
// Checks the sum amount of all UTXO's.
if (params.min_sum_amount != MAX_MONEY) {
if (result.total_amount >= params.min_sum_amount) {
@@ -575,6 +584,14 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
return result;
}
+ // Return early if we cannot cover the target with the wallet's UTXO.
+ // We use the total effective value if we are not subtracting fee from outputs and 'available_coins' contains the data.
+ CAmount available_coins_total_amount = coin_selection_params.m_subtract_fee_outputs ? available_coins.total_amount :
+ (available_coins.total_effective_amount.has_value() ? *available_coins.total_effective_amount : 0);
+ if (selection_target > available_coins_total_amount) {
+ return std::nullopt; // Insufficient funds
+ }
+
// Start wallet Coin Selection procedure
auto op_selection_result = AutomaticCoinSelection(wallet, available_coins, selection_target, coin_control, coin_selection_params);
if (!op_selection_result) return op_selection_result;
diff --git a/src/wallet/spend.h b/src/wallet/spend.h
index df57fc1362..8612ce49ad 100644
--- a/src/wallet/spend.h
+++ b/src/wallet/spend.h
@@ -51,8 +51,10 @@ struct CoinsResult {
void Shuffle(FastRandomContext& rng_fast);
void Add(OutputType type, const COutput& out);
- /** Sum of all available coins */
+ /** Sum of all available coins raw value */
CAmount total_amount{0};
+ /** Sum of all available coins effective value (each output value minus fees required to spend it) */
+ std::optional<CAmount> total_effective_amount{0};
};
struct CoinFilterParams {