@@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
117
117
118
118
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
119
119
BOOST_CHECK ( wallet.SelectCoinsMinConf (34 * CENT, 1 , 1 , vCoins, setCoinsRet, nValueRet));
120
- BOOST_CHECK_GT (nValueRet, 34 * CENT); // but should get more than 34 cents
120
+ BOOST_CHECK_EQUAL (nValueRet, 35 * CENT); // but 35 cents is closest
121
121
BOOST_CHECK_EQUAL (setCoinsRet.size (), 3U ); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
122
122
123
123
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
@@ -185,33 +185,34 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
185
185
BOOST_CHECK_EQUAL (nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
186
186
BOOST_CHECK_EQUAL (setCoinsRet.size (), 1U );
187
187
188
- // empty the wallet and start again, now with fractions of a cent, to test sub-cent change avoidance
188
+ // empty the wallet and start again, now with fractions of a cent, to test small change avoidance
189
+
189
190
empty_wallet ();
190
- add_coin (0.1 *CENT );
191
- add_coin (0.2 *CENT );
192
- add_coin (0.3 *CENT );
193
- add_coin (0.4 *CENT );
194
- add_coin (0.5 *CENT );
195
-
196
- // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents
197
- // we'll get sub-cent change whatever happens, so can expect 1.0 exactly
198
- BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * CENT , 1 , 1 , vCoins, setCoinsRet, nValueRet));
199
- BOOST_CHECK_EQUAL (nValueRet, 1 * CENT );
191
+ add_coin (0.1 *MIN_CHANGE );
192
+ add_coin (0.2 *MIN_CHANGE );
193
+ add_coin (0.3 *MIN_CHANGE );
194
+ add_coin (0.4 *MIN_CHANGE );
195
+ add_coin (0.5 *MIN_CHANGE );
196
+
197
+ // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
198
+ // we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
199
+ BOOST_CHECK ( wallet.SelectCoinsMinConf (MIN_CHANGE , 1 , 1 , vCoins, setCoinsRet, nValueRet));
200
+ BOOST_CHECK_EQUAL (nValueRet, MIN_CHANGE );
200
201
201
- // but if we add a bigger coin, making it possible to avoid sub-cent change, things change:
202
- add_coin (1111 *CENT );
202
+ // but if we add a bigger coin, small change is avoided
203
+ add_coin (1111 *MIN_CHANGE );
203
204
204
- // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents
205
- BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * CENT , 1 , 1 , vCoins, setCoinsRet, nValueRet));
206
- BOOST_CHECK_EQUAL (nValueRet, 1 * CENT ); // we should get the exact amount
205
+ // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
206
+ BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * MIN_CHANGE , 1 , 1 , vCoins, setCoinsRet, nValueRet));
207
+ BOOST_CHECK_EQUAL (nValueRet, 1 * MIN_CHANGE ); // we should get the exact amount
207
208
208
- // if we add more sub-cent coins:
209
- add_coin (0.6 *CENT );
210
- add_coin (0.7 *CENT );
209
+ // if we add more small coins:
210
+ add_coin (0.6 *MIN_CHANGE );
211
+ add_coin (0.7 *MIN_CHANGE );
211
212
212
- // and try again to make 1.0 cents, we can still make 1.0 cents
213
- BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * CENT , 1 , 1 , vCoins, setCoinsRet, nValueRet));
214
- BOOST_CHECK_EQUAL (nValueRet, 1 * CENT ); // we should get the exact amount
213
+ // and try again to make 1.0 * MIN_CHANGE
214
+ BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * MIN_CHANGE , 1 , 1 , vCoins, setCoinsRet, nValueRet));
215
+ BOOST_CHECK_EQUAL (nValueRet, 1 * MIN_CHANGE ); // we should get the exact amount
215
216
216
217
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
217
218
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
@@ -223,45 +224,65 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
223
224
BOOST_CHECK_EQUAL (nValueRet, 500000 * COIN); // we should get the exact amount
224
225
BOOST_CHECK_EQUAL (setCoinsRet.size (), 10U ); // in ten coins
225
226
226
- // if there's not enough in the smaller coins to make at least 1 cent change (0.5+0.6+0.7 < 1.0+1.0),
227
+ // if there's not enough in the smaller coins to make at least 1 * MIN_CHANGE change (0.5+0.6+0.7 < 1.0+1.0),
227
228
// we need to try finding an exact subset anyway
228
229
229
230
// sometimes it will fail, and so we use the next biggest coin:
230
231
empty_wallet ();
231
- add_coin (0.5 * CENT );
232
- add_coin (0.6 * CENT );
233
- add_coin (0.7 * CENT );
234
- add_coin (1111 * CENT );
235
- BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * CENT , 1 , 1 , vCoins, setCoinsRet, nValueRet));
236
- BOOST_CHECK_EQUAL (nValueRet, 1111 * CENT ); // we get the bigger coin
232
+ add_coin (0.5 * MIN_CHANGE );
233
+ add_coin (0.6 * MIN_CHANGE );
234
+ add_coin (0.7 * MIN_CHANGE );
235
+ add_coin (1111 * MIN_CHANGE );
236
+ BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * MIN_CHANGE , 1 , 1 , vCoins, setCoinsRet, nValueRet));
237
+ BOOST_CHECK_EQUAL (nValueRet, 1111 * MIN_CHANGE ); // we get the bigger coin
237
238
BOOST_CHECK_EQUAL (setCoinsRet.size (), 1U );
238
239
239
240
// but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0)
240
241
empty_wallet ();
241
- add_coin (0.4 * CENT );
242
- add_coin (0.6 * CENT );
243
- add_coin (0.8 * CENT );
244
- add_coin (1111 * CENT );
245
- BOOST_CHECK ( wallet.SelectCoinsMinConf (1 * CENT , 1 , 1 , vCoins, setCoinsRet, nValueRet));
246
- BOOST_CHECK_EQUAL (nValueRet, 1 * CENT ); // we should get the exact amount
242
+ add_coin (0.4 * MIN_CHANGE );
243
+ add_coin (0.6 * MIN_CHANGE );
244
+ add_coin (0.8 * MIN_CHANGE );
245
+ add_coin (1111 * MIN_CHANGE );
246
+ BOOST_CHECK ( wallet.SelectCoinsMinConf (MIN_CHANGE , 1 , 1 , vCoins, setCoinsRet, nValueRet));
247
+ BOOST_CHECK_EQUAL (nValueRet, MIN_CHANGE ); // we should get the exact amount
247
248
BOOST_CHECK_EQUAL (setCoinsRet.size (), 2U ); // in two coins 0.4+0.6
248
249
249
- // test avoiding sub-cent change
250
+ // test avoiding small change
250
251
empty_wallet ();
251
- add_coin (0.0005 * COIN );
252
- add_coin (0.01 * COIN );
253
- add_coin (1 * COIN );
252
+ add_coin (0.05 * MIN_CHANGE );
253
+ add_coin (1 * MIN_CHANGE );
254
+ add_coin (100 * MIN_CHANGE );
254
255
255
- // trying to make 1.0001 from these three coins
256
- BOOST_CHECK ( wallet.SelectCoinsMinConf (1.0001 * COIN , 1 , 1 , vCoins, setCoinsRet, nValueRet));
257
- BOOST_CHECK_EQUAL (nValueRet, 1.0105 * COIN ); // we should get all coins
256
+ // trying to make 100.01 from these three coins
257
+ BOOST_CHECK ( wallet.SelectCoinsMinConf (100.01 * MIN_CHANGE , 1 , 1 , vCoins, setCoinsRet, nValueRet));
258
+ BOOST_CHECK_EQUAL (nValueRet, 101.05 * MIN_CHANGE ); // we should get all coins
258
259
BOOST_CHECK_EQUAL (setCoinsRet.size (), 3U );
259
260
260
- // but if we try to make 0.999 , we should take the bigger of the two small coins to avoid sub-cent change
261
- BOOST_CHECK ( wallet.SelectCoinsMinConf (0.999 * COIN , 1 , 1 , vCoins, setCoinsRet, nValueRet));
262
- BOOST_CHECK_EQUAL (nValueRet, 1.01 * COIN); // we should get 1 + 0.01
261
+ // but if we try to make 99.9 , we should take the bigger of the two small coins to avoid small change
262
+ BOOST_CHECK ( wallet.SelectCoinsMinConf (99.9 * MIN_CHANGE , 1 , 1 , vCoins, setCoinsRet, nValueRet));
263
+ BOOST_CHECK_EQUAL (nValueRet, 101 * MIN_CHANGE);
263
264
BOOST_CHECK_EQUAL (setCoinsRet.size (), 2U );
264
265
266
+ // test with many inputs
267
+ for (CAmount amt=1500 ; amt < COIN; amt*=10 ) {
268
+ empty_wallet ();
269
+ // Create 676 inputs (= MAX_STANDARD_TX_SIZE / 148 bytes per input)
270
+ for (uint16_t j = 0 ; j < 676 ; j++)
271
+ add_coin (amt);
272
+ BOOST_CHECK (wallet.SelectCoinsMinConf (2000 , 1 , 1 , vCoins, setCoinsRet, nValueRet));
273
+ if (amt - 2000 < MIN_CHANGE) {
274
+ // needs more than one input:
275
+ uint16_t returnSize = std::ceil ((2000.0 + MIN_CHANGE)/amt);
276
+ CAmount returnValue = amt * returnSize;
277
+ BOOST_CHECK_EQUAL (nValueRet, returnValue);
278
+ BOOST_CHECK_EQUAL (setCoinsRet.size (), returnSize);
279
+ } else {
280
+ // one input is sufficient:
281
+ BOOST_CHECK_EQUAL (nValueRet, amt);
282
+ BOOST_CHECK_EQUAL (setCoinsRet.size (), 1U );
283
+ }
284
+ }
285
+
265
286
// test randomness
266
287
{
267
288
empty_wallet ();
0 commit comments