@@ -597,11 +597,12 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx
597597 * nTargetValue, with indices corresponding to groups. If the ith
598598 * entry is true, that means the ith group in groups was selected.
599599 * 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.
600601 * param@[in] iterations Maximum number of tries.
601602 */
602603static void ApproximateBestSubset (FastRandomContext& insecure_rand, const std::vector<OutputGroup>& groups,
603604 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 )
605606{
606607 std::vector<char > vfIncluded;
607608
@@ -613,6 +614,7 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
613614 {
614615 vfIncluded.assign (groups.size (), false );
615616 CAmount nTotal = 0 ;
617+ int selected_coins_weight{0 };
616618 bool fReachedTarget = false ;
617619 for (int nPass = 0 ; nPass < 2 && !fReachedTarget ; nPass++)
618620 {
@@ -627,9 +629,9 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
627629 if (nPass == 0 ? insecure_rand.randbool () : !vfIncluded[i])
628630 {
629631 nTotal += groups[i].GetSelectionAmount ();
632+ selected_coins_weight += groups[i].m_weight ;
630633 vfIncluded[i] = true ;
631- if (nTotal >= nTargetValue)
632- {
634+ if (nTotal >= nTargetValue && selected_coins_weight <= max_selection_weight) {
633635 fReachedTarget = true ;
634636 // If the total is between nTargetValue and nBest, it's our new best
635637 // approximation.
@@ -639,6 +641,7 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
639641 vfBest = vfIncluded;
640642 }
641643 nTotal -= groups[i].GetSelectionAmount ();
644+ selected_coins_weight -= groups[i].m_weight ;
642645 vfIncluded[i] = false ;
643646 }
644647 }
@@ -652,6 +655,7 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
652655{
653656 SelectionResult result (nTargetValue, SelectionAlgorithm::KNAPSACK);
654657
658+ bool max_weight_exceeded{false };
655659 // List of values less than target
656660 std::optional<OutputGroup> lowest_larger;
657661 // 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
662666 Shuffle (groups.begin (), groups.end (), rng);
663667
664668 for (const OutputGroup& group : groups) {
669+ if (group.m_weight > max_selection_weight) {
670+ max_weight_exceeded = true ;
671+ continue ;
672+ }
665673 if (group.GetSelectionAmount () == nTargetValue) {
666674 result.AddInput (group);
667675 return result;
@@ -677,11 +685,18 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
677685 for (const auto & group : applicable_groups) {
678686 result.AddInput (group);
679687 }
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 ();
681693 }
682694
683695 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+ }
685700 result.AddInput (*lowest_larger);
686701 return result;
687702 }
@@ -691,9 +706,9 @@ util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, c
691706 std::vector<char > vfBest;
692707 CAmount nBest;
693708
694- ApproximateBestSubset (rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
709+ ApproximateBestSubset (rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest, max_selection_weight );
695710 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 );
697712 }
698713
699714 // 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
728743 LogPrint (BCLog::SELECTCOINS, " %stotal %s\n " , log_message, FormatMoney (nBest));
729744 }
730745 }
731-
746+ Assume (result. GetWeight () <= max_selection_weight);
732747 return result;
733748}
734749
0 commit comments