14
14
#include < wallet/test/wallet_test_fixture.h>
15
15
#include < wallet/wallet.h>
16
16
17
+ #include < algorithm>
17
18
#include < boost/test/unit_test.hpp>
18
19
#include < random>
19
20
@@ -95,20 +96,22 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount
95
96
coins.push_back (output);
96
97
}
97
98
98
- static bool equivalent_sets (CoinSet a, CoinSet b)
99
+ /* * Check if SelectionResult a is equivalent to SelectionResult b.
100
+ * Equivalent means same input values, but maybe different inputs (i.e. same value, different prevout) */
101
+ static bool EquivalentResult (const SelectionResult& a, const SelectionResult& b)
99
102
{
100
103
std::vector<CAmount> a_amts;
101
104
std::vector<CAmount> b_amts;
102
- for (const auto & coin : a) {
105
+ for (const auto & coin : a. GetInputSet () ) {
103
106
a_amts.push_back (coin.txout .nValue );
104
107
}
105
- for (const auto & coin : b) {
108
+ for (const auto & coin : b. GetInputSet () ) {
106
109
b_amts.push_back (coin.txout .nValue );
107
110
}
108
111
std::sort (a_amts.begin (), a_amts.end ());
109
112
std::sort (b_amts.begin (), b_amts.end ());
110
113
111
- std::pair<std::vector<CAmount>::iterator, std::vector<CAmount>::iterator> ret = mismatch (a_amts.begin (), a_amts.end (), b_amts.begin ());
114
+ std::pair<std::vector<CAmount>::iterator, std::vector<CAmount>::iterator> ret = std:: mismatch (a_amts.begin (), a_amts.end (), b_amts.begin ());
112
115
return ret.first == a_amts.end () && ret.second == b_amts.end ();
113
116
}
114
117
@@ -168,17 +171,14 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
168
171
{
169
172
// Setup
170
173
std::vector<CInputCoin> utxo_pool;
171
- CoinSet selection;
172
174
SelectionResult expected_result (CAmount (0 ));
173
- CAmount value_ret = 0 ;
174
175
175
176
// ///////////////////////
176
177
// Known Outcome tests //
177
178
// ///////////////////////
178
179
179
180
// Empty utxo pool
180
- BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 1 * CENT, 0.5 * CENT, selection, value_ret));
181
- selection.clear ();
181
+ BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 1 * CENT, 0.5 * CENT));
182
182
183
183
// Add utxos
184
184
add_coin (1 * CENT, 1 , utxo_pool);
@@ -188,78 +188,77 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
188
188
189
189
// Select 1 Cent
190
190
add_coin (1 * CENT, 1 , expected_result);
191
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), 1 * CENT, 0.5 * CENT, selection, value_ret));
192
- BOOST_CHECK (equivalent_sets (selection, expected_result.GetInputSet ()));
193
- BOOST_CHECK_EQUAL (value_ret, 1 * CENT);
191
+ const auto result1 = SelectCoinsBnB (GroupCoins (utxo_pool), 1 * CENT, 0.5 * CENT);
192
+ BOOST_CHECK (result1);
193
+ BOOST_CHECK (EquivalentResult (expected_result, *result1));
194
+ BOOST_CHECK_EQUAL (result1->GetSelectedValue (), 1 * CENT);
194
195
expected_result.Clear ();
195
- selection.clear ();
196
196
197
197
// Select 2 Cent
198
198
add_coin (2 * CENT, 2 , expected_result);
199
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), 2 * CENT, 0.5 * CENT, selection, value_ret));
200
- BOOST_CHECK (equivalent_sets (selection, expected_result.GetInputSet ()));
201
- BOOST_CHECK_EQUAL (value_ret, 2 * CENT);
199
+ const auto result2 = SelectCoinsBnB (GroupCoins (utxo_pool), 2 * CENT, 0.5 * CENT);
200
+ BOOST_CHECK (result2);
201
+ BOOST_CHECK (EquivalentResult (expected_result, *result2));
202
+ BOOST_CHECK_EQUAL (result2->GetSelectedValue (), 2 * CENT);
202
203
expected_result.Clear ();
203
- selection.clear ();
204
204
205
205
// Select 5 Cent
206
206
add_coin (4 * CENT, 4 , expected_result);
207
207
add_coin (1 * CENT, 1 , expected_result);
208
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), 5 * CENT, 0.5 * CENT, selection, value_ret));
209
- BOOST_CHECK (equivalent_sets (selection, expected_result.GetInputSet ()));
210
- BOOST_CHECK_EQUAL (value_ret, 5 * CENT);
208
+ const auto result3 = SelectCoinsBnB (GroupCoins (utxo_pool), 5 * CENT, 0.5 * CENT);
209
+ BOOST_CHECK (result3);
210
+ BOOST_CHECK (EquivalentResult (expected_result, *result3));
211
+ BOOST_CHECK_EQUAL (result3->GetSelectedValue (), 5 * CENT);
211
212
expected_result.Clear ();
212
- selection.clear ();
213
213
214
214
// Select 11 Cent, not possible
215
- BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 11 * CENT, 0.5 * CENT, selection, value_ret ));
215
+ BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 11 * CENT, 0.5 * CENT));
216
216
expected_result.Clear ();
217
- selection.clear ();
218
217
219
218
// Cost of change is greater than the difference between target value and utxo sum
220
219
add_coin (1 * CENT, 1 , expected_result);
221
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), 0.9 * CENT, 0.5 * CENT, selection, value_ret));
222
- BOOST_CHECK_EQUAL (value_ret, 1 * CENT);
223
- BOOST_CHECK (equivalent_sets (selection, expected_result.GetInputSet ()));
220
+ const auto result4 = SelectCoinsBnB (GroupCoins (utxo_pool), 0.9 * CENT, 0.5 * CENT);
221
+ BOOST_CHECK (result4);
222
+ BOOST_CHECK_EQUAL (result4->GetSelectedValue (), 1 * CENT);
223
+ BOOST_CHECK (EquivalentResult (expected_result, *result4));
224
224
expected_result.Clear ();
225
- selection.clear ();
226
225
227
226
// Cost of change is less than the difference between target value and utxo sum
228
- BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 0.9 * CENT, 0 , selection, value_ret ));
227
+ BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 0.9 * CENT, 0 ));
229
228
expected_result.Clear ();
230
- selection.clear ();
231
229
232
230
// Select 10 Cent
233
231
add_coin (5 * CENT, 5 , utxo_pool);
234
232
add_coin (5 * CENT, 5 , expected_result);
235
233
add_coin (4 * CENT, 4 , expected_result);
236
234
add_coin (1 * CENT, 1 , expected_result);
237
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), 10 * CENT, 0.5 * CENT, selection, value_ret));
238
- BOOST_CHECK (equivalent_sets (selection, expected_result.GetInputSet ()));
239
- BOOST_CHECK_EQUAL (value_ret, 10 * CENT);
235
+ const auto result5 = SelectCoinsBnB (GroupCoins (utxo_pool), 10 * CENT, 0.5 * CENT);
236
+ BOOST_CHECK (result5);
237
+ BOOST_CHECK (EquivalentResult (expected_result, *result5));
238
+ BOOST_CHECK_EQUAL (result5->GetSelectedValue (), 10 * CENT);
240
239
expected_result.Clear ();
241
- selection.clear ();
242
240
243
241
// Negative effective value
244
242
// Select 10 Cent but have 1 Cent not be possible because too small
245
243
add_coin (5 * CENT, 5 , expected_result);
246
244
add_coin (3 * CENT, 3 , expected_result);
247
245
add_coin (2 * CENT, 2 , expected_result);
248
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), 10 * CENT, 5000 , selection, value_ret));
249
- BOOST_CHECK_EQUAL (value_ret, 10 * CENT);
246
+ const auto result6 = SelectCoinsBnB (GroupCoins (utxo_pool), 10 * CENT, 5000 );
247
+ BOOST_CHECK (result6);
248
+ BOOST_CHECK_EQUAL (result6->GetSelectedValue (), 10 * CENT);
250
249
// FIXME: this test is redundant with the above, because 1 Cent is selected, not "too small"
251
- // BOOST_CHECK(equivalent_sets(selection, expected_result.GetInputSet() ));
250
+ // BOOST_CHECK(EquivalentResult(expected_result, *result ));
252
251
253
252
// Select 0.25 Cent, not possible
254
- BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 0.25 * CENT, 0.5 * CENT, selection, value_ret ));
253
+ BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 0.25 * CENT, 0.5 * CENT));
255
254
expected_result.Clear ();
256
- selection.clear ();
257
255
258
256
// Iteration exhaustion test
259
257
CAmount target = make_hard_case (17 , utxo_pool);
260
- BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), target, 0 , selection, value_ret )); // Should exhaust
258
+ BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), target, 0 )); // Should exhaust
261
259
target = make_hard_case (14 , utxo_pool);
262
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), target, 0 , selection, value_ret)); // Should not exhaust
260
+ const auto result7 = SelectCoinsBnB (GroupCoins (utxo_pool), target, 0 ); // Should not exhaust
261
+ BOOST_CHECK (result7);
263
262
264
263
// Test same value early bailout optimization
265
264
utxo_pool.clear ();
@@ -276,9 +275,10 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
276
275
for (int i = 0 ; i < 50000 ; ++i) {
277
276
add_coin (5 * CENT, 7 , utxo_pool);
278
277
}
279
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (utxo_pool), 30 * CENT, 5000 , selection, value_ret));
280
- BOOST_CHECK_EQUAL (value_ret, 30 * CENT);
281
- BOOST_CHECK (equivalent_sets (selection, expected_result.GetInputSet ()));
278
+ const auto result8 = SelectCoinsBnB (GroupCoins (utxo_pool), 30 * CENT, 5000 );
279
+ BOOST_CHECK (result8);
280
+ BOOST_CHECK_EQUAL (result8->GetSelectedValue (), 30 * CENT);
281
+ BOOST_CHECK (EquivalentResult (expected_result, *result8));
282
282
283
283
// //////////////////
284
284
// Behavior tests //
@@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
290
290
}
291
291
// Run 100 times, to make sure it is never finding a solution
292
292
for (int i = 0 ; i < 100 ; ++i) {
293
- BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 1 * CENT, 2 * CENT, selection, value_ret ));
293
+ BOOST_CHECK (!SelectCoinsBnB (GroupCoins (utxo_pool), 1 * CENT, 2 * CENT));
294
294
}
295
295
296
296
// Make sure that effective value is working in AttemptSelection when BnB is used
@@ -306,20 +306,19 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
306
306
wallet->SetupDescriptorScriptPubKeyMans ();
307
307
308
308
std::vector<COutput> coins;
309
- CoinSet setCoinsRet;
310
- CAmount nValueRet;
311
309
312
310
add_coin (coins, *wallet, 1 );
313
311
coins.at (0 ).nInputBytes = 40 ; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail
314
- BOOST_CHECK (!SelectCoinsBnB (GroupCoins (coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change , setCoinsRet, nValueRet ));
312
+ BOOST_CHECK (!SelectCoinsBnB (GroupCoins (coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change ));
315
313
316
314
// Test fees subtracted from output:
317
315
coins.clear ();
318
316
add_coin (coins, *wallet, 1 * CENT);
319
317
coins.at (0 ).nInputBytes = 40 ;
320
318
coin_selection_params_bnb.m_subtract_fee_outputs = true ;
321
- BOOST_CHECK (SelectCoinsBnB (GroupCoins (coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change , setCoinsRet, nValueRet));
322
- BOOST_CHECK_EQUAL (nValueRet, 1 * CENT);
319
+ const auto result9 = SelectCoinsBnB (GroupCoins (coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change );
320
+ BOOST_CHECK (result9);
321
+ BOOST_CHECK_EQUAL (result9->GetSelectedValue (), 1 * CENT);
323
322
}
324
323
325
324
{
0 commit comments