Skip to content

Commit

Permalink
Add Largest First Selector
Browse files Browse the repository at this point in the history
  • Loading branch information
murchandamus committed Apr 17, 2024
1 parent b5dc6c6 commit 7d7f516
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
28 changes: 28 additions & 0 deletions src/wallet/coinselection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,34 @@ class MinOutputGroupComparator
}
};

util::Result<SelectionResult> LargestFirst(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_weight)
{
SelectionResult result(selection_target, SelectionAlgorithm::LF);

// Include a minimum change budget for Largest First as we want to avoid
// making really small change if the selection just barely meets the target.
const CAmount total_target = selection_target + change_target;

std::sort(utxo_pool.begin(), utxo_pool.end(), descending);
CAmount selected_amount = 0;
int weight = 0;

for (const OutputGroup& group : utxo_pool) {
weight += group.m_weight;
selected_amount += group.GetSelectionAmount();
result.AddInput(group);
if (weight > max_weight) {
return ErrorMaxWeightExceeded();
}
if (selected_amount >= total_target) {
return result;
}
}

// Didn’t find a solution
return util::Error();
}

util::Result<SelectionResult> SandCompactor(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_weight)
{
SelectionResult result(selection_target, SelectionAlgorithm::SC);
Expand Down
14 changes: 13 additions & 1 deletion src/wallet/coinselection.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ enum class SelectionAlgorithm : uint8_t
SRD = 2,
CG = 3,
SC = 4,
MANUAL = 5,
LF = 5,
MANUAL = 6,
};

std::string GetAlgorithmName(const SelectionAlgorithm algo);
Expand Down Expand Up @@ -450,6 +451,17 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool

util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_weight);

/**
* Largest first selector picks UTXOs from highest effective value to lowest effective value.
*
* @param[in] utxo_pool The OutputGroups eligible for selection
* @param[in] selection_target The target value to select for
* @param[in] change_target The minimum budget necessary to create a change output
* @param[in] max_weight The maximum allowed weight for a selection result to be valid
* @returns If successful, a valid SelectionResult, otherwise, util::Error
*/
util::Result<SelectionResult> LargestFirst(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_weight);


/**
* Sand Compactor selects OutputGroups by descending confirmation count (FIFO). If there are multiple UTXOs in an
Expand Down
5 changes: 5 additions & 0 deletions src/wallet/spend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,11 @@ util::Result<SelectionResult> ChooseSelectionResult(interfaces::Chain& chain, co
}
}

// Allow Largest First to spend UTXOs with negative effective value at any feerate
if (auto lf_result{LargestFirst(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, max_inputs_weight)}) {
results.push_back(*lf_result);
} else append_error(lf_result);

// Allow SandCompactor to spend UTXOs with negative effective value at any feerate
if (auto sc_result{SandCompactor(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, max_inputs_weight)}) {
results.push_back(*sc_result);
Expand Down

0 comments on commit 7d7f516

Please sign in to comment.