@@ -597,11 +597,12 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx
597
597
* nTargetValue, with indices corresponding to groups. If the ith
598
598
* entry is true, that means the ith group in groups was selected.
599
599
* param@[out] nBest Total amount of subset chosen that is closest to nTargetValue.
600
+ * paramp[in] max_selection_weight The maximum allowed weight for a selection result to be valid.
600
601
* param@[in] iterations Maximum number of tries.
601
602
*/
602
603
static void ApproximateBestSubset (FastRandomContext& insecure_rand, const std::vector<OutputGroup>& groups,
603
604
const CAmount& nTotalLower, const CAmount& nTargetValue,
604
- std::vector<char >& vfBest, CAmount& nBest, int iterations = 1000 )
605
+ std::vector<char >& vfBest, CAmount& nBest, int max_selection_weight, int iterations = 1000 )
605
606
{
606
607
std::vector<char > vfIncluded;
607
608
@@ -613,6 +614,7 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
613
614
{
614
615
vfIncluded.assign (groups.size (), false );
615
616
CAmount nTotal = 0 ;
617
+ int selected_coins_weight{0 };
616
618
bool fReachedTarget = false ;
617
619
for (int nPass = 0 ; nPass < 2 && !fReachedTarget ; nPass++)
618
620
{
@@ -627,9 +629,9 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
627
629
if (nPass == 0 ? insecure_rand.randbool () : !vfIncluded[i])
628
630
{
629
631
nTotal += groups[i].GetSelectionAmount ();
632
+ selected_coins_weight += groups[i].m_weight ;
630
633
vfIncluded[i] = true ;
631
- if (nTotal >= nTargetValue)
632
- {
634
+ if (nTotal >= nTargetValue && selected_coins_weight <= max_selection_weight) {
633
635
fReachedTarget = true ;
634
636
// If the total is between nTargetValue and nBest, it's our new best
635
637
// approximation.
@@ -639,6 +641,7 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
639
641
vfBest = vfIncluded;
640
642
}
641
643
nTotal -= groups[i].GetSelectionAmount ();
644
+ selected_coins_weight -= groups[i].m_weight ;
642
645
vfIncluded[i] = false ;
643
646
}
644
647
}
@@ -652,6 +655,7 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
652
655
{
653
656
SelectionResult result (nTargetValue, SelectionAlgorithm::KNAPSACK);
654
657
658
+ bool max_weight_exceeded{false };
655
659
// List of values less than target
656
660
std::optional<OutputGroup> lowest_larger;
657
661
// Groups with selection amount smaller than the target and any change we might produce.
@@ -662,6 +666,10 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
662
666
Shuffle (groups.begin (), groups.end (), rng);
663
667
664
668
for (const OutputGroup& group : groups) {
669
+ if (group.m_weight > max_selection_weight) {
670
+ max_weight_exceeded = true ;
671
+ continue ;
672
+ }
665
673
if (group.GetSelectionAmount () == nTargetValue) {
666
674
result.AddInput (group);
667
675
return result;
@@ -677,11 +685,18 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
677
685
for (const auto & group : applicable_groups) {
678
686
result.AddInput (group);
679
687
}
680
- return result;
688
+ if (result.GetWeight () <= max_selection_weight) return result;
689
+ else max_weight_exceeded = true ;
690
+
691
+ // Try something else
692
+ result.Clear ();
681
693
}
682
694
683
695
if (nTotalLower < nTargetValue) {
684
- if (!lowest_larger) return util::Error ();
696
+ if (!lowest_larger) {
697
+ if (max_weight_exceeded) return ErrorMaxWeightExceeded ();
698
+ return util::Error ();
699
+ }
685
700
result.AddInput (*lowest_larger);
686
701
return result;
687
702
}
@@ -691,9 +706,9 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
691
706
std::vector<char > vfBest;
692
707
CAmount nBest;
693
708
694
- ApproximateBestSubset (rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
709
+ ApproximateBestSubset (rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest, max_selection_weight );
695
710
if (nBest != nTargetValue && nTotalLower >= nTargetValue + change_target) {
696
- ApproximateBestSubset (rng, applicable_groups, nTotalLower, nTargetValue + change_target, vfBest, nBest);
711
+ ApproximateBestSubset (rng, applicable_groups, nTotalLower, nTargetValue + change_target, vfBest, nBest, max_selection_weight );
697
712
}
698
713
699
714
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
@@ -728,7 +743,7 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
728
743
LogPrint (BCLog::SELECTCOINS, " %stotal %s\n " , log_message, FormatMoney (nBest));
729
744
}
730
745
}
731
-
746
+ Assume (result. GetWeight () <= max_selection_weight);
732
747
return result;
733
748
}
734
749
0 commit comments