Changeset View
Changeset View
Standalone View
Standalone View
src/test/policyestimator_tests.cpp
Show All 21 Lines | BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) { | ||||
std::vector<Amount> feeV; | std::vector<Amount> feeV; | ||||
// Populate vectors of increasing fees | // Populate vectors of increasing fees | ||||
for (int j = 0; j < 10; j++) { | for (int j = 0; j < 10; j++) { | ||||
feeV.push_back((j + 1) * basefee); | feeV.push_back((j + 1) * basefee); | ||||
} | } | ||||
// Store the hashes of transactions that have been added to the mempool by | // Store the hashes of transactions that have been added to the mempool by | ||||
// their associate fee txHashes[j] is populated with transactions either of | // their associate fee txIds[j] is populated with transactions either of | ||||
// fee = basefee * (j+1) | // fee = basefee * (j+1) | ||||
std::vector<uint256> txHashes[10]; | std::array<std::vector<TxId>, 10> txIds; | ||||
// Create a transaction template | // Create a transaction template | ||||
CScript garbage; | CScript garbage; | ||||
for (unsigned int i = 0; i < 128; i++) | for (unsigned int i = 0; i < 128; i++) { | ||||
garbage.push_back('X'); | garbage.push_back('X'); | ||||
} | |||||
CMutableTransaction tx; | CMutableTransaction tx; | ||||
tx.vin.resize(1); | tx.vin.resize(1); | ||||
tx.vin[0].scriptSig = garbage; | tx.vin[0].scriptSig = garbage; | ||||
tx.vout.resize(1); | tx.vout.resize(1); | ||||
tx.vout[0].nValue = Amount(0); | tx.vout[0].nValue = Amount(0); | ||||
CFeeRate baseRate(basefee, CTransaction(tx).GetTotalSize()); | CFeeRate baseRate(basefee, CTransaction(tx).GetTotalSize()); | ||||
// Create a fake block | // Create a fake block | ||||
std::vector<CTransactionRef> block; | std::vector<CTransactionRef> block; | ||||
int blocknum = 0; | int blocknum = 0; | ||||
// Loop through 200 blocks | // Loop through 200 blocks | ||||
// At a decay .998 and 4 fee transactions per block | // At a decay .998 and 4 fee transactions per block | ||||
// This makes the tx count about 1.33 per bucket, above the 1 threshold | // This makes the tx count about 1.33 per bucket, above the 1 threshold | ||||
while (blocknum < 200) { | while (blocknum < 200) { | ||||
// For each fee | // For each fee | ||||
for (int j = 0; j < 10; j++) { | for (size_t j = 0; j < txIds.size(); j++) { | ||||
// add 4 fee txs | // add 4 fee txs | ||||
for (int k = 0; k < 4; k++) { | for (int k = 0; k < 4; k++) { | ||||
// make transaction unique | // make transaction unique | ||||
tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; | tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; | ||||
uint256 hash = tx.GetId(); | TxId txid = tx.GetId(); | ||||
mpool.addUnchecked(hash, | mpool.addUnchecked(txid, | ||||
entry.Fee(feeV[j]) | entry.Fee(feeV[j]) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.Priority(0) | .Priority(0) | ||||
.Height(blocknum) | .Height(blocknum) | ||||
.FromTx(tx, &mpool)); | .FromTx(tx, &mpool)); | ||||
txHashes[j].push_back(hash); | txIds[j].push_back(txid); | ||||
} | } | ||||
} | } | ||||
// Create blocks where higher fee txs are included more often | // Create blocks where higher fee txs are included more often | ||||
for (int h = 0; h <= blocknum % 10; h++) { | for (int h = 0; h <= blocknum % txIds.size(); h++) { | ||||
// 10/10 blocks add highest fee transactions | // 10/10 blocks add highest fee transactions | ||||
// 9/10 blocks add 2nd highest and so on until ... | // 9/10 blocks add 2nd highest and so on until ... | ||||
// 1/10 blocks add lowest fee transactions | // 1/10 blocks add lowest fee transactions | ||||
while (txHashes[9 - h].size()) { | size_t i = txIds.size() - h - 1; | ||||
CTransactionRef ptx = mpool.get(txHashes[9 - h].back()); | while (txIds[i].size()) { | ||||
if (ptx) block.push_back(ptx); | CTransactionRef ptx = mpool.get(txIds[i].back()); | ||||
txHashes[9 - h].pop_back(); | if (ptx) { | ||||
block.push_back(ptx); | |||||
} | |||||
txIds[i].pop_back(); | |||||
} | } | ||||
} | } | ||||
mpool.removeForBlock(block, ++blocknum); | mpool.removeForBlock(block, ++blocknum); | ||||
block.clear(); | block.clear(); | ||||
if (blocknum == 30) { | if (blocknum == 30) { | ||||
// At this point we should need to combine 5 buckets to get enough | // At this point we should need to combine 5 buckets to get enough | ||||
// data points. So estimateFee(1,2,3) should fail and estimateFee(4) | // data points. So estimateFee(1,2,3) should fail and estimateFee(4) | ||||
// should return somewhere around 8*baserate. estimateFee(4) %'s | // should return somewhere around 8*baserate. estimateFee(4) %'s | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (int i = 1; i < 10; i++) { | ||||
} else { | } else { | ||||
BOOST_CHECK(origFeeEst[i - 1] == CFeeRate(Amount(0)).GetFeePerK()); | BOOST_CHECK(origFeeEst[i - 1] == CFeeRate(Amount(0)).GetFeePerK()); | ||||
} | } | ||||
} | } | ||||
// Mine 50 more blocks with no transactions happening, estimates shouldn't | // Mine 50 more blocks with no transactions happening, estimates shouldn't | ||||
// change. We haven't decayed the moving average enough so we still have | // change. We haven't decayed the moving average enough so we still have | ||||
// enough data points in every bucket | // enough data points in every bucket | ||||
while (blocknum < 250) | while (blocknum < 250) { | ||||
mpool.removeForBlock(block, ++blocknum); | mpool.removeForBlock(block, ++blocknum); | ||||
} | |||||
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0))); | BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0))); | ||||
for (int i = 2; i < 10; i++) { | for (int i = 2; i < 10; i++) { | ||||
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < | BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < | ||||
origFeeEst[i - 1] + deltaFee); | origFeeEst[i - 1] + deltaFee); | ||||
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > | BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > | ||||
origFeeEst[i - 1] - deltaFee); | origFeeEst[i - 1] - deltaFee); | ||||
} | } | ||||
// Mine 15 more blocks with lots of transactions happening and not getting | // Mine 15 more blocks with lots of transactions happening and not getting | ||||
// mined. Estimates should go up | // mined. Estimates should go up | ||||
while (blocknum < 265) { | while (blocknum < 265) { | ||||
// For each fee multiple | // For each fee multiple | ||||
for (int j = 0; j < 10; j++) { | for (size_t j = 0; j < txIds.size(); j++) { | ||||
// add 4 fee txs | // add 4 fee txs | ||||
for (int k = 0; k < 4; k++) { | for (int k = 0; k < 4; k++) { | ||||
tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; | tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; | ||||
uint256 txid = tx.GetId(); | TxId txid = tx.GetId(); | ||||
mpool.addUnchecked(txid, | mpool.addUnchecked(txid, | ||||
entry.Fee(feeV[j]) | entry.Fee(feeV[j]) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.Priority(0) | .Priority(0) | ||||
.Height(blocknum) | .Height(blocknum) | ||||
.FromTx(tx, &mpool)); | .FromTx(tx, &mpool)); | ||||
txHashes[j].push_back(txid); | txIds[j].push_back(txid); | ||||
} | } | ||||
} | } | ||||
mpool.removeForBlock(block, ++blocknum); | mpool.removeForBlock(block, ++blocknum); | ||||
} | } | ||||
int answerFound; | int answerFound; | ||||
for (int i = 1; i < 10; i++) { | for (int i = 1; i < 10; i++) { | ||||
BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(Amount(0)) || | BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(Amount(0)) || | ||||
mpool.estimateFee(i).GetFeePerK() > | mpool.estimateFee(i).GetFeePerK() > | ||||
origFeeEst[i - 1] - deltaFee); | origFeeEst[i - 1] - deltaFee); | ||||
Amount a1 = mpool.estimateSmartFee(i, &answerFound).GetFeePerK(); | Amount a1 = mpool.estimateSmartFee(i, &answerFound).GetFeePerK(); | ||||
Amount a2 = origFeeEst[answerFound - 1] - deltaFee; | Amount a2 = origFeeEst[answerFound - 1] - deltaFee; | ||||
BOOST_CHECK(a1 > a2); | BOOST_CHECK(a1 > a2); | ||||
} | } | ||||
// Mine all those transactions | // Mine all those transactions | ||||
// Estimates should still not be below original | // Estimates should still not be below original | ||||
for (int j = 0; j < 10; j++) { | for (size_t j = 0; j < txIds.size(); j++) { | ||||
while (txHashes[j].size()) { | while (txIds[j].size()) { | ||||
CTransactionRef ptx = mpool.get(txHashes[j].back()); | CTransactionRef ptx = mpool.get(txIds[j].back()); | ||||
if (ptx) block.push_back(ptx); | if (ptx) { | ||||
txHashes[j].pop_back(); | block.push_back(ptx); | ||||
} | |||||
txIds[j].pop_back(); | |||||
} | } | ||||
} | } | ||||
mpool.removeForBlock(block, 265); | mpool.removeForBlock(block, 265); | ||||
block.clear(); | block.clear(); | ||||
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0))); | BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0))); | ||||
for (int i = 2; i < 10; i++) { | for (int i = 2; i < 10; i++) { | ||||
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > | BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > | ||||
origFeeEst[i - 1] - deltaFee); | origFeeEst[i - 1] - deltaFee); | ||||
} | } | ||||
// Mine 200 more blocks where everything is mined every block | // Mine 200 more blocks where everything is mined every block | ||||
// Estimates should be below original estimates | // Estimates should be below original estimates | ||||
while (blocknum < 465) { | while (blocknum < 465) { | ||||
// For each fee multiple | // For each fee multiple | ||||
for (int j = 0; j < 10; j++) { | for (size_t j = 0; j < txIds.size(); j++) { | ||||
// add 4 fee txs | // add 4 fee txs | ||||
for (int k = 0; k < 4; k++) { | for (int k = 0; k < 4; k++) { | ||||
tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; | tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; | ||||
uint256 txid = tx.GetId(); | TxId txid = tx.GetId(); | ||||
mpool.addUnchecked(txid, | mpool.addUnchecked(txid, | ||||
entry.Fee(feeV[j]) | entry.Fee(feeV[j]) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.Priority(0) | .Priority(0) | ||||
.Height(blocknum) | .Height(blocknum) | ||||
.FromTx(tx, &mpool)); | .FromTx(tx, &mpool)); | ||||
CTransactionRef ptx = mpool.get(txid); | CTransactionRef ptx = mpool.get(txid); | ||||
if (ptx) block.push_back(ptx); | if (ptx) { | ||||
block.push_back(ptx); | |||||
} | |||||
} | } | ||||
} | } | ||||
mpool.removeForBlock(block, ++blocknum); | mpool.removeForBlock(block, ++blocknum); | ||||
block.clear(); | block.clear(); | ||||
} | } | ||||
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0))); | BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0))); | ||||
for (int i = 2; i < 10; i++) { | for (int i = 2; i < 10; i++) { | ||||
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < | BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < | ||||
Show All 22 Lines |