Skip to content

Commit 609c95d

Browse files
committed
Merge bitcoin/bitcoin#27227: wallet: 25806 follow-up
475c20a wallet: remove coin control arg from AutomaticCoinSelection (furszy) 8a55831 wallet: remove unused methods (furszy) 8471967 wallet: GroupOutput, remove unneeded "spendable" check (furszy) a9aa041 wallet: OutputGroup, remove unused effective_feerate member (furszy) 99034b2 wallet: APS, don't create empty groups (furszy) 805f399 wallet: do not make two COutputs, use shared_ptr (furszy) Pull request description: Few small findings post-#25806 and extra cleanups, nothing biggie. ACKs for top commit: S3RK: Code review ACK 475c20a Xekyo: utACK 475c20a achow101: ACK 475c20a Tree-SHA512: df45efebd6e2e4ecac619d6ecef794979c328a2d6ef532e25124d0dc1c72b55ccf13498f61fb65958b907bfba6a72ed569bf34eb5fbe35419632fe0406e78798
2 parents cbfbf46 + 475c20a commit 609c95d

File tree

5 files changed

+27
-46
lines changed

5 files changed

+27
-46
lines changed

src/wallet/coinselection.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -387,13 +387,6 @@ void OutputGroupTypeMap::Push(const OutputGroup& group, OutputType type, bool in
387387
}
388388
}
389389

390-
std::optional<Groups> OutputGroupTypeMap::Find(OutputType type)
391-
{
392-
auto it_by_type = groups_by_type.find(type);
393-
if (it_by_type == groups_by_type.end()) return std::nullopt;
394-
return it_by_type->second;
395-
}
396-
397390
CAmount GetSelectionWaste(const std::set<std::shared_ptr<COutput>>& inputs, CAmount change_cost, CAmount target, bool use_effective_value)
398391
{
399392
// This function should not be called with empty inputs as that would mean the selection failed

src/wallet/coinselection.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ struct CoinSelectionParams {
153153
* associated with the same address. This helps reduce privacy leaks resulting from address
154154
* reuse. Dust outputs are not eligible to be added to output groups and thus not considered. */
155155
bool m_avoid_partial_spends = false;
156+
/**
157+
* When true, allow unsafe coins to be selected during Coin Selection. This may spend unconfirmed outputs:
158+
* 1) Received from other wallets, 2) replacing other txs, 3) that have been replaced.
159+
*/
160+
bool m_include_unsafe_inputs = false;
156161

157162
CoinSelectionParams(FastRandomContext& rng_fast, size_t change_output_size, size_t change_spend_size,
158163
CAmount min_change_target, CFeeRate effective_feerate,
@@ -222,8 +227,6 @@ struct OutputGroup
222227
CAmount effective_value{0};
223228
/** The fee to spend these UTXOs at the effective feerate. */
224229
CAmount fee{0};
225-
/** The target feerate of the transaction we're trying to build. */
226-
CFeeRate m_effective_feerate{0};
227230
/** The fee to spend these UTXOs at the long term feerate. */
228231
CAmount long_term_fee{0};
229232
/** The feerate for spending a created change output eventually (i.e. not urgently, and thus at
@@ -238,7 +241,6 @@ struct OutputGroup
238241

239242
OutputGroup() {}
240243
OutputGroup(const CoinSelectionParams& params) :
241-
m_effective_feerate(params.m_effective_feerate),
242244
m_long_term_feerate(params.m_long_term_feerate),
243245
m_subtract_fee_outputs(params.m_subtract_fee_outputs)
244246
{}
@@ -266,8 +268,6 @@ struct OutputGroupTypeMap
266268
// Based on the insert flag; appends group to the 'mixed_group' and, if value > 0, to the 'positive_group'.
267269
// This affects both; the groups filtered by type and the overall groups container.
268270
void Push(const OutputGroup& group, OutputType type, bool insert_positive, bool insert_mixed);
269-
// Retrieves 'Groups' filtered by type
270-
std::optional<Groups> Find(OutputType type);
271271
// Different output types count
272272
size_t TypesCount() { return groups_by_type.size(); }
273273
};

src/wallet/spend.cpp

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,6 @@ FilteredOutputGroups GroupOutputs(const CWallet& wallet,
415415
// Allowing partial spends means no grouping. Each COutput gets its own OutputGroup
416416
for (const auto& [type, outputs] : coins.coins) {
417417
for (const COutput& output : outputs) {
418-
// Skip outputs we cannot spend
419-
if (!output.spendable) continue;
420-
421418
// Get mempool info
422419
size_t ancestors, descendants;
423420
wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
@@ -444,11 +441,10 @@ FilteredOutputGroups GroupOutputs(const CWallet& wallet,
444441
// to the last OutputGroup in the vector for the scriptPubKey. When the last OutputGroup has
445442
// OUTPUT_GROUP_MAX_ENTRIES COutputs, a new OutputGroup is added to the end of the vector.
446443
typedef std::map<std::pair<CScript, OutputType>, std::vector<OutputGroup>> ScriptPubKeyToOutgroup;
447-
const auto& group_outputs = [](
448-
const COutput& output, OutputType type, size_t ancestors, size_t descendants,
449-
ScriptPubKeyToOutgroup& groups_map, const CoinSelectionParams& coin_sel_params,
450-
bool positive_only) {
451-
std::vector<OutputGroup>& groups = groups_map[std::make_pair(output.txout.scriptPubKey,type)];
444+
const auto& insert_output = [&](
445+
const std::shared_ptr<COutput>& output, OutputType type, size_t ancestors, size_t descendants,
446+
ScriptPubKeyToOutgroup& groups_map) {
447+
std::vector<OutputGroup>& groups = groups_map[std::make_pair(output->txout.scriptPubKey,type)];
452448

453449
if (groups.size() == 0) {
454450
// No OutputGroups for this scriptPubKey yet, add one
@@ -467,25 +463,24 @@ FilteredOutputGroups GroupOutputs(const CWallet& wallet,
467463
group = &groups.back();
468464
}
469465

470-
// Filter for positive only before adding the output to group
471-
if (!positive_only || output.GetEffectiveValue() > 0) {
472-
group->Insert(std::make_shared<COutput>(output), ancestors, descendants);
473-
}
466+
group->Insert(output, ancestors, descendants);
474467
};
475468

476469
ScriptPubKeyToOutgroup spk_to_groups_map;
477470
ScriptPubKeyToOutgroup spk_to_positive_groups_map;
478471
for (const auto& [type, outs] : coins.coins) {
479472
for (const COutput& output : outs) {
480-
// Skip outputs we cannot spend
481-
if (!output.spendable) continue;
482-
483473
size_t ancestors, descendants;
484474
wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
485475

486-
group_outputs(output, type, ancestors, descendants, spk_to_groups_map, coin_sel_params, /*positive_only=*/ false);
487-
group_outputs(output, type, ancestors, descendants, spk_to_positive_groups_map,
488-
coin_sel_params, /*positive_only=*/ true);
476+
const auto& shared_output = std::make_shared<COutput>(output);
477+
// Filter for positive only before adding the output
478+
if (output.GetEffectiveValue() > 0) {
479+
insert_output(shared_output, type, ancestors, descendants, spk_to_positive_groups_map);
480+
}
481+
482+
// 'All' groups
483+
insert_output(shared_output, type, ancestors, descendants, spk_to_groups_map);
489484
}
490485
}
491486

@@ -622,7 +617,7 @@ util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& av
622617
}
623618

624619
// Start wallet Coin Selection procedure
625-
auto op_selection_result = AutomaticCoinSelection(wallet, available_coins, selection_target, coin_control, coin_selection_params);
620+
auto op_selection_result = AutomaticCoinSelection(wallet, available_coins, selection_target, coin_selection_params);
626621
if (!op_selection_result) return op_selection_result;
627622

628623
// If needed, add preset inputs to the automatic coin selection result
@@ -637,7 +632,7 @@ util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& av
637632
return op_selection_result;
638633
}
639634

640-
util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& value_to_select, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
635+
util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& value_to_select, const CoinSelectionParams& coin_selection_params)
641636
{
642637
unsigned int limit_ancestor_count = 0;
643638
unsigned int limit_descendant_count = 0;
@@ -646,12 +641,10 @@ util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, Coin
646641
const size_t max_descendants = (size_t)std::max<int64_t>(1, limit_descendant_count);
647642
const bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
648643

649-
// form groups from remaining coins; note that preset coins will not
650-
// automatically have their associated (same address) coins included
651-
if (coin_control.m_avoid_partial_spends && available_coins.Size() > OUTPUT_GROUP_MAX_ENTRIES) {
652-
// Cases where we have 101+ outputs all pointing to the same destination may result in
653-
// privacy leaks as they will potentially be deterministically sorted. We solve that by
654-
// explicitly shuffling the outputs before processing
644+
// Cases where we have 101+ outputs all pointing to the same destination may result in
645+
// privacy leaks as they will potentially be deterministically sorted. We solve that by
646+
// explicitly shuffling the outputs before processing
647+
if (coin_selection_params.m_avoid_partial_spends && available_coins.Size() > OUTPUT_GROUP_MAX_ENTRIES) {
655648
available_coins.Shuffle(coin_selection_params.rng_fast);
656649
}
657650

@@ -678,7 +671,7 @@ util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, Coin
678671
ordered_filters.push_back({CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, /*include_partial=*/true)});
679672
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
680673
// received from other wallets.
681-
if (coin_control.m_include_unsafe_inputs) {
674+
if (coin_selection_params.m_include_unsafe_inputs) {
682675
ordered_filters.push_back({CoinEligibilityFilter(/*conf_mine=*/0, /*conf_theirs*/0, max_ancestors-1, max_descendants-1, /*include_partial=*/true)});
683676
}
684677
// Try with unlimited ancestors/descendants. The transaction will still need to meet
@@ -809,6 +802,7 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
809802

810803
CoinSelectionParams coin_selection_params{rng_fast}; // Parameters for coin selection, init with dummy
811804
coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends;
805+
coin_selection_params.m_include_unsafe_inputs = coin_control.m_include_unsafe_inputs;
812806

813807
// Set the long term feerate estimate to the wallet's consolidate feerate
814808
coin_selection_params.m_long_term_feerate = wallet.m_consolidate_feerate;

src/wallet/spend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const
191191
* or (2) an specific error message if there was something particularly wrong (e.g. a selection
192192
* result that surpassed the tx max weight size).
193193
*/
194-
util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control,
194+
util::Result<SelectionResult> AutomaticCoinSelection(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue,
195195
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
196196

197197
/**

src/wallet/wallet.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -592,12 +592,6 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
592592
bool SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const
593593
EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
594594

595-
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, const CCoinControl* coin_control = nullptr) const
596-
{
597-
std::vector<CTxOut> v_txouts(txouts.size());
598-
std::copy(txouts.begin(), txouts.end(), v_txouts.begin());
599-
return DummySignTx(txNew, v_txouts, coin_control);
600-
}
601595
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, const CCoinControl* coin_control = nullptr) const;
602596

603597
bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);

0 commit comments

Comments
 (0)