13
13
14
14
#include < numeric>
15
15
#include < optional>
16
+ #include < queue>
16
17
17
18
namespace wallet {
18
19
// Common selection error across the algorithms
@@ -172,9 +173,20 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
172
173
return result;
173
174
}
174
175
175
- util::Result<SelectionResult> SelectCoinsSRD (const std::vector<OutputGroup>& utxo_pool, CAmount target_value, FastRandomContext& rng)
176
+ class MinOutputGroupComparator
177
+ {
178
+ public:
179
+ int operator () (const OutputGroup& group1, const OutputGroup& group2) const
180
+ {
181
+ return group1.GetSelectionAmount () > group2.GetSelectionAmount ();
182
+ }
183
+ };
184
+
185
+ util::Result<SelectionResult> SelectCoinsSRD (const std::vector<OutputGroup>& utxo_pool, CAmount target_value, FastRandomContext& rng,
186
+ int max_weight)
176
187
{
177
188
SelectionResult result (target_value, SelectionAlgorithm::SRD);
189
+ std::priority_queue<OutputGroup, std::vector<OutputGroup>, MinOutputGroupComparator> heap;
178
190
179
191
// Include change for SRD as we want to avoid making really small change if the selection just
180
192
// barely meets the target. Just use the lower bound change target instead of the randomly
@@ -188,16 +200,40 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx
188
200
Shuffle (indexes.begin (), indexes.end (), rng);
189
201
190
202
CAmount selected_eff_value = 0 ;
203
+ int weight = 0 ;
204
+ bool max_tx_weight_exceeded = false ;
191
205
for (const size_t i : indexes) {
192
206
const OutputGroup& group = utxo_pool.at (i);
193
207
Assume (group.GetSelectionAmount () > 0 );
208
+
209
+ // Add group to selection
210
+ heap.push (group);
194
211
selected_eff_value += group.GetSelectionAmount ();
195
- result.AddInput (group);
212
+ weight += group.m_weight ;
213
+
214
+ // If the selection weight exceeds the maximum allowed size, remove the least valuable inputs until we
215
+ // are below max weight.
216
+ if (weight > max_weight) {
217
+ max_tx_weight_exceeded = true ; // mark it in case we don't find any useful result.
218
+ do {
219
+ const OutputGroup& to_remove_group = heap.top ();
220
+ selected_eff_value -= to_remove_group.GetSelectionAmount ();
221
+ weight -= to_remove_group.m_weight ;
222
+ heap.pop ();
223
+ } while (!heap.empty () && weight > max_weight);
224
+ }
225
+
226
+ // Now check if we are above the target
196
227
if (selected_eff_value >= target_value) {
228
+ // Result found, add it.
229
+ while (!heap.empty ()) {
230
+ result.AddInput (heap.top ());
231
+ heap.pop ();
232
+ }
197
233
return result;
198
234
}
199
235
}
200
- return util::Error ();
236
+ return max_tx_weight_exceeded ? ErrorMaxWeightExceeded () : util::Error ();
201
237
}
202
238
203
239
/* * Find a subset of the OutputGroups that is at least as large as, but as close as possible to, the
0 commit comments