Changeset View
Changeset View
Standalone View
Standalone View
src/test/miner_tests.cpp
Show First 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | static void TestPackageSelection(Config &config, CScript scriptPubKey, | ||||
tx.vin[0].prevout = COutPoint(freeTxId, 0); | tx.vin[0].prevout = COutPoint(freeTxId, 0); | ||||
tx.vout[0].nValue = | tx.vout[0].nValue = | ||||
int64_t(5000000000LL - 1000 - 50000) * SATOSHI - feeToUse; | int64_t(5000000000LL - 1000 - 50000) * SATOSHI - feeToUse; | ||||
TxId lowFeeTxId = tx.GetId(); | TxId lowFeeTxId = tx.GetId(); | ||||
g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse).FromTx(tx)); | g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse).FromTx(tx)); | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); | BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); | ||||
// Verify that the free tx and the low fee tx didn't get selected. | // Verify that the free tx and the low fee tx didn't get selected. | ||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 4); | |||||
for (const auto &txn : pblocktemplate->block.vtx) { | for (const auto &txn : pblocktemplate->block.vtx) { | ||||
BOOST_CHECK(txn->GetId() != freeTxId); | BOOST_CHECK(txn->GetId() != freeTxId); | ||||
BOOST_CHECK(txn->GetId() != lowFeeTxId); | BOOST_CHECK(txn->GetId() != lowFeeTxId); | ||||
} | } | ||||
// Test that packages above the min relay fee do get included, even if one | // Test that packages above the min relay fee do get included, even if one | ||||
// of the transactions is below the min relay fee. Remove the low fee | // of the transactions is below the min relay fee. Remove the low fee | ||||
// transaction and replace with a higher fee transaction | // transaction and replace with a higher fee transaction | ||||
Show All 27 Lines | static void TestPackageSelection(Config &config, CScript scriptPubKey, | ||||
tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI - feeToUse; | tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI - feeToUse; | ||||
TxId lowFeeTxId2 = tx.GetId(); | TxId lowFeeTxId2 = tx.GetId(); | ||||
g_mempool.addUnchecked( | g_mempool.addUnchecked( | ||||
lowFeeTxId2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); | lowFeeTxId2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); | BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey); | ||||
// Verify that this tx isn't selected. | // Verify that this tx isn't selected. | ||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 6); | |||||
for (const auto &txn : pblocktemplate->block.vtx) { | for (const auto &txn : pblocktemplate->block.vtx) { | ||||
BOOST_CHECK(txn->GetId() != freeTxId2); | BOOST_CHECK(txn->GetId() != freeTxId2); | ||||
BOOST_CHECK(txn->GetId() != lowFeeTxId2); | BOOST_CHECK(txn->GetId() != lowFeeTxId2); | ||||
} | } | ||||
// This tx will be mineable, and should cause lowFeeTxId2 to be selected as | // This tx will be mineable, and should cause lowFeeTxId2 to be selected as | ||||
// well. | // well. | ||||
tx.vin[0].prevout = COutPoint(freeTxId2, 1); | tx.vin[0].prevout = COutPoint(freeTxId2, 1); | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { | ||||
fCheckpointsEnabled = false; | fCheckpointsEnabled = false; | ||||
GlobalConfig config; | GlobalConfig config; | ||||
// Simple block creation, nothing special yet: | // Simple block creation, nothing special yet: | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, g_mempool) | ||||
.CreateNewBlock(scriptPubKey, BlockAssemblerFlags::NONE)); | |||||
// We can't make transactions until we have inputs. Therefore, load 100 | // We can't make transactions until we have inputs. Therefore, load 100 | ||||
// blocks :) | // blocks :) | ||||
int baseheight = 0; | int baseheight = 0; | ||||
std::vector<CTransactionRef> txFirst; | std::vector<CTransactionRef> txFirst; | ||||
for (size_t i = 0; i < sizeof(blockinfo) / sizeof(*blockinfo); ++i) { | for (size_t i = 0; i < sizeof(blockinfo) / sizeof(*blockinfo); ++i) { | ||||
// pointer for convenience. | // pointer for convenience. | ||||
CBlock *pblock = &pblocktemplate->block; | CBlock *pblock = &pblocktemplate->block; | ||||
Show All 24 Lines | for (size_t i = 0; i < sizeof(blockinfo) / sizeof(*blockinfo); ++i) { | ||||
pblock->hashPrevBlock = pblock->GetHash(); | pblock->hashPrevBlock = pblock->GetHash(); | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Just to make sure we can still make simple blocks. | // Just to make sure we can still make simple blocks. | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, g_mempool) | ||||
.CreateNewBlock(scriptPubKey, BlockAssemblerFlags::NONE)); | |||||
const Amount BLOCKSUBSIDY = 50 * COIN; | const Amount BLOCKSUBSIDY = 50 * COIN; | ||||
const Amount LOWFEE = CENT; | const Amount LOWFEE = CENT; | ||||
const Amount HIGHFEE = COIN; | const Amount HIGHFEE = COIN; | ||||
const Amount HIGHERFEE = 4 * COIN; | const Amount HIGHERFEE = 4 * COIN; | ||||
// block sigops > limit: 1000 CHECKMULTISIG + 1 | // block sigops > limit: 1000 CHECKMULTISIG + 1 | ||||
tx.vin.resize(1); | tx.vin.resize(1); | ||||
Show All 12 Lines | for (unsigned int i = 0; i < 1001; ++i) { | ||||
// creation fails. | // creation fails. | ||||
g_mempool.addUnchecked(txid, entry.Fee(LOWFEE) | g_mempool.addUnchecked(txid, entry.Fee(LOWFEE) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.SpendsCoinbase(spendsCoinbase) | .SpendsCoinbase(spendsCoinbase) | ||||
.FromTx(tx)); | .FromTx(tx)); | ||||
tx.vin[0].prevout = COutPoint(txid, 0); | tx.vin[0].prevout = COutPoint(txid, 0); | ||||
} | } | ||||
BOOST_CHECK_THROW( | BOOST_CHECK_THROW( | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), | BlockAssembler(config, g_mempool) | ||||
.CreateNewBlock(scriptPubKey, BlockAssemblerFlags::NONE), | |||||
std::runtime_error); | std::runtime_error); | ||||
// Test empty block fallback, which should create a valid empty block | |||||
BOOST_CHECK( | |||||
pblocktemplate = | |||||
BlockAssembler(config, g_mempool) | |||||
.CreateNewBlock(scriptPubKey, | |||||
BlockAssemblerFlags::EMPTY_BLOCK_ON_FAILURE)); | |||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0); | tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0); | ||||
tx.vout[0].nValue = BLOCKSUBSIDY; | tx.vout[0].nValue = BLOCKSUBSIDY; | ||||
for (unsigned int i = 0; i < 1001; ++i) { | for (unsigned int i = 0; i < 1001; ++i) { | ||||
tx.vout[0].nValue -= LOWFEE; | tx.vout[0].nValue -= LOWFEE; | ||||
const TxId txid = tx.GetId(); | const TxId txid = tx.GetId(); | ||||
// Only first tx spends coinbase. | // Only first tx spends coinbase. | ||||
bool spendsCoinbase = i == 0; | bool spendsCoinbase = i == 0; | ||||
// If we do set the # of sig ops in the CTxMemPoolEntry, template | // If we do set the # of sig ops in the CTxMemPoolEntry, template | ||||
// creation passes. | // creation passes. | ||||
g_mempool.addUnchecked(txid, entry.Fee(LOWFEE) | g_mempool.addUnchecked(txid, entry.Fee(LOWFEE) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.SpendsCoinbase(spendsCoinbase) | .SpendsCoinbase(spendsCoinbase) | ||||
.SigOpsCost(80) | .SigOpsCost(80) | ||||
.FromTx(tx)); | .FromTx(tx)); | ||||
tx.vin[0].prevout = COutPoint(txid, 0); | tx.vin[0].prevout = COutPoint(txid, 0); | ||||
} | } | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | ||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 249); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
// block size > limit | // block size > limit | ||||
tx.vin[0].scriptSig = CScript(); | tx.vin[0].scriptSig = CScript(); | ||||
// 18 * (520char + DROP) + OP_1 = 9433 bytes | // 18 * (520char + DROP) + OP_1 = 9433 bytes | ||||
std::vector<uint8_t> vchData(520); | std::vector<uint8_t> vchData(520); | ||||
for (unsigned int i = 0; i < 18; ++i) { | for (unsigned int i = 0; i < 18; ++i) { | ||||
tx.vin[0].scriptSig << vchData << OP_DROP; | tx.vin[0].scriptSig << vchData << OP_DROP; | ||||
Show All 11 Lines | for (unsigned int i = 0; i < 128; ++i) { | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.SpendsCoinbase(spendsCoinbase) | .SpendsCoinbase(spendsCoinbase) | ||||
.FromTx(tx)); | .FromTx(tx)); | ||||
tx.vin[0].prevout = COutPoint(txid, 0); | tx.vin[0].prevout = COutPoint(txid, 0); | ||||
} | } | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | ||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 129); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
// Orphan in mempool, template creation fails. | // Orphan in mempool, template creation fails. | ||||
TxId txid = tx.GetId(); | TxId txid = tx.GetId(); | ||||
g_mempool.addUnchecked(txid, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); | g_mempool.addUnchecked(txid, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); | ||||
BOOST_CHECK_THROW( | BOOST_CHECK_THROW( | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), | BlockAssembler(config, g_mempool) | ||||
.CreateNewBlock(scriptPubKey, BlockAssemblerFlags::NONE), | |||||
std::runtime_error); | std::runtime_error); | ||||
// Add back the unused fees | |||||
tx.vout[0].nValue += 1001 * CENT; | |||||
// Test empty block fallback, which should create a valid empty block | |||||
BOOST_CHECK( | |||||
pblocktemplate = | |||||
BlockAssembler(config, g_mempool) | |||||
.CreateNewBlock(scriptPubKey, | |||||
BlockAssemblerFlags::EMPTY_BLOCK_ON_FAILURE)); | |||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
// Child with higher priority than parent. | // Child with higher priority than parent. | ||||
tx.vin[0].scriptSig = CScript() << OP_1; | tx.vin[0].scriptSig = CScript() << OP_1; | ||||
tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0); | tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0); | ||||
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; | tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; | ||||
txid = tx.GetId(); | txid = tx.GetId(); | ||||
g_mempool.addUnchecked( | g_mempool.addUnchecked( | ||||
txid, | txid, | ||||
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
tx.vin[0].prevout = COutPoint(txid, 0); | tx.vin[0].prevout = COutPoint(txid, 0); | ||||
tx.vin.resize(2); | tx.vin.resize(2); | ||||
tx.vin[1].scriptSig = CScript() << OP_1; | tx.vin[1].scriptSig = CScript() << OP_1; | ||||
tx.vin[1].prevout = COutPoint(txFirst[0]->GetId(), 0); | tx.vin[1].prevout = COutPoint(txFirst[0]->GetId(), 0); | ||||
// First txn output + fresh coinbase - new txn fee. | // First txn output + fresh coinbase - new txn fee. | ||||
tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; | tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; | ||||
txid = tx.GetId(); | txid = tx.GetId(); | ||||
g_mempool.addUnchecked( | g_mempool.addUnchecked( | ||||
txid, | txid, | ||||
entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey)); | ||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
// Coinbase in mempool, template creation fails. | // Coinbase in mempool, template creation fails. | ||||
tx.vin.resize(1); | tx.vin.resize(1); | ||||
tx.vin[0].prevout = COutPoint(); | tx.vin[0].prevout = COutPoint(); | ||||
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; | tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; | ||||
tx.vout[0].nValue = Amount::zero(); | tx.vout[0].nValue = Amount::zero(); | ||||
txid = tx.GetId(); | txid = tx.GetId(); | ||||
// Give it a fee so it'll get mined. | // Give it a fee so it'll get mined. | ||||
g_mempool.addUnchecked( | g_mempool.addUnchecked( | ||||
txid, | txid, | ||||
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | ||||
BOOST_CHECK_THROW( | BOOST_CHECK_THROW( | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), | BlockAssembler(config, g_mempool) | ||||
.CreateNewBlock(scriptPubKey, BlockAssemblerFlags::NONE), | |||||
std::runtime_error); | std::runtime_error); | ||||
// Test empty block fallback, which should create a valid empty block | |||||
BOOST_CHECK( | |||||
pblocktemplate = | |||||
BlockAssembler(config, g_mempool) | |||||
.CreateNewBlock(scriptPubKey, | |||||
BlockAssemblerFlags::EMPTY_BLOCK_ON_FAILURE)); | |||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
// Double spend txn pair in mempool, template creation fails. | // Double spend txn pair in mempool, template creation fails. | ||||
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0); | tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0); | ||||
tx.vin[0].scriptSig = CScript() << OP_1; | tx.vin[0].scriptSig = CScript() << OP_1; | ||||
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; | tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; | ||||
tx.vout[0].scriptPubKey = CScript() << OP_1; | tx.vout[0].scriptPubKey = CScript() << OP_1; | ||||
txid = tx.GetId(); | txid = tx.GetId(); | ||||
g_mempool.addUnchecked( | g_mempool.addUnchecked( | ||||
txid, | txid, | ||||
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
tx.vout[0].scriptPubKey = CScript() << OP_2; | tx.vout[0].scriptPubKey = CScript() << OP_2; | ||||
txid = tx.GetId(); | txid = tx.GetId(); | ||||
g_mempool.addUnchecked( | g_mempool.addUnchecked( | ||||
txid, | txid, | ||||
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
BOOST_CHECK_THROW( | BOOST_CHECK_THROW( | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), | BlockAssembler(config, g_mempool) | ||||
.CreateNewBlock(scriptPubKey, BlockAssemblerFlags::NONE), | |||||
std::runtime_error); | std::runtime_error); | ||||
// Test empty block fallback, which should create a valid empty block | |||||
BOOST_CHECK( | |||||
pblocktemplate = | |||||
BlockAssembler(config, g_mempool) | |||||
.CreateNewBlock(scriptPubKey, | |||||
BlockAssemblerFlags::EMPTY_BLOCK_ON_FAILURE)); | |||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
// Subsidy changing. | // Subsidy changing. | ||||
int nHeight = chainActive.Height(); | int nHeight = chainActive.Height(); | ||||
// Create an actual 209999-long block chain (without valid blocks). | // Create an actual 209999-long block chain (without valid blocks). | ||||
while (chainActive.Tip()->nHeight < 209999) { | while (chainActive.Tip()->nHeight < 209999) { | ||||
CBlockIndex *prev = chainActive.Tip(); | CBlockIndex *prev = chainActive.Tip(); | ||||
CBlockIndex *next = new CBlockIndex(); | CBlockIndex *next = new CBlockIndex(); | ||||
Show All 36 Lines | BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { | ||||
tx.vin[0].scriptSig = CScript() | tx.vin[0].scriptSig = CScript() | ||||
<< std::vector<uint8_t>(script.begin(), script.end()); | << std::vector<uint8_t>(script.begin(), script.end()); | ||||
tx.vout[0].nValue -= LOWFEE; | tx.vout[0].nValue -= LOWFEE; | ||||
txid = tx.GetId(); | txid = tx.GetId(); | ||||
g_mempool.addUnchecked( | g_mempool.addUnchecked( | ||||
txid, | txid, | ||||
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | ||||
BOOST_CHECK_THROW( | BOOST_CHECK_THROW( | ||||
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey), | BlockAssembler(config, g_mempool) | ||||
.CreateNewBlock(scriptPubKey, BlockAssemblerFlags::NONE), | |||||
std::runtime_error); | std::runtime_error); | ||||
// Test empty block fallback, which should create a valid empty block | |||||
BOOST_CHECK( | |||||
pblocktemplate = | |||||
BlockAssembler(config, g_mempool) | |||||
.CreateNewBlock(scriptPubKey, | |||||
BlockAssemblerFlags::EMPTY_BLOCK_ON_FAILURE)); | |||||
BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); | |||||
g_mempool.clear(); | g_mempool.clear(); | ||||
// Delete the dummy blocks again. | // Delete the dummy blocks again. | ||||
while (chainActive.Tip()->nHeight > nHeight) { | while (chainActive.Tip()->nHeight > nHeight) { | ||||
CBlockIndex *del = chainActive.Tip(); | CBlockIndex *del = chainActive.Tip(); | ||||
chainActive.SetTip(del->pprev); | chainActive.SetTip(del->pprev); | ||||
pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); | pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); | ||||
delete del->phashBlock; | delete del->phashBlock; | ||||
▲ Show 20 Lines • Show All 252 Lines • Show Last 20 Lines |