mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-12 06:58:57 +01:00
refactor coin selection for parameterizable change target
no behavior changes, since the target is always MIN_CHANGE
This commit is contained in:
@@ -187,11 +187,24 @@ std::optional<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& ut
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::vector<OutputGroup>& groups, const CAmount& nTotalLower, const CAmount& nTargetValue,
|
||||
/** Find a subset of the OutputGroups that is at least as large as, but as close as possible to, the
|
||||
* target amount; solve subset sum.
|
||||
* param@[in] groups OutputGroups to choose from, sorted by value in descending order.
|
||||
* param@[in] nTotalLower Total (effective) value of the UTXOs in groups.
|
||||
* param@[in] nTargetValue Subset sum target, not including change.
|
||||
* param@[out] vfBest Boolean vector representing the subset chosen that is closest to
|
||||
* nTargetValue, with indices corresponding to groups. If the ith
|
||||
* entry is true, that means the ith group in groups was selected.
|
||||
* param@[out] nBest Total amount of subset chosen that is closest to nTargetValue.
|
||||
* param@[in] iterations Maximum number of tries.
|
||||
*/
|
||||
static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::vector<OutputGroup>& groups,
|
||||
const CAmount& nTotalLower, const CAmount& nTargetValue,
|
||||
std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
|
||||
{
|
||||
std::vector<char> vfIncluded;
|
||||
|
||||
// Worst case "best" approximation is just all of the groups.
|
||||
vfBest.assign(groups.size(), true);
|
||||
nBest = nTotalLower;
|
||||
|
||||
@@ -217,6 +230,8 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
|
||||
if (nTotal >= nTargetValue)
|
||||
{
|
||||
fReachedTarget = true;
|
||||
// If the total is between nTargetValue and nBest, it's our new best
|
||||
// approximation.
|
||||
if (nTotal < nBest)
|
||||
{
|
||||
nBest = nTotal;
|
||||
@@ -231,12 +246,15 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue, FastRandomContext& rng)
|
||||
std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
|
||||
CAmount change_target, FastRandomContext& rng)
|
||||
{
|
||||
SelectionResult result(nTargetValue);
|
||||
|
||||
// List of values less than target
|
||||
std::optional<OutputGroup> lowest_larger;
|
||||
// Groups with selection amount smaller than the target and any change we might produce.
|
||||
// Don't include groups larger than this, because they will only cause us to overshoot.
|
||||
std::vector<OutputGroup> applicable_groups;
|
||||
CAmount nTotalLower = 0;
|
||||
|
||||
@@ -246,7 +264,7 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
|
||||
if (group.GetSelectionAmount() == nTargetValue) {
|
||||
result.AddInput(group);
|
||||
return result;
|
||||
} else if (group.GetSelectionAmount() < nTargetValue + MIN_CHANGE) {
|
||||
} else if (group.GetSelectionAmount() < nTargetValue + change_target) {
|
||||
applicable_groups.push_back(group);
|
||||
nTotalLower += group.GetSelectionAmount();
|
||||
} else if (!lowest_larger || group.GetSelectionAmount() < lowest_larger->GetSelectionAmount()) {
|
||||
@@ -273,14 +291,14 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
|
||||
CAmount nBest;
|
||||
|
||||
ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
|
||||
if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) {
|
||||
ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
|
||||
if (nBest != nTargetValue && nTotalLower >= nTargetValue + change_target) {
|
||||
ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue + change_target, vfBest, nBest);
|
||||
}
|
||||
|
||||
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
|
||||
// or the next bigger coin is closer), return the bigger coin
|
||||
if (lowest_larger &&
|
||||
((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || lowest_larger->GetSelectionAmount() <= nBest)) {
|
||||
((nBest != nTargetValue && nBest < nTargetValue + change_target) || lowest_larger->GetSelectionAmount() <= nBest)) {
|
||||
result.AddInput(*lowest_larger);
|
||||
} else {
|
||||
for (unsigned int i = 0; i < applicable_groups.size(); i++) {
|
||||
|
||||
Reference in New Issue
Block a user