8
8
9
9
// Descending order comparator
10
10
struct {
11
- bool operator ()(const CInputCoin & a, const CInputCoin & b) const
11
+ bool operator ()(const OutputGroup & a, const OutputGroup & b) const
12
12
{
13
13
return a.effective_value > b.effective_value ;
14
14
}
@@ -59,7 +59,7 @@ struct {
59
59
60
60
static const size_t TOTAL_TRIES = 100000 ;
61
61
62
- bool SelectCoinsBnB (std::vector<CInputCoin >& utxo_pool, const CAmount& target_value, const CAmount& cost_of_change, std::set<CInputCoin>& out_set, CAmount& value_ret, CAmount not_input_fees)
62
+ bool SelectCoinsBnB (std::vector<OutputGroup >& utxo_pool, const CAmount& target_value, const CAmount& cost_of_change, std::set<CInputCoin>& out_set, CAmount& value_ret, CAmount not_input_fees)
63
63
{
64
64
out_set.clear ();
65
65
CAmount curr_value = 0 ;
@@ -70,7 +70,7 @@ bool SelectCoinsBnB(std::vector<CInputCoin>& utxo_pool, const CAmount& target_va
70
70
71
71
// Calculate curr_available_value
72
72
CAmount curr_available_value = 0 ;
73
- for (const CInputCoin & utxo : utxo_pool) {
73
+ for (const OutputGroup & utxo : utxo_pool) {
74
74
// Assert that this utxo is not negative. It should never be negative, effective value calculation should have removed it
75
75
assert (utxo.effective_value > 0 );
76
76
curr_available_value += utxo.effective_value ;
@@ -123,11 +123,11 @@ bool SelectCoinsBnB(std::vector<CInputCoin>& utxo_pool, const CAmount& target_va
123
123
124
124
// Output was included on previous iterations, try excluding now.
125
125
curr_selection.back () = false ;
126
- CInputCoin & utxo = utxo_pool.at (curr_selection.size () - 1 );
126
+ OutputGroup & utxo = utxo_pool.at (curr_selection.size () - 1 );
127
127
curr_value -= utxo.effective_value ;
128
128
curr_waste -= utxo.fee - utxo.long_term_fee ;
129
129
} else { // Moving forwards, continuing down this branch
130
- CInputCoin & utxo = utxo_pool.at (curr_selection.size ());
130
+ OutputGroup & utxo = utxo_pool.at (curr_selection.size ());
131
131
132
132
// Remove this utxo from the curr_available_value utxo amount
133
133
curr_available_value -= utxo.effective_value ;
@@ -156,32 +156,32 @@ bool SelectCoinsBnB(std::vector<CInputCoin>& utxo_pool, const CAmount& target_va
156
156
value_ret = 0 ;
157
157
for (size_t i = 0 ; i < best_selection.size (); ++i) {
158
158
if (best_selection.at (i)) {
159
- out_set. insert (utxo_pool.at (i));
160
- value_ret += utxo_pool.at (i).txout . nValue ;
159
+ util:: insert (out_set, utxo_pool.at (i). m_outputs );
160
+ value_ret += utxo_pool.at (i).m_value ;
161
161
}
162
162
}
163
163
164
164
return true ;
165
165
}
166
166
167
- static void ApproximateBestSubset (const std::vector<CInputCoin >& vValue , const CAmount& nTotalLower, const CAmount& nTargetValue,
167
+ static void ApproximateBestSubset (const std::vector<OutputGroup >& groups , const CAmount& nTotalLower, const CAmount& nTargetValue,
168
168
std::vector<char >& vfBest, CAmount& nBest, int iterations = 1000 )
169
169
{
170
170
std::vector<char > vfIncluded;
171
171
172
- vfBest.assign (vValue .size (), true );
172
+ vfBest.assign (groups .size (), true );
173
173
nBest = nTotalLower;
174
174
175
175
FastRandomContext insecure_rand;
176
176
177
177
for (int nRep = 0 ; nRep < iterations && nBest != nTargetValue; nRep++)
178
178
{
179
- vfIncluded.assign (vValue .size (), false );
179
+ vfIncluded.assign (groups .size (), false );
180
180
CAmount nTotal = 0 ;
181
181
bool fReachedTarget = false ;
182
182
for (int nPass = 0 ; nPass < 2 && !fReachedTarget ; nPass++)
183
183
{
184
- for (unsigned int i = 0 ; i < vValue .size (); i++)
184
+ for (unsigned int i = 0 ; i < groups .size (); i++)
185
185
{
186
186
// The solver here uses a randomized algorithm,
187
187
// the randomness serves no real security purpose but is just
@@ -191,7 +191,7 @@ static void ApproximateBestSubset(const std::vector<CInputCoin>& vValue, const C
191
191
// the selection random.
192
192
if (nPass == 0 ? insecure_rand.randbool () : !vfIncluded[i])
193
193
{
194
- nTotal += vValue [i].txout . nValue ;
194
+ nTotal += groups [i].m_value ;
195
195
vfIncluded[i] = true ;
196
196
if (nTotal >= nTargetValue)
197
197
{
@@ -201,7 +201,7 @@ static void ApproximateBestSubset(const std::vector<CInputCoin>& vValue, const C
201
201
nBest = nTotal;
202
202
vfBest = vfIncluded;
203
203
}
204
- nTotal -= vValue [i].txout . nValue ;
204
+ nTotal -= groups [i].m_value ;
205
205
vfIncluded[i] = false ;
206
206
}
207
207
}
@@ -210,86 +210,75 @@ static void ApproximateBestSubset(const std::vector<CInputCoin>& vValue, const C
210
210
}
211
211
}
212
212
213
- bool KnapsackSolver (const CAmount& nTargetValue, std::vector<CInputCoin >& vCoins , std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet)
213
+ bool KnapsackSolver (const CAmount& nTargetValue, std::vector<OutputGroup >& groups , std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet)
214
214
{
215
215
setCoinsRet.clear ();
216
216
nValueRet = 0 ;
217
217
218
218
// List of values less than target
219
- boost::optional<CInputCoin> coinLowestLarger ;
220
- std::vector<CInputCoin> vValue ;
219
+ boost::optional<OutputGroup> lowest_larger ;
220
+ std::vector<OutputGroup> applicable_groups ;
221
221
CAmount nTotalLower = 0 ;
222
222
223
- random_shuffle (vCoins .begin (), vCoins .end (), GetRandInt);
223
+ random_shuffle (groups .begin (), groups .end (), GetRandInt);
224
224
225
- for (const CInputCoin &coin : vCoins)
226
- {
227
- if (coin.txout .nValue == nTargetValue)
228
- {
229
- setCoinsRet.insert (coin);
230
- nValueRet += coin.txout .nValue ;
225
+ for (const OutputGroup& group : groups) {
226
+ if (group.m_value == nTargetValue) {
227
+ util::insert (setCoinsRet, group.m_outputs );
228
+ nValueRet += group.m_value ;
231
229
return true ;
232
- }
233
- else if (coin.txout .nValue < nTargetValue + MIN_CHANGE)
234
- {
235
- vValue.push_back (coin);
236
- nTotalLower += coin.txout .nValue ;
237
- }
238
- else if (!coinLowestLarger || coin.txout .nValue < coinLowestLarger->txout .nValue )
239
- {
240
- coinLowestLarger = coin;
230
+ } else if (group.m_value < nTargetValue + MIN_CHANGE) {
231
+ applicable_groups.push_back (group);
232
+ nTotalLower += group.m_value ;
233
+ } else if (!lowest_larger || group.m_value < lowest_larger->m_value ) {
234
+ lowest_larger = group;
241
235
}
242
236
}
243
237
244
- if (nTotalLower == nTargetValue)
245
- {
246
- for (const auto & input : vValue)
247
- {
248
- setCoinsRet.insert (input);
249
- nValueRet += input.txout .nValue ;
238
+ if (nTotalLower == nTargetValue) {
239
+ for (const auto & group : applicable_groups) {
240
+ util::insert (setCoinsRet, group.m_outputs );
241
+ nValueRet += group.m_value ;
250
242
}
251
243
return true ;
252
244
}
253
245
254
- if (nTotalLower < nTargetValue)
255
- {
256
- if (!coinLowestLarger)
257
- return false ;
258
- setCoinsRet.insert (coinLowestLarger.get ());
259
- nValueRet += coinLowestLarger->txout .nValue ;
246
+ if (nTotalLower < nTargetValue) {
247
+ if (!lowest_larger) return false ;
248
+ util::insert (setCoinsRet, lowest_larger->m_outputs );
249
+ nValueRet += lowest_larger->m_value ;
260
250
return true ;
261
251
}
262
252
263
253
// Solve subset sum by stochastic approximation
264
- std::sort (vValue .begin (), vValue .end (), descending);
254
+ std::sort (applicable_groups .begin (), applicable_groups .end (), descending);
265
255
std::vector<char > vfBest;
266
256
CAmount nBest;
267
257
268
- ApproximateBestSubset (vValue, nTotalLower, nTargetValue, vfBest, nBest);
269
- if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE)
270
- ApproximateBestSubset (vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
258
+ ApproximateBestSubset (applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
259
+ if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) {
260
+ ApproximateBestSubset (applicable_groups, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
261
+ }
271
262
272
263
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
273
264
// or the next bigger coin is closer), return the bigger coin
274
- if (coinLowestLarger &&
275
- ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger->txout .nValue <= nBest))
276
- {
277
- setCoinsRet.insert (coinLowestLarger.get ());
278
- nValueRet += coinLowestLarger->txout .nValue ;
279
- }
280
- else {
281
- for (unsigned int i = 0 ; i < vValue.size (); i++)
282
- if (vfBest[i])
283
- {
284
- setCoinsRet.insert (vValue[i]);
285
- nValueRet += vValue[i].txout .nValue ;
265
+ if (lowest_larger &&
266
+ ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || lowest_larger->m_value <= nBest)) {
267
+ util::insert (setCoinsRet, lowest_larger->m_outputs );
268
+ nValueRet += lowest_larger->m_value ;
269
+ } else {
270
+ for (unsigned int i = 0 ; i < applicable_groups.size (); i++) {
271
+ if (vfBest[i]) {
272
+ util::insert (setCoinsRet, applicable_groups[i].m_outputs );
273
+ nValueRet += applicable_groups[i].m_value ;
286
274
}
275
+ }
287
276
288
277
if (LogAcceptCategory (BCLog::SELECTCOINS)) {
289
278
LogPrint (BCLog::SELECTCOINS, " SelectCoins() best subset: " ); /* Continued */
290
- for (unsigned int i = 0 ; i < vValue .size (); i++) {
279
+ for (unsigned int i = 0 ; i < applicable_groups .size (); i++) {
291
280
if (vfBest[i]) {
292
- LogPrint (BCLog::SELECTCOINS, " %s " , FormatMoney (vValue [i].txout . nValue )); /* Continued */
281
+ LogPrint (BCLog::SELECTCOINS, " %s " , FormatMoney (applicable_groups [i].m_value )); /* Continued */
293
282
}
294
283
}
295
284
LogPrint (BCLog::SELECTCOINS, " total %s\n " , FormatMoney (nBest));
0 commit comments