@@ -327,15 +327,20 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c
327
327
std::sort (utxo_pool.begin (), utxo_pool.end (), descending_effval_weight);
328
328
// The sum of UTXO amounts after this UTXO index, e.g. lookahead[5] = Σ(UTXO[6+].amount)
329
329
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 ());
330
332
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
332
334
CAmount total_available = 0 ;
335
+ int min_group_weight = std::numeric_limits<int >::max ();
333
336
for (size_t i = 0 ; i < utxo_pool.size (); ++i) {
334
337
size_t index = utxo_pool.size () - 1 - i; // Loop over every element in reverse order
335
338
lookahead[index] = total_available;
339
+ min_tail_weight[index] = min_group_weight;
336
340
// UTXOs with non-positive effective value must have been filtered
337
341
Assume (utxo_pool[index].GetSelectionAmount () > 0 );
338
342
total_available += utxo_pool[index].GetSelectionAmount ();
343
+ min_group_weight = std::min (min_group_weight, utxo_pool[index].m_weight );
339
344
}
340
345
341
346
const CAmount total_target = selection_target + change_target;
@@ -426,16 +431,26 @@ util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, c
426
431
++curr_try;
427
432
428
433
// 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) {
430
436
// Insufficient funds with lookahead: CUT
431
437
should_cut = true ;
432
438
} 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
434
440
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
+ }
436
446
} 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
+ }
439
454
} else if (curr_amount >= total_target) {
440
455
// Success, adding more weight cannot be better: SHIFT
441
456
should_shift = true ;
0 commit comments