Changeset View
Changeset View
Standalone View
Standalone View
src/test/mempool_tests.cpp
Show First 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(MempoolClearTest) { | ||||
testPool.clear(); | testPool.clear(); | ||||
BOOST_CHECK_EQUAL(testPool.size(), 0UL); | BOOST_CHECK_EQUAL(testPool.size(), 0UL); | ||||
BOOST_CHECK_EQUAL(testPool.mapTx.size(), 0UL); | BOOST_CHECK_EQUAL(testPool.mapTx.size(), 0UL); | ||||
BOOST_CHECK_EQUAL(testPool.mapNextTx.size(), 0UL); | BOOST_CHECK_EQUAL(testPool.mapNextTx.size(), 0UL); | ||||
BOOST_CHECK_EQUAL(testPool.vTxHashes.size(), 0UL); | BOOST_CHECK_EQUAL(testPool.vTxHashes.size(), 0UL); | ||||
} | } | ||||
template <typename name> | template <typename name> | ||||
void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder) { | void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder, | ||||
std::string &&testcase) { | |||||
BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size()); | BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size()); | ||||
typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator | typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator | ||||
it = pool.mapTx.get<name>().begin(); | it = pool.mapTx.get<name>().begin(); | ||||
int count = 0; | int count = 0; | ||||
for (; it != pool.mapTx.get<name>().end(); ++it, ++count) { | for (; it != pool.mapTx.get<name>().end(); ++it, ++count) { | ||||
BOOST_CHECK_EQUAL(it->GetTx().GetId().ToString(), sortedOrder[count]); | BOOST_CHECK_MESSAGE(it->GetTx().GetId().ToString() == | ||||
sortedOrder[count], | |||||
it->GetTx().GetId().ToString() | |||||
<< " != " << sortedOrder[count] << " in test " | |||||
<< testcase << ":" << count); | |||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { | BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { | ||||
CTxMemPool pool; | CTxMemPool pool; | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
/* 3rd highest fee */ | /* 3rd highest fee */ | ||||
Show All 40 Lines | BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { | ||||
std::vector<std::string> sortedOrder; | std::vector<std::string> sortedOrder; | ||||
sortedOrder.resize(5); | sortedOrder.resize(5); | ||||
sortedOrder[0] = tx3.GetId().ToString(); // 0 | sortedOrder[0] = tx3.GetId().ToString(); // 0 | ||||
sortedOrder[1] = tx5.GetId().ToString(); // 10000 | sortedOrder[1] = tx5.GetId().ToString(); // 10000 | ||||
sortedOrder[2] = tx1.GetId().ToString(); // 10000 | sortedOrder[2] = tx1.GetId().ToString(); // 10000 | ||||
sortedOrder[3] = tx4.GetId().ToString(); // 15000 | sortedOrder[3] = tx4.GetId().ToString(); // 15000 | ||||
sortedOrder[4] = tx2.GetId().ToString(); // 20000 | sortedOrder[4] = tx2.GetId().ToString(); // 20000 | ||||
CheckSort<descendant_score>(pool, sortedOrder); | CheckSort<descendant_score>(pool, sortedOrder, "MempoolIndexingTest1"); | ||||
/* low fee but with high fee child */ | /* low fee but with high fee child */ | ||||
/* tx6 -> tx7 -> tx8, tx9 -> tx10 */ | /* tx6 -> tx7 -> tx8, tx9 -> tx10 */ | ||||
CMutableTransaction tx6 = CMutableTransaction(); | CMutableTransaction tx6 = CMutableTransaction(); | ||||
tx6.vout.resize(1); | tx6.vout.resize(1); | ||||
tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | ||||
tx6.vout[0].nValue = 20 * COIN; | tx6.vout[0].nValue = 20 * COIN; | ||||
pool.addUnchecked(tx6.GetId(), entry.Fee(Amount(0LL)).FromTx(tx6)); | pool.addUnchecked(tx6.GetId(), entry.Fee(Amount(0LL)).FromTx(tx6)); | ||||
BOOST_CHECK_EQUAL(pool.size(), 6UL); | BOOST_CHECK_EQUAL(pool.size(), 6UL); | ||||
// Check that at this point, tx6 is sorted low | // Check that at this point, tx6 is sorted low | ||||
sortedOrder.insert(sortedOrder.begin(), tx6.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin(), tx6.GetId().ToString()); | ||||
CheckSort<descendant_score>(pool, sortedOrder); | CheckSort<descendant_score>(pool, sortedOrder, "MempoolIndexingTest2"); | ||||
CTxMemPool::setEntries setAncestors; | CTxMemPool::setEntries setAncestors; | ||||
setAncestors.insert(pool.mapTx.find(tx6.GetId())); | setAncestors.insert(pool.mapTx.find(tx6.GetId())); | ||||
CMutableTransaction tx7 = CMutableTransaction(); | CMutableTransaction tx7 = CMutableTransaction(); | ||||
tx7.vin.resize(1); | tx7.vin.resize(1); | ||||
tx7.vin[0].prevout = COutPoint(tx6.GetId(), 0); | tx7.vin[0].prevout = COutPoint(tx6.GetId(), 0); | ||||
tx7.vin[0].scriptSig = CScript() << OP_11; | tx7.vin[0].scriptSig = CScript() << OP_11; | ||||
tx7.vout.resize(2); | tx7.vout.resize(2); | ||||
Show All 13 Lines | BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { | ||||
pool.addUnchecked(tx7.GetId(), entry.FromTx(tx7), setAncestors); | pool.addUnchecked(tx7.GetId(), entry.FromTx(tx7), setAncestors); | ||||
BOOST_CHECK_EQUAL(pool.size(), 7UL); | BOOST_CHECK_EQUAL(pool.size(), 7UL); | ||||
// Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... | // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... | ||||
sortedOrder.erase(sortedOrder.begin()); | sortedOrder.erase(sortedOrder.begin()); | ||||
sortedOrder.push_back(tx6.GetId().ToString()); | sortedOrder.push_back(tx6.GetId().ToString()); | ||||
sortedOrder.push_back(tx7.GetId().ToString()); | sortedOrder.push_back(tx7.GetId().ToString()); | ||||
CheckSort<descendant_score>(pool, sortedOrder); | CheckSort<descendant_score>(pool, sortedOrder, "MempoolIndexingTest3"); | ||||
/* low fee child of tx7 */ | /* low fee child of tx7 */ | ||||
CMutableTransaction tx8 = CMutableTransaction(); | CMutableTransaction tx8 = CMutableTransaction(); | ||||
tx8.vin.resize(1); | tx8.vin.resize(1); | ||||
tx8.vin[0].prevout = COutPoint(tx7.GetId(), 0); | tx8.vin[0].prevout = COutPoint(tx7.GetId(), 0); | ||||
tx8.vin[0].scriptSig = CScript() << OP_11; | tx8.vin[0].scriptSig = CScript() << OP_11; | ||||
tx8.vout.resize(1); | tx8.vout.resize(1); | ||||
tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | ||||
tx8.vout[0].nValue = 10 * COIN; | tx8.vout[0].nValue = 10 * COIN; | ||||
setAncestors.insert(pool.mapTx.find(tx7.GetId())); | setAncestors.insert(pool.mapTx.find(tx7.GetId())); | ||||
pool.addUnchecked(tx8.GetId(), entry.Fee(Amount(0LL)).Time(2).FromTx(tx8), | pool.addUnchecked(tx8.GetId(), entry.Fee(Amount(0LL)).Time(2).FromTx(tx8), | ||||
setAncestors); | setAncestors); | ||||
// Now tx8 should be sorted low, but tx6/tx both high | // Now tx8 should be sorted low, but tx6/tx both high | ||||
sortedOrder.insert(sortedOrder.begin(), tx8.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin(), tx8.GetId().ToString()); | ||||
CheckSort<descendant_score>(pool, sortedOrder); | CheckSort<descendant_score>(pool, sortedOrder, "MempoolIndexingTest4"); | ||||
/* low fee child of tx7 */ | /* low fee child of tx7 */ | ||||
CMutableTransaction tx9 = CMutableTransaction(); | CMutableTransaction tx9 = CMutableTransaction(); | ||||
tx9.vin.resize(1); | tx9.vin.resize(1); | ||||
tx9.vin[0].prevout = COutPoint(tx7.GetId(), 1); | tx9.vin[0].prevout = COutPoint(tx7.GetId(), 1); | ||||
tx9.vin[0].scriptSig = CScript() << OP_11; | tx9.vin[0].scriptSig = CScript() << OP_11; | ||||
tx9.vout.resize(1); | tx9.vout.resize(1); | ||||
tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | ||||
tx9.vout[0].nValue = 1 * COIN; | tx9.vout[0].nValue = 1 * COIN; | ||||
pool.addUnchecked(tx9.GetId(), entry.Fee(Amount(0LL)).Time(3).FromTx(tx9), | pool.addUnchecked(tx9.GetId(), entry.Fee(Amount(0LL)).Time(3).FromTx(tx9), | ||||
setAncestors); | setAncestors); | ||||
// tx9 should be sorted low | // tx9 should be sorted low | ||||
BOOST_CHECK_EQUAL(pool.size(), 9UL); | BOOST_CHECK_EQUAL(pool.size(), 9UL); | ||||
sortedOrder.insert(sortedOrder.begin(), tx9.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin(), tx9.GetId().ToString()); | ||||
CheckSort<descendant_score>(pool, sortedOrder); | CheckSort<descendant_score>(pool, sortedOrder, "MempoolIndexingTest5"); | ||||
std::vector<std::string> snapshotOrder = sortedOrder; | std::vector<std::string> snapshotOrder = sortedOrder; | ||||
setAncestors.insert(pool.mapTx.find(tx8.GetId())); | setAncestors.insert(pool.mapTx.find(tx8.GetId())); | ||||
setAncestors.insert(pool.mapTx.find(tx9.GetId())); | setAncestors.insert(pool.mapTx.find(tx9.GetId())); | ||||
/* tx10 depends on tx8 and tx9 and has a high fee*/ | /* tx10 depends on tx8 and tx9 and has a high fee*/ | ||||
CMutableTransaction tx10 = CMutableTransaction(); | CMutableTransaction tx10 = CMutableTransaction(); | ||||
tx10.vin.resize(2); | tx10.vin.resize(2); | ||||
Show All 31 Lines | BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { | ||||
* tx7 = 2.2M (4 txs) | * tx7 = 2.2M (4 txs) | ||||
*/ | */ | ||||
// take out tx9, tx8 from the beginning | // take out tx9, tx8 from the beginning | ||||
sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin() + 2); | sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin() + 2); | ||||
sortedOrder.insert(sortedOrder.begin() + 5, tx9.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin() + 5, tx9.GetId().ToString()); | ||||
sortedOrder.insert(sortedOrder.begin() + 6, tx8.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin() + 6, tx8.GetId().ToString()); | ||||
// tx10 is just before tx6 | // tx10 is just before tx6 | ||||
sortedOrder.insert(sortedOrder.begin() + 7, tx10.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin() + 7, tx10.GetId().ToString()); | ||||
CheckSort<descendant_score>(pool, sortedOrder); | CheckSort<descendant_score>(pool, sortedOrder, "MempoolIndexingTest6"); | ||||
// there should be 10 transactions in the mempool | // there should be 10 transactions in the mempool | ||||
BOOST_CHECK_EQUAL(pool.size(), 10UL); | BOOST_CHECK_EQUAL(pool.size(), 10UL); | ||||
// Now try removing tx10 and verify the sort order returns to normal | // Now try removing tx10 and verify the sort order returns to normal | ||||
pool.removeRecursive(pool.mapTx.find(tx10.GetId())->GetTx()); | pool.removeRecursive(pool.mapTx.find(tx10.GetId())->GetTx()); | ||||
CheckSort<descendant_score>(pool, snapshotOrder); | CheckSort<descendant_score>(pool, snapshotOrder, "MempoolIndexingTest7"); | ||||
pool.removeRecursive(pool.mapTx.find(tx9.GetId())->GetTx()); | pool.removeRecursive(pool.mapTx.find(tx9.GetId())->GetTx()); | ||||
pool.removeRecursive(pool.mapTx.find(tx8.GetId())->GetTx()); | pool.removeRecursive(pool.mapTx.find(tx8.GetId())->GetTx()); | ||||
/* Now check the sort on the mining score index. | /* Now check the sort on the mining score index. | ||||
* Final order should be: | * Final order should be: | ||||
* | * | ||||
* tx7 (2M) | * tx7 (2M) | ||||
* tx2 (20k) | * tx2 (20k) | ||||
Show All 15 Lines | BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { | ||||
} | } | ||||
if (tx3.GetId() < tx6.GetId()) { | if (tx3.GetId() < tx6.GetId()) { | ||||
sortedOrder.push_back(tx6.GetId().ToString()); | sortedOrder.push_back(tx6.GetId().ToString()); | ||||
sortedOrder.push_back(tx3.GetId().ToString()); | sortedOrder.push_back(tx3.GetId().ToString()); | ||||
} else { | } else { | ||||
sortedOrder.push_back(tx3.GetId().ToString()); | sortedOrder.push_back(tx3.GetId().ToString()); | ||||
sortedOrder.push_back(tx6.GetId().ToString()); | sortedOrder.push_back(tx6.GetId().ToString()); | ||||
} | } | ||||
CheckSort<mining_score>(pool, sortedOrder); | CheckSort<mining_score>(pool, sortedOrder, "MempoolIndexingTest8"); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) { | BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) { | ||||
CTxMemPool pool; | CTxMemPool pool; | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
/* 3rd highest fee */ | /* 3rd highest fee */ | ||||
CMutableTransaction tx1 = CMutableTransaction(); | CMutableTransaction tx1 = CMutableTransaction(); | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | if (tx1.GetId() < tx5.GetId()) { | ||||
sortedOrder[2] = tx1.GetId().ToString(); | sortedOrder[2] = tx1.GetId().ToString(); | ||||
sortedOrder[3] = tx5.GetId().ToString(); | sortedOrder[3] = tx5.GetId().ToString(); | ||||
} else { | } else { | ||||
sortedOrder[2] = tx5.GetId().ToString(); | sortedOrder[2] = tx5.GetId().ToString(); | ||||
sortedOrder[3] = tx1.GetId().ToString(); | sortedOrder[3] = tx1.GetId().ToString(); | ||||
} | } | ||||
sortedOrder[4] = tx3.GetId().ToString(); // 0 | sortedOrder[4] = tx3.GetId().ToString(); // 0 | ||||
CheckSort<ancestor_score>(pool, sortedOrder); | CheckSort<ancestor_score>(pool, sortedOrder, | ||||
"MempoolAncestorIndexingTest1"); | |||||
/* low fee parent with high fee child */ | /* low fee parent with high fee child */ | ||||
/* tx6 (0) -> tx7 (high) */ | /* tx6 (0) -> tx7 (high) */ | ||||
CMutableTransaction tx6 = CMutableTransaction(); | CMutableTransaction tx6 = CMutableTransaction(); | ||||
tx6.vout.resize(1); | tx6.vout.resize(1); | ||||
tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | ||||
tx6.vout[0].nValue = 20 * COIN; | tx6.vout[0].nValue = 20 * COIN; | ||||
uint64_t tx6Size = CTransaction(tx6).GetTotalSize(); | uint64_t tx6Size = CTransaction(tx6).GetTotalSize(); | ||||
pool.addUnchecked(tx6.GetId(), entry.Fee(Amount(0LL)).FromTx(tx6)); | pool.addUnchecked(tx6.GetId(), entry.Fee(Amount(0LL)).FromTx(tx6)); | ||||
BOOST_CHECK_EQUAL(pool.size(), 6UL); | BOOST_CHECK_EQUAL(pool.size(), 6UL); | ||||
// Ties are broken by hash | // Ties are broken by hash | ||||
if (tx3.GetId() < tx6.GetId()) { | if (tx3.GetId() < tx6.GetId()) { | ||||
sortedOrder.push_back(tx6.GetId().ToString()); | sortedOrder.push_back(tx6.GetId().ToString()); | ||||
} else { | } else { | ||||
sortedOrder.insert(sortedOrder.end() - 1, tx6.GetId().ToString()); | sortedOrder.insert(sortedOrder.end() - 1, tx6.GetId().ToString()); | ||||
} | } | ||||
CheckSort<ancestor_score>(pool, sortedOrder); | CheckSort<ancestor_score>(pool, sortedOrder, | ||||
"MempoolAncestorIndexingTest2"); | |||||
CMutableTransaction tx7 = CMutableTransaction(); | CMutableTransaction tx7 = CMutableTransaction(); | ||||
tx7.vin.resize(1); | tx7.vin.resize(1); | ||||
tx7.vin[0].prevout = COutPoint(tx6.GetId(), 0); | tx7.vin[0].prevout = COutPoint(tx6.GetId(), 0); | ||||
tx7.vin[0].scriptSig = CScript() << OP_11; | tx7.vin[0].scriptSig = CScript() << OP_11; | ||||
tx7.vout.resize(1); | tx7.vout.resize(1); | ||||
tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; | ||||
tx7.vout[0].nValue = 10 * COIN; | tx7.vout[0].nValue = 10 * COIN; | ||||
uint64_t tx7Size = CTransaction(tx7).GetTotalSize(); | uint64_t tx7Size = CTransaction(tx7).GetTotalSize(); | ||||
/* set the fee to just below tx2's feerate when including ancestor */ | /* set the fee to just below tx2's feerate when including ancestor */ | ||||
Amount fee((20000 / tx2Size) * (tx7Size + tx6Size) - 1); | Amount fee((20000 / tx2Size) * (tx7Size + tx6Size) - 1); | ||||
// CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); | // CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); | ||||
pool.addUnchecked(tx7.GetId(), entry.Fee(Amount(fee)).FromTx(tx7)); | pool.addUnchecked(tx7.GetId(), entry.Fee(Amount(fee)).FromTx(tx7)); | ||||
BOOST_CHECK_EQUAL(pool.size(), 7UL); | BOOST_CHECK_EQUAL(pool.size(), 7UL); | ||||
sortedOrder.insert(sortedOrder.begin() + 1, tx7.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin() + 1, tx7.GetId().ToString()); | ||||
CheckSort<ancestor_score>(pool, sortedOrder); | CheckSort<ancestor_score>(pool, sortedOrder, | ||||
"MempoolAncestorIndexingTest3"); | |||||
/* after tx6 is mined, tx7 should move up in the sort */ | /* after tx6 is mined, tx7 should move up in the sort */ | ||||
std::vector<CTransactionRef> vtx; | std::vector<CTransactionRef> vtx; | ||||
vtx.push_back(MakeTransactionRef(tx6)); | vtx.push_back(MakeTransactionRef(tx6)); | ||||
pool.removeForBlock(vtx, 1); | pool.removeForBlock(vtx, 1); | ||||
sortedOrder.erase(sortedOrder.begin() + 1); | sortedOrder.erase(sortedOrder.begin() + 1); | ||||
// Ties are broken by hash | // Ties are broken by hash | ||||
if (tx3.GetId() < tx6.GetId()) | if (tx3.GetId() < tx6.GetId()) | ||||
sortedOrder.pop_back(); | sortedOrder.pop_back(); | ||||
else | else | ||||
sortedOrder.erase(sortedOrder.end() - 2); | sortedOrder.erase(sortedOrder.end() - 2); | ||||
sortedOrder.insert(sortedOrder.begin(), tx7.GetId().ToString()); | sortedOrder.insert(sortedOrder.begin(), tx7.GetId().ToString()); | ||||
CheckSort<ancestor_score>(pool, sortedOrder); | CheckSort<ancestor_score>(pool, sortedOrder, | ||||
"MempoolAncestorIndexingTest4"); | |||||
} | } | ||||
BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) { | BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) { | ||||
CTxMemPool pool; | CTxMemPool pool; | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
entry.dPriority = 10.0; | entry.dPriority = 10.0; | ||||
Amount feeIncrement = MEMPOOL_FULL_FEE_INCREMENT.GetFeePerK(); | Amount feeIncrement = MEMPOOL_FULL_FEE_INCREMENT.GetFeePerK(); | ||||
▲ Show 20 Lines • Show All 170 Lines • Show Last 20 Lines |