@@ -327,15 +327,20 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c
327327 std::sort (utxo_pool.begin (), utxo_pool.end (), descending_effval_weight);
328328 // The sum of UTXO amounts after this UTXO index, e.g. lookahead[5] = Σ(UTXO[6+].amount)
329329 std::vector<CAmount> lookahead (utxo_pool.size ());
330+ // The minimum UTXO weight among the remaining UTXOs after this UTXO index, e.g. min_tail_weight[5] = min(UTXO[6+].weight)
331+ std::vector<int > min_tail_weight (utxo_pool.size ());
330332
331- // Calculate lookahead values, and check that there are sufficient funds
333+ // Calculate lookahead values, min_tail_weights, and check that there are sufficient funds
332334 CAmount total_available = 0 ;
335+ int min_group_weight = std::numeric_limits<int >::max ();
333336 for (size_t i = 0 ; i < utxo_pool.size (); ++i) {
334337 size_t index = utxo_pool.size () - 1 - i; // Loop over every element in reverse order
335338 lookahead[index] = total_available;
339+ min_tail_weight[index] = min_group_weight;
336340 // UTXOs with non-positive effective value must have been filtered
337341 Assume (utxo_pool[index].GetSelectionAmount () > 0 );
338342 total_available += utxo_pool[index].GetSelectionAmount ();
343+ min_group_weight = std::min (min_group_weight, utxo_pool[index].m_weight );
339344 }
340345
341346 const CAmount total_target = selection_target + change_target;
@@ -426,16 +431,26 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c
426431 ++curr_try;
427432
428433 // EVALUATE current selection: check for solutions and see whether we can CUT or SHIFT before EXPLORING further
429- if (curr_amount + lookahead[curr_selection.back ()] < total_target) {
434+ auto curr_tail = curr_selection.back ();
435+ if (curr_amount + lookahead[curr_tail] < total_target) {
430436 // Insufficient funds with lookahead: CUT
431437 should_cut = true ;
432438 } else if (curr_weight > max_weight) {
433- // max_weight exceeded: SHIFT
439+ // max_weight exceeded: CUT if last selected group had minimal weight, else SHIFT
434440 max_tx_weight_exceeded = true ;
435- should_shift = true ;
441+ if (utxo_pool[curr_tail].m_weight <= min_tail_weight[curr_tail]) {
442+ should_cut = true ;
443+ } else {
444+ should_shift = true ;
445+ }
436446 } else if (curr_weight > best_selection_weight) {
437- // Worse weight than best solution. More UTXOs only increase weight: SHIFT
438- should_shift = true ;
447+ // Worse weight than best solution. More UTXOs only increase weight:
448+ // CUT if last selected group had minimal weight, else SHIFT
449+ if (utxo_pool[curr_tail].m_weight <= min_tail_weight[curr_tail]) {
450+ should_cut = true ;
451+ } else {
452+ should_shift = true ;
453+ }
439454 } else if (curr_amount >= total_target) {
440455 // Success, adding more weight cannot be better: SHIFT
441456 should_shift = true ;
0 commit comments