Changeset View
Changeset View
Standalone View
Standalone View
src/test/miner_tests.cpp
Show First 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | void TestPackageSelection(const CChainParams &chainparams, CScript scriptPubKey, | ||||
// these 3 tests assume blockprioritypercentage is 0. | // these 3 tests assume blockprioritypercentage is 0. | ||||
config.SetBlockPriorityPercentage(0); | config.SetBlockPriorityPercentage(0); | ||||
// Test that a medium fee transaction will be selected after a higher fee | // Test that a medium fee transaction will be selected after a higher fee | ||||
// rate package with a low fee rate parent. | // rate package with a low fee rate parent. | ||||
CMutableTransaction tx; | CMutableTransaction tx; | ||||
tx.vin.resize(1); | tx.vin.resize(1); | ||||
tx.vin[0].scriptSig = CScript() << OP_1; | tx.vin[0].scriptSig = CScript() << OP_1; | ||||
tx.vin[0].prevout.hash = txFirst[0]->GetId(); | tx.vin[0].prevout.hash = txFirst[0]->GetHash(); | ||||
tx.vin[0].prevout.n = 0; | tx.vin[0].prevout.n = 0; | ||||
tx.vout.resize(1); | tx.vout.resize(1); | ||||
tx.vout[0].nValue = 5000000000LL - 1000; | tx.vout[0].nValue = 5000000000LL - 1000; | ||||
// This tx has a low fee: 1000 satoshis. | // This tx has a low fee: 1000 satoshis. | ||||
// Save this txid for later use. | // Save this txid for later use. | ||||
uint256 hashParentTx = tx.GetId(); | uint256 hashParentTx = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hashParentTx, | hashParentTx, | ||||
entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
// This tx has a medium fee: 10000 satoshis. | // This tx has a medium fee: 10000 satoshis. | ||||
tx.vin[0].prevout.hash = txFirst[1]->GetId(); | tx.vin[0].prevout.hash = txFirst[1]->GetHash(); | ||||
tx.vout[0].nValue = 5000000000LL - 10000; | tx.vout[0].nValue = 5000000000LL - 10000; | ||||
uint256 hashMediumFeeTx = tx.GetId(); | uint256 hashMediumFeeTx = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hashMediumFeeTx, | hashMediumFeeTx, | ||||
entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
// This tx has a high fee, but depends on the first transaction. | // This tx has a high fee, but depends on the first transaction. | ||||
tx.vin[0].prevout.hash = hashParentTx; | tx.vin[0].prevout.hash = hashParentTx; | ||||
// 50k satoshi fee. | // 50k satoshi fee. | ||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; | tx.vout[0].nValue = 5000000000LL - 1000 - 50000; | ||||
uint256 hashHighFeeTx = tx.GetId(); | uint256 hashHighFeeTx = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hashHighFeeTx, | hashHighFeeTx, | ||||
entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | ||||
std::unique_ptr<CBlockTemplate> pblocktemplate = | std::unique_ptr<CBlockTemplate> pblocktemplate = | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == hashParentTx); | BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == hashHighFeeTx); | BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == hashMediumFeeTx); | BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx); | ||||
// Test that a package below the block min tx fee doesn't get included | // Test that a package below the block min tx fee doesn't get included | ||||
tx.vin[0].prevout.hash = hashHighFeeTx; | tx.vin[0].prevout.hash = hashHighFeeTx; | ||||
// 0 fee. | // 0 fee. | ||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; | tx.vout[0].nValue = 5000000000LL - 1000 - 50000; | ||||
uint256 hashFreeTx = tx.GetId(); | uint256 hashFreeTx = tx.GetHash(); | ||||
mempool.addUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx)); | mempool.addUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx)); | ||||
size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); | size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); | ||||
// Calculate a fee on child transaction that will put the package just | // Calculate a fee on child transaction that will put the package just | ||||
// below the block min tx fee (assuming 1 child tx of the same size). | // below the block min tx fee (assuming 1 child tx of the same size). | ||||
CAmount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize).GetSatoshis() - 1; | CAmount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize).GetSatoshis() - 1; | ||||
tx.vin[0].prevout.hash = hashFreeTx; | tx.vin[0].prevout.hash = hashFreeTx; | ||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; | tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; | ||||
uint256 hashLowFeeTx = tx.GetId(); | uint256 hashLowFeeTx = tx.GetHash(); | ||||
mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx)); | mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx)); | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | BlockAssembler(config, chainparams).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. | ||||
for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { | for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { | ||||
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashFreeTx); | BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashLowFeeTx); | BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx); | ||||
} | } | ||||
// 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 | ||||
mempool.removeRecursive(tx); | mempool.removeRecursive(tx); | ||||
// Now we should be just over the min relay fee. | // Now we should be just over the min relay fee. | ||||
tx.vout[0].nValue -= 2; | tx.vout[0].nValue -= 2; | ||||
hashLowFeeTx = tx.GetId(); | hashLowFeeTx = tx.GetHash(); | ||||
mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse + 2).FromTx(tx)); | mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse + 2).FromTx(tx)); | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == hashFreeTx); | BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == hashLowFeeTx); | BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); | ||||
// Test that transaction selection properly updates ancestor fee | // Test that transaction selection properly updates ancestor fee | ||||
// calculations as ancestor transactions get included in a block. Add a | // calculations as ancestor transactions get included in a block. Add a | ||||
// 0-fee transaction that has 2 outputs. | // 0-fee transaction that has 2 outputs. | ||||
tx.vin[0].prevout.hash = txFirst[2]->GetId(); | tx.vin[0].prevout.hash = txFirst[2]->GetHash(); | ||||
tx.vout.resize(2); | tx.vout.resize(2); | ||||
tx.vout[0].nValue = 5000000000LL - 100000000; | tx.vout[0].nValue = 5000000000LL - 100000000; | ||||
// 1BCC output. | // 1BCC output. | ||||
tx.vout[1].nValue = 100000000; | tx.vout[1].nValue = 100000000; | ||||
uint256 hashFreeTx2 = tx.GetId(); | uint256 hashFreeTx2 = tx.GetHash(); | ||||
mempool.addUnchecked(hashFreeTx2, | mempool.addUnchecked(hashFreeTx2, | ||||
entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); | ||||
// This tx can't be mined by itself. | // This tx can't be mined by itself. | ||||
tx.vin[0].prevout.hash = hashFreeTx2; | tx.vin[0].prevout.hash = hashFreeTx2; | ||||
tx.vout.resize(1); | tx.vout.resize(1); | ||||
feeToUse = blockMinFeeRate.GetFee(freeTxSize).GetSatoshis(); | feeToUse = blockMinFeeRate.GetFee(freeTxSize).GetSatoshis(); | ||||
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; | tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; | ||||
uint256 hashLowFeeTx2 = tx.GetId(); | uint256 hashLowFeeTx2 = tx.GetHash(); | ||||
mempool.addUnchecked(hashLowFeeTx2, | mempool.addUnchecked(hashLowFeeTx2, | ||||
entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); | entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | ||||
// Verify that this tx isn't selected. | // Verify that this tx isn't selected. | ||||
for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { | for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { | ||||
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashFreeTx2); | BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx2); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashLowFeeTx2); | BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx2); | ||||
} | } | ||||
// This tx will be mineable, and should cause hashLowFeeTx2 to be selected | // This tx will be mineable, and should cause hashLowFeeTx2 to be selected | ||||
// as well. | // as well. | ||||
tx.vin[0].prevout.n = 1; | tx.vin[0].prevout.n = 1; | ||||
// 10k satoshi fee. | // 10k satoshi fee. | ||||
tx.vout[0].nValue = 100000000 - 10000; | tx.vout[0].nValue = 100000000 - 10000; | ||||
mempool.addUnchecked(tx.GetId(), entry.Fee(10000).FromTx(tx)); | mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx)); | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == hashLowFeeTx2); | BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); | ||||
} | } | ||||
void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg) { | void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg) { | ||||
GlobalConfig config; | GlobalConfig config; | ||||
config.SetMaxBlockSize(eb); | config.SetMaxBlockSize(eb); | ||||
const CChainParams &chainparams = config.GetChainParams(); | const CChainParams &chainparams = config.GetChainParams(); | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { | ||||
const CAmount HIGHFEE = COIN.GetSatoshis(); | const CAmount HIGHFEE = COIN.GetSatoshis(); | ||||
const CAmount HIGHERFEE = 4 * COIN.GetSatoshis(); | const CAmount HIGHERFEE = 4 * COIN.GetSatoshis(); | ||||
// block sigops > limit: 1000 CHECKMULTISIG + 1 | // block sigops > limit: 1000 CHECKMULTISIG + 1 | ||||
tx.vin.resize(1); | tx.vin.resize(1); | ||||
// NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG | // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG | ||||
tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP | tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP | ||||
<< OP_CHECKMULTISIG << OP_1; | << OP_CHECKMULTISIG << OP_1; | ||||
tx.vin[0].prevout.hash = txFirst[0]->GetId(); | tx.vin[0].prevout.hash = txFirst[0]->GetHash(); | ||||
tx.vin[0].prevout.n = 0; | tx.vin[0].prevout.n = 0; | ||||
tx.vout.resize(1); | tx.vout.resize(1); | ||||
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; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
// Only first tx spends coinbase. | // Only first tx spends coinbase. | ||||
bool spendsCoinbase = (i == 0) ? true : false; | bool spendsCoinbase = (i == 0) ? true : false; | ||||
// If we don't set the # of sig ops in the CTxMemPoolEntry, template | // If we don't set the # of sig ops in the CTxMemPoolEntry, template | ||||
// creation fails. | // creation fails. | ||||
mempool.addUnchecked(hash, entry.Fee(LOWFEE) | mempool.addUnchecked(hash, entry.Fee(LOWFEE) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.SpendsCoinbase(spendsCoinbase) | .SpendsCoinbase(spendsCoinbase) | ||||
.FromTx(tx)); | .FromTx(tx)); | ||||
tx.vin[0].prevout.hash = hash; | tx.vin[0].prevout.hash = hash; | ||||
} | } | ||||
BOOST_CHECK_THROW( | BOOST_CHECK_THROW( | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), | ||||
std::runtime_error); | std::runtime_error); | ||||
mempool.clear(); | mempool.clear(); | ||||
tx.vin[0].prevout.hash = txFirst[0]->GetId(); | tx.vin[0].prevout.hash = txFirst[0]->GetHash(); | ||||
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; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
// Only first tx spends coinbase. | // Only first tx spends coinbase. | ||||
bool spendsCoinbase = (i == 0) ? true : false; | bool spendsCoinbase = (i == 0) ? true : false; | ||||
// 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. | ||||
mempool.addUnchecked(hash, entry.Fee(LOWFEE) | mempool.addUnchecked(hash, entry.Fee(LOWFEE) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.SpendsCoinbase(spendsCoinbase) | .SpendsCoinbase(spendsCoinbase) | ||||
.SigOpsCost(80) | .SigOpsCost(80) | ||||
.FromTx(tx)); | .FromTx(tx)); | ||||
tx.vin[0].prevout.hash = hash; | tx.vin[0].prevout.hash = hash; | ||||
} | } | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); | ||||
mempool.clear(); | 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; | ||||
tx.vin[0].scriptSig << OP_1; | tx.vin[0].scriptSig << OP_1; | ||||
tx.vin[0].prevout.hash = txFirst[0]->GetId(); | tx.vin[0].prevout.hash = txFirst[0]->GetHash(); | ||||
tx.vout[0].nValue = BLOCKSUBSIDY; | tx.vout[0].nValue = BLOCKSUBSIDY; | ||||
for (unsigned int i = 0; i < 128; ++i) { | for (unsigned int i = 0; i < 128; ++i) { | ||||
tx.vout[0].nValue -= LOWFEE; | tx.vout[0].nValue -= LOWFEE; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
// Only first tx spends coinbase. | // Only first tx spends coinbase. | ||||
bool spendsCoinbase = (i == 0) ? true : false; | bool spendsCoinbase = (i == 0) ? true : false; | ||||
mempool.addUnchecked(hash, entry.Fee(LOWFEE) | mempool.addUnchecked(hash, entry.Fee(LOWFEE) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.SpendsCoinbase(spendsCoinbase) | .SpendsCoinbase(spendsCoinbase) | ||||
.FromTx(tx)); | .FromTx(tx)); | ||||
tx.vin[0].prevout.hash = hash; | tx.vin[0].prevout.hash = hash; | ||||
} | } | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
pblocktemplate = | pblocktemplate = | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); | ||||
mempool.clear(); | mempool.clear(); | ||||
// Orphan in mempool, template creation fails. | // Orphan in mempool, template creation fails. | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); | mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); | ||||
BOOST_CHECK_THROW( | BOOST_CHECK_THROW( | ||||
BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), | ||||
std::runtime_error); | std::runtime_error); | ||||
mempool.clear(); | 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.hash = txFirst[1]->GetId(); | tx.vin[0].prevout.hash = txFirst[1]->GetHash(); | ||||
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; | tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
tx.vin[0].prevout.hash = hash; | tx.vin[0].prevout.hash = hash; | ||||
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.hash = txFirst[0]->GetId(); | tx.vin[1].prevout.hash = txFirst[0]->GetHash(); | ||||
tx.vin[1].prevout.n = 0; | tx.vin[1].prevout.n = 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; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
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, chainparams).CreateNewBlock(scriptPubKey)); | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); | ||||
mempool.clear(); | 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.SetNull(); | tx.vin[0].prevout.SetNull(); | ||||
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; | tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; | ||||
tx.vout[0].nValue = 0; | tx.vout[0].nValue = 0; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
// Give it a fee so it'll get mined. | // Give it a fee so it'll get mined. | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
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, chainparams).CreateNewBlock(scriptPubKey), | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), | ||||
std::runtime_error); | std::runtime_error); | ||||
mempool.clear(); | mempool.clear(); | ||||
// Invalid (pre-p2sh) txn in mempool, template creation fails. | // Invalid (pre-p2sh) txn in mempool, template creation fails. | ||||
tx.vin[0].prevout.hash = txFirst[0]->GetId(); | tx.vin[0].prevout.hash = txFirst[0]->GetHash(); | ||||
tx.vin[0].prevout.n = 0; | tx.vin[0].prevout.n = 0; | ||||
tx.vin[0].scriptSig = CScript() << OP_1; | tx.vin[0].scriptSig = CScript() << OP_1; | ||||
tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE; | tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE; | ||||
script = CScript() << OP_0; | script = CScript() << OP_0; | ||||
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); | tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
tx.vin[0].prevout.hash = hash; | tx.vin[0].prevout.hash = hash; | ||||
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; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
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, chainparams).CreateNewBlock(scriptPubKey), | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), | ||||
std::runtime_error); | std::runtime_error); | ||||
mempool.clear(); | mempool.clear(); | ||||
// Double spend txn pair in mempool, template creation fails. | // Double spend txn pair in mempool, template creation fails. | ||||
tx.vin[0].prevout.hash = txFirst[0]->GetId(); | tx.vin[0].prevout.hash = txFirst[0]->GetHash(); | ||||
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; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
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; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
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, chainparams).CreateNewBlock(scriptPubKey), | BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), | ||||
std::runtime_error); | std::runtime_error); | ||||
mempool.clear(); | mempool.clear(); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { | ||||
// height map | // height map | ||||
std::vector<int> prevheights; | std::vector<int> prevheights; | ||||
// Relative height locked. | // Relative height locked. | ||||
tx.nVersion = 2; | tx.nVersion = 2; | ||||
tx.vin.resize(1); | tx.vin.resize(1); | ||||
prevheights.resize(1); | prevheights.resize(1); | ||||
// Only 1 transaction. | // Only 1 transaction. | ||||
tx.vin[0].prevout.hash = txFirst[0]->GetId(); | tx.vin[0].prevout.hash = txFirst[0]->GetHash(); | ||||
tx.vin[0].prevout.n = 0; | tx.vin[0].prevout.n = 0; | ||||
tx.vin[0].scriptSig = CScript() << OP_1; | tx.vin[0].scriptSig = CScript() << OP_1; | ||||
// txFirst[0] is the 2nd block | // txFirst[0] is the 2nd block | ||||
tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; | tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; | ||||
prevheights[0] = baseheight + 1; | prevheights[0] = baseheight + 1; | ||||
tx.vout.resize(1); | tx.vout.resize(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; | ||||
tx.nLockTime = 0; | tx.nLockTime = 0; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked( | mempool.addUnchecked( | ||||
hash, | hash, | ||||
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
{ | { | ||||
// Locktime passes. | // Locktime passes. | ||||
GlobalConfig config; | GlobalConfig config; | ||||
CValidationState state; | CValidationState state; | ||||
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock( | BOOST_CHECK(ContextualCheckTransactionForCurrentBlock( | ||||
config, tx, state, chainparams.GetConsensus(), flags)); | config, tx, state, chainparams.GetConsensus(), flags)); | ||||
} | } | ||||
// Sequence locks fail. | // Sequence locks fail. | ||||
BOOST_CHECK(!TestSequenceLocks(tx, flags)); | BOOST_CHECK(!TestSequenceLocks(tx, flags)); | ||||
// Sequence locks pass on 2nd block. | // Sequence locks pass on 2nd block. | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
SequenceLocks(tx, flags, &prevheights, | SequenceLocks(tx, flags, &prevheights, | ||||
CreateBlockIndex(chainActive.Tip()->nHeight + 2))); | CreateBlockIndex(chainActive.Tip()->nHeight + 2))); | ||||
// Relative time locked. | // Relative time locked. | ||||
tx.vin[0].prevout.hash = txFirst[1]->GetId(); | tx.vin[0].prevout.hash = txFirst[1]->GetHash(); | ||||
// txFirst[1] is the 3rd block. | // txFirst[1] is the 3rd block. | ||||
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | | tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | | ||||
(((chainActive.Tip()->GetMedianTimePast() + 1 - | (((chainActive.Tip()->GetMedianTimePast() + 1 - | ||||
chainActive[1]->GetMedianTimePast()) >> | chainActive[1]->GetMedianTimePast()) >> | ||||
CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + | CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + | ||||
1); | 1); | ||||
prevheights[0] = baseheight + 2; | prevheights[0] = baseheight + 2; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); | mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); | ||||
{ | { | ||||
// Locktime passes. | // Locktime passes. | ||||
GlobalConfig config; | GlobalConfig config; | ||||
CValidationState state; | CValidationState state; | ||||
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock( | BOOST_CHECK(ContextualCheckTransactionForCurrentBlock( | ||||
config, tx, state, chainparams.GetConsensus(), flags)); | config, tx, state, chainparams.GetConsensus(), flags)); | ||||
Show All 13 Lines | BOOST_CHECK( | ||||
CreateBlockIndex(chainActive.Tip()->nHeight + 1))); | CreateBlockIndex(chainActive.Tip()->nHeight + 1))); | ||||
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { | for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { | ||||
// Undo tricked MTP. | // Undo tricked MTP. | ||||
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= | chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= | ||||
512; | 512; | ||||
} | } | ||||
// Absolute height locked. | // Absolute height locked. | ||||
tx.vin[0].prevout.hash = txFirst[2]->GetId(); | tx.vin[0].prevout.hash = txFirst[2]->GetHash(); | ||||
tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; | tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; | ||||
prevheights[0] = baseheight + 3; | prevheights[0] = baseheight + 3; | ||||
tx.nLockTime = chainActive.Tip()->nHeight + 1; | tx.nLockTime = chainActive.Tip()->nHeight + 1; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); | mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); | ||||
{ | { | ||||
// Locktime fails. | // Locktime fails. | ||||
GlobalConfig config; | GlobalConfig config; | ||||
CValidationState state; | CValidationState state; | ||||
BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock( | BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock( | ||||
config, tx, state, chainparams.GetConsensus(), flags)); | config, tx, state, chainparams.GetConsensus(), flags)); | ||||
Show All 9 Lines | BOOST_CHECK(TestSequenceLocks(tx, flags)); | ||||
CValidationState state; | CValidationState state; | ||||
BOOST_CHECK(ContextualCheckTransaction( | BOOST_CHECK(ContextualCheckTransaction( | ||||
config, tx, state, chainparams.GetConsensus(), | config, tx, state, chainparams.GetConsensus(), | ||||
chainActive.Tip()->nHeight + 2, | chainActive.Tip()->nHeight + 2, | ||||
chainActive.Tip()->GetMedianTimePast())); | chainActive.Tip()->GetMedianTimePast())); | ||||
} | } | ||||
// Absolute time locked. | // Absolute time locked. | ||||
tx.vin[0].prevout.hash = txFirst[3]->GetId(); | tx.vin[0].prevout.hash = txFirst[3]->GetHash(); | ||||
tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); | tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); | ||||
prevheights.resize(1); | prevheights.resize(1); | ||||
prevheights[0] = baseheight + 4; | prevheights[0] = baseheight + 4; | ||||
hash = tx.GetId(); | hash = tx.GetHash(); | ||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); | mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); | ||||
{ | { | ||||
// Locktime fails. | // Locktime fails. | ||||
GlobalConfig config; | GlobalConfig config; | ||||
CValidationState state; | CValidationState state; | ||||
BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock( | BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock( | ||||
config, tx, state, chainparams.GetConsensus(), flags)); | config, tx, state, chainparams.GetConsensus(), flags)); | ||||
▲ Show 20 Lines • Show All 146 Lines • Show Last 20 Lines |