Changeset View
Changeset View
Standalone View
Standalone View
src/test/mempool_tests.cpp
// Copyright (c) 2011-2016 The Bitcoin Core developers | // Copyright (c) 2011-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "policy/policy.h" | #include "policy/policy.h" | ||||
#include "txmempool.h" | #include "txmempool.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "test/test_bitcoin.h" | #include "test/test_bitcoin.h" | ||||
#include <algorithm> | |||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
#include <list> | #include <list> | ||||
#include <vector> | #include <vector> | ||||
BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup) | BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup) | ||||
BOOST_AUTO_TEST_CASE(TestPackageAccounting) { | |||||
CTxMemPool testPool; | |||||
TestMemPoolEntryHelper entry; | |||||
CMutableTransaction parentOfAll; | |||||
std::vector<CTxIn> outpoints; | |||||
const size_t maxOutputs = 3; | |||||
// Construct a parent for the rest of the chain | |||||
parentOfAll.vin.resize(1); | |||||
parentOfAll.vin[0].scriptSig = CScript(); | |||||
// Give us a couple outpoints so we can spend them | |||||
for (size_t i = 0; i < maxOutputs; i++) { | |||||
parentOfAll.vout.emplace_back(10 * SATOSHI, CScript() << OP_TRUE); | |||||
} | |||||
TxId parentOfAllId = parentOfAll.GetId(); | |||||
testPool.addUnchecked(parentOfAllId, entry.FromTx(parentOfAll)); | |||||
// Add some outpoints to the tracking vector | |||||
for (size_t i = 0; i < maxOutputs; i++) { | |||||
outpoints.emplace_back(COutPoint(parentOfAllId, i)); | |||||
} | |||||
Amount totalFee = Amount::zero(); | |||||
size_t totalSize = CTransaction(parentOfAll).GetTotalSize(); | |||||
size_t totalTransactions = 1; | |||||
// Generate 100 transactions | |||||
while (totalTransactions < 100) { | |||||
jasonbcox: Why use a while-loop instead of a for-loop? | |||||
CMutableTransaction mtx; | |||||
totalTransactions++; | |||||
uint64_t minAncestors = std::numeric_limits<size_t>::max(); | |||||
uint64_t maxAncestors = 0; | |||||
Amount minFees = MAX_MONEY; | |||||
Amount maxFees = Amount::zero(); | |||||
uint64_t minSize = std::numeric_limits<size_t>::max(); | |||||
uint64_t maxSize = 0; | |||||
// Consume random inputs, but make sure we don't consume more than | |||||
// available | |||||
for (size_t input = std::min(InsecureRandRange(maxOutputs) + 1, | |||||
uint64_t(outpoints.size())); | |||||
input > 0; input--) { | |||||
std::swap(outpoints[InsecureRandRange(outpoints.size())], | |||||
outpoints.back()); | |||||
mtx.vin.emplace_back(outpoints.back()); | |||||
outpoints.pop_back(); | |||||
// We don't know exactly how many ancestors this transaction has | |||||
// due to possible duplicates. Calculate a valid range based on | |||||
// parents. | |||||
CTxMemPoolEntry parent = | |||||
*testPool.mapTx.find(mtx.vin.back().prevout.GetTxId()); | |||||
minAncestors = | |||||
std::min(minAncestors, parent.GetCountWithAncestors()); | |||||
maxAncestors += parent.GetCountWithAncestors(); | |||||
minFees = std::min(minFees, parent.GetModFeesWithAncestors()); | |||||
maxFees += parent.GetModFeesWithAncestors(); | |||||
minSize = std::min(minSize, parent.GetSizeWithAncestors()); | |||||
maxSize += parent.GetSizeWithAncestors(); | |||||
} | |||||
// Produce random number of outputs | |||||
for (size_t output = InsecureRandRange(maxOutputs) + 1; output > 0; | |||||
output--) { | |||||
mtx.vout.emplace_back(10 * SATOSHI, CScript() << OP_TRUE); | |||||
} | |||||
CTransaction tx(mtx); | |||||
TxId curId = tx.GetId(); | |||||
// Record the outputs | |||||
for (size_t output = tx.vout.size(); output > 0; output--) { | |||||
outpoints.emplace_back(COutPoint(curId, output)); | |||||
} | |||||
testPool.addUnchecked(curId, entry.Fee(1 * SATOSHI).FromTx(tx)); | |||||
// Add this transaction to the totals. | |||||
minAncestors += 1; | |||||
maxAncestors += 1; | |||||
minFees += 1 * SATOSHI; | |||||
jasonbcoxUnsubmitted Not Done Inline ActionsIs this test intended to cover varying fees/values? If so, add some randomness to the fee and/or value of the inputs/outputs. jasonbcox: Is this test intended to cover varying fees/values? If so, add some randomness to the fee… | |||||
maxFees += 1 * SATOSHI; | |||||
minSize += CTransaction(tx).GetTotalSize(); | |||||
maxSize += CTransaction(tx).GetTotalSize(); | |||||
// Calculate overall values | |||||
totalFee += 1 * SATOSHI; | |||||
totalSize += CTransaction(tx).GetTotalSize(); | |||||
CTxMemPoolEntry parentEntry = *testPool.mapTx.find(parentOfAllId); | |||||
CTxMemPoolEntry latestEntry = *testPool.mapTx.find(curId); | |||||
// Ensure values are within the expected ranges | |||||
BOOST_CHECK(latestEntry.GetCountWithAncestors() >= minAncestors); | |||||
BOOST_CHECK(latestEntry.GetCountWithAncestors() <= maxAncestors); | |||||
BOOST_CHECK(latestEntry.GetSizeWithAncestors() >= minSize); | |||||
BOOST_CHECK(latestEntry.GetSizeWithAncestors() <= maxSize); | |||||
BOOST_CHECK(latestEntry.GetModFeesWithAncestors() >= minFees); | |||||
BOOST_CHECK(latestEntry.GetModFeesWithAncestors() <= maxFees); | |||||
BOOST_CHECK_EQUAL(parentEntry.GetCountWithDescendants(), | |||||
testPool.mapTx.size()); | |||||
BOOST_CHECK_EQUAL(parentEntry.GetSizeWithDescendants(), totalSize); | |||||
BOOST_CHECK_EQUAL(parentEntry.GetModFeesWithDescendants(), totalFee); | |||||
} | |||||
} | |||||
BOOST_AUTO_TEST_CASE(MempoolRemoveTest) { | BOOST_AUTO_TEST_CASE(MempoolRemoveTest) { | ||||
// Test CTxMemPool::remove functionality | // Test CTxMemPool::remove functionality | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
// Parent transaction with three children, and three grand-children: | // Parent transaction with three children, and three grand-children: | ||||
CMutableTransaction txParent; | CMutableTransaction txParent; | ||||
txParent.vin.resize(1); | txParent.vin.resize(1); | ||||
txParent.vin[0].scriptSig = CScript() << OP_11; | txParent.vin[0].scriptSig = CScript() << OP_11; | ||||
▲ Show 20 Lines • Show All 643 Lines • Show Last 20 Lines |
Why use a while-loop instead of a for-loop?