Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/test/wallet_tests.cpp
Show First 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static bool equal_sets(CoinSet a, CoinSet b) { | static bool equal_sets(CoinSet a, CoinSet b) { | ||||
std::pair<CoinSet::iterator, CoinSet::iterator> ret = | std::pair<CoinSet::iterator, CoinSet::iterator> ret = | ||||
mismatch(a.begin(), a.end(), b.begin()); | mismatch(a.begin(), a.end(), b.begin()); | ||||
return ret.first == a.end() && ret.second == b.end(); | return ret.first == a.end() && ret.second == b.end(); | ||||
} | } | ||||
CoinEligibilityFilter filter_standard(1, 6, 0); | |||||
CoinEligibilityFilter filter_confirmed(1, 1, 0); | |||||
CoinEligibilityFilter filter_standard_extra(6, 6, 0); | |||||
BOOST_AUTO_TEST_CASE(coin_selection_tests) { | BOOST_AUTO_TEST_CASE(coin_selection_tests) { | ||||
CoinSet setCoinsRet, setCoinsRet2; | CoinSet setCoinsRet, setCoinsRet2; | ||||
Amount nValueRet; | Amount nValueRet; | ||||
const CWallet wallet(Params(), "dummy", CWalletDBWrapper::CreateDummy()); | const CWallet wallet(Params(), "dummy", CWalletDBWrapper::CreateDummy()); | ||||
LOCK(walletCriticalSection); | LOCK(walletCriticalSection); | ||||
// test multiple times to allow for differences in the shuffle order | // test multiple times to allow for differences in the shuffle order | ||||
for (int i = 0; i < RUN_TESTS; i++) { | for (int i = 0; i < RUN_TESTS; i++) { | ||||
empty_wallet(); | empty_wallet(); | ||||
// with an empty wallet we can't even pay one cent | // with an empty wallet we can't even pay one cent | ||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(1 * CENT, 1, 6, 0, vCoins, | BOOST_CHECK(!wallet.SelectCoinsMinConf(1 * CENT, filter_standard, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// add a new 1 cent coin | // add a new 1 cent coin | ||||
add_coin(wallet, 1 * CENT, 4); | add_coin(wallet, 1 * CENT, 4); | ||||
// with a new 1 cent coin, we still can't find a mature 1 cent | // with a new 1 cent coin, we still can't find a mature 1 cent | ||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(1 * CENT, 1, 6, 0, vCoins, | BOOST_CHECK(!wallet.SelectCoinsMinConf(1 * CENT, filter_standard, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// but we can find a new 1 cent | // but we can find a new 1 cent | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(1 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(1 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); | ||||
// add a mature 2 cent coin | // add a mature 2 cent coin | ||||
add_coin(wallet, 2 * CENT); | add_coin(wallet, 2 * CENT); | ||||
// we can't make 3 cents of mature coins | // we can't make 3 cents of mature coins | ||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(3 * CENT, 1, 6, 0, vCoins, | BOOST_CHECK(!wallet.SelectCoinsMinConf(3 * CENT, filter_standard, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we can make 3 cents of new coins | // we can make 3 cents of new coins | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(3 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(3 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 3 * CENT); | ||||
// add a mature 5 cent coin, | // add a mature 5 cent coin, | ||||
add_coin(wallet, 5 * CENT); | add_coin(wallet, 5 * CENT); | ||||
// a new 10 cent coin sent from one of our own addresses | // a new 10 cent coin sent from one of our own addresses | ||||
add_coin(wallet, 10 * CENT, 3, true); | add_coin(wallet, 10 * CENT, 3, true); | ||||
// and a mature 20 cent coin | // and a mature 20 cent coin | ||||
add_coin(wallet, 20 * CENT); | add_coin(wallet, 20 * CENT); | ||||
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: | // now we have new: 1+10=11 (of which 10 was self-sent), and mature: | ||||
// 2+5+20=27. total = 38 | // 2+5+20=27. total = 38 | ||||
// we can't make 38 cents only if we disallow new coins: | // we can't make 38 cents only if we disallow new coins: | ||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, 0, vCoins, | BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, filter_standard, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we can't even make 37 cents if we don't allow new coins even if | // we can't even make 37 cents if we don't allow new coins even if | ||||
// they're from us | // they're from us | ||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, 0, vCoins, | BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, filter_standard_extra, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// but we can make 37 cents if we accept new coins from ourself | // but we can make 37 cents if we accept new coins from ourself | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(37 * CENT, 1, 6, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(37 * CENT, filter_standard, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 37 * CENT); | ||||
// and we can make 38 cents if we accept all new coins | // and we can make 38 cents if we accept all new coins | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(38 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(38 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 38 * CENT); | ||||
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly | // try making 34 cents from 1,2,5,10,20 - we can't do it exactly | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(34 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(34 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// but 35 cents is closest | // but 35 cents is closest | ||||
BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); | ||||
// the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got | // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got | ||||
// included (but possible) | // included (but possible) | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | ||||
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We | // when we try making 7 cents, the smaller coins (1,2,5) are enough. We | ||||
// should see just 2+5 | // should see just 2+5 | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(7 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(7 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 7 * CENT); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | ||||
// when we try making 8 cents, the smaller coins (1,2,5) are exactly | // when we try making 8 cents, the smaller coins (1,2,5) are exactly | ||||
// enough. | // enough. | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(8 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(8 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK(nValueRet == 8 * CENT); | BOOST_CHECK(nValueRet == 8 * CENT); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | ||||
// when we try making 9 cents, no subset of smaller coins is enough, and | // when we try making 9 cents, no subset of smaller coins is enough, and | ||||
// we get the next bigger coin (10) | // we get the next bigger coin (10) | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(9 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(9 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 10 * CENT); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | ||||
// now clear out the wallet and start again to test choosing between | // now clear out the wallet and start again to test choosing between | ||||
// subsets of smaller coins and the next biggest coin | // subsets of smaller coins and the next biggest coin | ||||
empty_wallet(); | empty_wallet(); | ||||
add_coin(wallet, 6 * CENT); | add_coin(wallet, 6 * CENT); | ||||
add_coin(wallet, 7 * CENT); | add_coin(wallet, 7 * CENT); | ||||
add_coin(wallet, 8 * CENT); | add_coin(wallet, 8 * CENT); | ||||
add_coin(wallet, 20 * CENT); | add_coin(wallet, 20 * CENT); | ||||
// now we have 6+7+8+20+30 = 71 cents total | // now we have 6+7+8+20+30 = 71 cents total | ||||
add_coin(wallet, 30 * CENT); | add_coin(wallet, 30 * CENT); | ||||
// check that we have 71 and not 72 | // check that we have 71 and not 72 | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(71 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(71 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// now try making 16 cents. the best smaller coins can do is 6+7+8 = | // now try making 16 cents. the best smaller coins can do is 6+7+8 = | ||||
// 21; not as good at the next biggest coin, 20 | // 21; not as good at the next biggest coin, 20 | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(16 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get 20 in one coin | // we should get 20 in one coin | ||||
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | ||||
// now we have 5+6+7+8+20+30 = 75 cents total | // now we have 5+6+7+8+20+30 = 75 cents total | ||||
add_coin(wallet, 5 * CENT); | add_coin(wallet, 5 * CENT); | ||||
// now if we try making 16 cents again, the smaller coins can make 5+6+7 | // now if we try making 16 cents again, the smaller coins can make 5+6+7 | ||||
// = 18 cents, better than the next biggest coin, 20 | // = 18 cents, better than the next biggest coin, 20 | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(16 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get 18 in 3 coins | // we should get 18 in 3 coins | ||||
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | ||||
// now we have 5+6+7+8+18+20+30 | // now we have 5+6+7+8+18+20+30 | ||||
add_coin(wallet, 18 * CENT); | add_coin(wallet, 18 * CENT); | ||||
// and now if we try making 16 cents again, the smaller coins can make | // and now if we try making 16 cents again, the smaller coins can make | ||||
// 5+6+7 = 18 cents, the same as the next biggest coin, 18 | // 5+6+7 = 18 cents, the same as the next biggest coin, 18 | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(16 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get 18 in 1 coin | // we should get 18 in 1 coin | ||||
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); | ||||
// because in the event of a tie, the biggest coin wins | // because in the event of a tie, the biggest coin wins | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | ||||
// now try making 11 cents. we should get 5+6 | // now try making 11 cents. we should get 5+6 | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(11 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(11 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT); | BOOST_CHECK_EQUAL(nValueRet, 11 * CENT); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | ||||
// check that the smallest bigger coin is used | // check that the smallest bigger coin is used | ||||
add_coin(wallet, 1 * COIN); | add_coin(wallet, 1 * COIN); | ||||
add_coin(wallet, 2 * COIN); | add_coin(wallet, 2 * COIN); | ||||
add_coin(wallet, 3 * COIN); | add_coin(wallet, 3 * COIN); | ||||
// now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents | // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents | ||||
add_coin(wallet, 4 * COIN); | add_coin(wallet, 4 * COIN); | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(95 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(95 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get 1 BCH in 1 coin | // we should get 1 BCH in 1 coin | ||||
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); | BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(195 * CENT, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(195 * CENT, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get 2 BCH in 1 coin | // we should get 2 BCH in 1 coin | ||||
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); | BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | ||||
// empty the wallet and start again, now with fractions of a cent, to | // empty the wallet and start again, now with fractions of a cent, to | ||||
// test small change avoidance | // test small change avoidance | ||||
empty_wallet(); | empty_wallet(); | ||||
add_coin(wallet, 1 * MIN_CHANGE / 10); | add_coin(wallet, 1 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 2 * MIN_CHANGE / 10); | add_coin(wallet, 2 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 3 * MIN_CHANGE / 10); | add_coin(wallet, 3 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 4 * MIN_CHANGE / 10); | add_coin(wallet, 4 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 5 * MIN_CHANGE / 10); | add_coin(wallet, 5 * MIN_CHANGE / 10); | ||||
// try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE we'll get change | // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE we'll get change | ||||
// smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE | // smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE | ||||
// exactly | // exactly | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); | BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); | ||||
// but if we add a bigger coin, small change is avoided | // but if we add a bigger coin, small change is avoided | ||||
add_coin(wallet, 1111 * MIN_CHANGE); | add_coin(wallet, 1111 * MIN_CHANGE); | ||||
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 | // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get the exact amount | // we should get the exact amount | ||||
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); | BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); | ||||
// if we add more small coins: | // if we add more small coins: | ||||
add_coin(wallet, 6 * MIN_CHANGE / 10); | add_coin(wallet, 6 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 7 * MIN_CHANGE / 10); | add_coin(wallet, 7 * MIN_CHANGE / 10); | ||||
// and try again to make 1.0 * MIN_CHANGE | // and try again to make 1.0 * MIN_CHANGE | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get the exact amount | // we should get the exact amount | ||||
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); | BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); | ||||
// run the 'mtgox' test (see | // run the 'mtgox' test (see | ||||
// http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) | // http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) | ||||
// they tried to consolidate 10 50k coins into one 500k coin, and ended | // they tried to consolidate 10 50k coins into one 500k coin, and ended | ||||
// up with 50k in change | // up with 50k in change | ||||
empty_wallet(); | empty_wallet(); | ||||
for (int j = 0; j < 20; j++) { | for (int j = 0; j < 20; j++) { | ||||
add_coin(wallet, 50000 * COIN); | add_coin(wallet, 50000 * COIN); | ||||
} | } | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(500000 * COIN, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get the exact amount | // we should get the exact amount | ||||
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); | BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); | ||||
// in ten coins | // in ten coins | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); | ||||
// if there's not enough in the smaller coins to make at least 1 * | // 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), we need to try finding an | // MIN_CHANGE change (0.5+0.6+0.7 < 1.0+1.0), we need to try finding an | ||||
// exact subset anyway | // exact subset anyway | ||||
// sometimes it will fail, and so we use the next biggest coin: | // sometimes it will fail, and so we use the next biggest coin: | ||||
empty_wallet(); | empty_wallet(); | ||||
add_coin(wallet, 5 * MIN_CHANGE / 10); | add_coin(wallet, 5 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 6 * MIN_CHANGE / 10); | add_coin(wallet, 6 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 7 * MIN_CHANGE / 10); | add_coin(wallet, 7 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 1111 * MIN_CHANGE); | add_coin(wallet, 1111 * MIN_CHANGE); | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we get the bigger coin | // we get the bigger coin | ||||
BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); | BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | ||||
// but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = | // but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = | ||||
// 1.0) | // 1.0) | ||||
empty_wallet(); | empty_wallet(); | ||||
add_coin(wallet, 4 * MIN_CHANGE / 10); | add_coin(wallet, 4 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 6 * MIN_CHANGE / 10); | add_coin(wallet, 6 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 8 * MIN_CHANGE / 10); | add_coin(wallet, 8 * MIN_CHANGE / 10); | ||||
add_coin(wallet, 1111 * MIN_CHANGE); | add_coin(wallet, 1111 * MIN_CHANGE); | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE, filter_confirmed, | ||||
setCoinsRet, nValueRet)); | vCoins, setCoinsRet, nValueRet)); | ||||
// we should get the exact amount | // we should get the exact amount | ||||
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); | BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); | ||||
// in two coins 0.4+0.6 | // in two coins 0.4+0.6 | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | ||||
// test avoiding small change | // test avoiding small change | ||||
empty_wallet(); | empty_wallet(); | ||||
add_coin(wallet, 5 * MIN_CHANGE / 100); | add_coin(wallet, 5 * MIN_CHANGE / 100); | ||||
add_coin(wallet, 1 * MIN_CHANGE); | add_coin(wallet, 1 * MIN_CHANGE); | ||||
add_coin(wallet, 100 * MIN_CHANGE); | add_coin(wallet, 100 * MIN_CHANGE); | ||||
// trying to make 100.01 from these three coins | // trying to make 100.01 from these three coins | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(10001 * MIN_CHANGE / 100, 1, 1, 0, | BOOST_CHECK(wallet.SelectCoinsMinConf(10001 * MIN_CHANGE / 100, | ||||
vCoins, setCoinsRet, nValueRet)); | filter_confirmed, vCoins, | ||||
setCoinsRet, nValueRet)); | |||||
// we should get all coins | // we should get all coins | ||||
BOOST_CHECK_EQUAL(nValueRet, 10105 * MIN_CHANGE / 100); | BOOST_CHECK_EQUAL(nValueRet, 10105 * MIN_CHANGE / 100); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); | ||||
// but if we try to make 99.9, we should take the bigger of the two | // but if we try to make 99.9, we should take the bigger of the two | ||||
// small coins to avoid small change | // small coins to avoid small change | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(9990 * MIN_CHANGE / 100, 1, 1, 0, | BOOST_CHECK(wallet.SelectCoinsMinConf(9990 * MIN_CHANGE / 100, | ||||
vCoins, setCoinsRet, nValueRet)); | filter_confirmed, vCoins, | ||||
setCoinsRet, nValueRet)); | |||||
BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE); | BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | ||||
// test with many inputs | // test with many inputs | ||||
for (Amount amt = 1500 * SATOSHI; amt < COIN; amt = 10 * amt) { | for (Amount amt = 1500 * SATOSHI; amt < COIN; amt = 10 * amt) { | ||||
empty_wallet(); | empty_wallet(); | ||||
// Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 | // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 | ||||
// bytes per input) | // bytes per input) | ||||
for (uint16_t j = 0; j < 676; j++) { | for (uint16_t j = 0; j < 676; j++) { | ||||
add_coin(wallet, amt); | add_coin(wallet, amt); | ||||
} | } | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf( | BOOST_CHECK(wallet.SelectCoinsMinConf(2000 * SATOSHI, | ||||
2000 * SATOSHI, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); | filter_confirmed, vCoins, | ||||
setCoinsRet, nValueRet)); | |||||
if (amt - 2000 * SATOSHI < MIN_CHANGE) { | if (amt - 2000 * SATOSHI < MIN_CHANGE) { | ||||
// needs more than one input: | // needs more than one input: | ||||
uint16_t returnSize = std::ceil( | uint16_t returnSize = std::ceil( | ||||
double(2000 + (MIN_CHANGE / SATOSHI)) / (amt / SATOSHI)); | double(2000 + (MIN_CHANGE / SATOSHI)) / (amt / SATOSHI)); | ||||
Amount returnValue = returnSize * amt; | Amount returnValue = returnSize * amt; | ||||
BOOST_CHECK_EQUAL(nValueRet, returnValue); | BOOST_CHECK_EQUAL(nValueRet, returnValue); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), returnSize); | BOOST_CHECK_EQUAL(setCoinsRet.size(), returnSize); | ||||
} else { | } else { | ||||
// one input is sufficient: | // one input is sufficient: | ||||
BOOST_CHECK_EQUAL(nValueRet, amt); | BOOST_CHECK_EQUAL(nValueRet, amt); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); | ||||
} | } | ||||
} | } | ||||
// test randomness | // test randomness | ||||
{ | { | ||||
empty_wallet(); | empty_wallet(); | ||||
for (int i2 = 0; i2 < 100; i2++) { | for (int i2 = 0; i2 < 100; i2++) { | ||||
add_coin(wallet, COIN); | add_coin(wallet, COIN); | ||||
} | } | ||||
// picking 50 from 100 coins doesn't depend on the shuffle, but does | // picking 50 from 100 coins doesn't depend on the shuffle, but does | ||||
// depend on randomness in the stochastic approximation code | // depend on randomness in the stochastic approximation code | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf( | ||||
setCoinsRet, nValueRet)); | 50 * COIN, filter_standard, vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf( | ||||
setCoinsRet2, nValueRet)); | 50 * COIN, filter_standard, vCoins, setCoinsRet2, nValueRet)); | ||||
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); | BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); | ||||
int fails = 0; | int fails = 0; | ||||
for (int j = 0; j < RANDOM_REPEATS; j++) { | for (int j = 0; j < RANDOM_REPEATS; j++) { | ||||
// selecting 1 from 100 identical coins depends on the shuffle; | // selecting 1 from 100 identical coins depends on the shuffle; | ||||
// this test will fail 1% of the time run the test | // this test will fail 1% of the time run the test | ||||
// RANDOM_REPEATS times and only complain if all of them fail | // RANDOM_REPEATS times and only complain if all of them fail | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf( | ||||
setCoinsRet, nValueRet)); | COIN, filter_standard, vCoins, setCoinsRet, nValueRet)); | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf( | ||||
setCoinsRet2, nValueRet)); | COIN, filter_standard, vCoins, setCoinsRet2, nValueRet)); | ||||
if (equal_sets(setCoinsRet, setCoinsRet2)) { | if (equal_sets(setCoinsRet, setCoinsRet2)) { | ||||
fails++; | fails++; | ||||
} | } | ||||
} | } | ||||
BOOST_CHECK_NE(fails, RANDOM_REPEATS); | BOOST_CHECK_NE(fails, RANDOM_REPEATS); | ||||
// add 75 cents in small change. not enough to make 90 cents, then | // add 75 cents in small change. not enough to make 90 cents, then | ||||
// try making 90 cents. there are multiple competing "smallest | // try making 90 cents. there are multiple competing "smallest | ||||
// bigger" coins, one of which should be picked at random | // bigger" coins, one of which should be picked at random | ||||
add_coin(wallet, 5 * CENT); | add_coin(wallet, 5 * CENT); | ||||
add_coin(wallet, 10 * CENT); | add_coin(wallet, 10 * CENT); | ||||
add_coin(wallet, 15 * CENT); | add_coin(wallet, 15 * CENT); | ||||
add_coin(wallet, 20 * CENT); | add_coin(wallet, 20 * CENT); | ||||
add_coin(wallet, 25 * CENT); | add_coin(wallet, 25 * CENT); | ||||
fails = 0; | fails = 0; | ||||
for (int j = 0; j < RANDOM_REPEATS; j++) { | for (int j = 0; j < RANDOM_REPEATS; j++) { | ||||
// selecting 1 from 100 identical coins depends on the shuffle; | // selecting 1 from 100 identical coins depends on the shuffle; | ||||
// this test will fail 1% of the time run the test | // this test will fail 1% of the time run the test | ||||
// RANDOM_REPEATS times and only complain if all of them fail | // RANDOM_REPEATS times and only complain if all of them fail | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf( | BOOST_CHECK(wallet.SelectCoinsMinConf(90 * CENT, | ||||
90 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet)); | filter_standard, vCoins, | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf( | setCoinsRet, nValueRet)); | ||||
90 * CENT, 1, 6, 0, vCoins, setCoinsRet2, nValueRet)); | BOOST_CHECK(wallet.SelectCoinsMinConf(90 * CENT, | ||||
filter_standard, vCoins, | |||||
setCoinsRet2, nValueRet)); | |||||
if (equal_sets(setCoinsRet, setCoinsRet2)) { | if (equal_sets(setCoinsRet, setCoinsRet2)) { | ||||
fails++; | fails++; | ||||
} | } | ||||
} | } | ||||
BOOST_CHECK_NE(fails, RANDOM_REPEATS); | BOOST_CHECK_NE(fails, RANDOM_REPEATS); | ||||
} | } | ||||
} | } | ||||
empty_wallet(); | empty_wallet(); | ||||
Show All 9 Lines | BOOST_AUTO_TEST_CASE(ApproximateBestSubset) { | ||||
empty_wallet(); | empty_wallet(); | ||||
// Test vValue sort order | // Test vValue sort order | ||||
for (int i = 0; i < 1000; i++) { | for (int i = 0; i < 1000; i++) { | ||||
add_coin(wallet, 1000 * COIN); | add_coin(wallet, 1000 * COIN); | ||||
} | } | ||||
add_coin(wallet, 3 * COIN); | add_coin(wallet, 3 * COIN); | ||||
BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, | BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, vCoins, | ||||
setCoinsRet, nValueRet)); | setCoinsRet, nValueRet)); | ||||
BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN); | BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN); | ||||
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); | ||||
empty_wallet(); | empty_wallet(); | ||||
} | } | ||||
static void AddKey(CWallet &wallet, const CKey &key) { | static void AddKey(CWallet &wallet, const CKey &key) { | ||||
▲ Show 20 Lines • Show All 354 Lines • Show Last 20 Lines |