Page MenuHomePhabricator

miner_tests.cpp
No OneTemporary

miner_tests.cpp

// Copyright (c) 2011-2016 The Bitcoin Core developers
// Copyright (c) 2017-2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <miner.h>
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
#include <config.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <policy/policy.h>
#include <pubkey.h>
#include <script/standard.h>
#include <txmempool.h>
#include <uint256.h>
#include <util.h>
#include <utilstrencodings.h>
#include <validation.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <memory>
BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB);
static struct {
uint8_t extranonce;
uint32_t nonce;
} blockinfo[] = {
{4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5},
{2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84},
{2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4},
{2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa},
{1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb},
{3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406},
{2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38},
{2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9},
{1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7},
{2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34},
{1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c},
{1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f},
{1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81},
{1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78},
{1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c},
{2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049},
{2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169},
{1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10},
{1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d},
{2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323},
{1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6},
{1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408},
{1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602},
{0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459},
{2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668},
{1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce},
{2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e},
{2, 0xbbbeb305}, {2, 0xfe1c810a},
};
CBlockIndex CreateBlockIndex(int nHeight) {
CBlockIndex index;
index.nHeight = nHeight;
index.pprev = chainActive.Tip();
return index;
}
bool TestSequenceLocks(const CTransaction &tx, int flags) {
LOCK(g_mempool.cs);
return CheckSequenceLocks(tx, flags);
}
// Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case, to
// allow reusing the blockchain created in CreateNewBlock_validity.
// Note that this test assumes blockprioritypercentage is 0.
void TestPackageSelection(Config &config, CScript scriptPubKey,
std::vector<CTransactionRef> &txFirst) {
// Test the ancestor feerate transaction selection.
TestMemPoolEntryHelper entry;
// these 3 tests assume blockprioritypercentage is 0.
config.SetBlockPriorityPercentage(0);
// Test that a medium fee transaction will be selected after a higher fee
// rate package with a low fee rate parent.
CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout.resize(1);
tx.vout[0].nValue = int64_t(5000000000LL - 1000) * SATOSHI;
// This tx has a low fee: 1000 satoshis.
// Save this txid for later use.
TxId parentTxId = tx.GetId();
g_mempool.addUnchecked(parentTxId, entry.Fee(1000 * SATOSHI)
.Time(GetTime())
.SpendsCoinbase(true)
.FromTx(tx));
// This tx has a medium fee: 10000 satoshis.
tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
tx.vout[0].nValue = int64_t(5000000000LL - 10000) * SATOSHI;
TxId mediumFeeTxId = tx.GetId();
g_mempool.addUnchecked(mediumFeeTxId, entry.Fee(10000 * SATOSHI)
.Time(GetTime())
.SpendsCoinbase(true)
.FromTx(tx));
// This tx has a high fee, but depends on the first transaction.
tx.vin[0].prevout = COutPoint(parentTxId, 0);
// 50k satoshi fee.
tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI;
TxId highFeeTxId = tx.GetId();
g_mempool.addUnchecked(highFeeTxId, entry.Fee(50000 * SATOSHI)
.Time(GetTime())
.SpendsCoinbase(false)
.FromTx(tx));
std::unique_ptr<CBlockTemplate> pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == parentTxId);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == highFeeTxId);
BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == mediumFeeTxId);
// Test that a package below the block min tx fee doesn't get included
tx.vin[0].prevout = COutPoint(highFeeTxId, 0);
// 0 fee.
tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI;
TxId freeTxId = tx.GetId();
g_mempool.addUnchecked(freeTxId, entry.Fee(Amount::zero()).FromTx(tx));
size_t freeTxSize = CTransaction(tx).GetBillableSize();
// 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).
Amount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize) - SATOSHI;
tx.vin[0].prevout = COutPoint(freeTxId, 0);
tx.vout[0].nValue =
int64_t(5000000000LL - 1000 - 50000) * SATOSHI - feeToUse;
TxId lowFeeTxId = tx.GetId();
g_mempool.addUnchecked(lowFeeTxId, entry.Fee(feeToUse).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected.
for (const auto &txn : pblocktemplate->block.vtx) {
BOOST_CHECK(txn->GetId() != freeTxId);
BOOST_CHECK(txn->GetId() != lowFeeTxId);
}
// 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
// transaction and replace with a higher fee transaction
g_mempool.removeRecursive(CTransaction(tx));
// Now we should be just over the min relay fee.
tx.vout[0].nValue -= 2 * SATOSHI;
lowFeeTxId = tx.GetId();
g_mempool.addUnchecked(lowFeeTxId,
entry.Fee(feeToUse + 2 * SATOSHI).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == freeTxId);
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == lowFeeTxId);
// Test that transaction selection properly updates ancestor fee
// calculations as ancestor transactions get included in a block. Add a
// 0-fee transaction that has 2 outputs.
tx.vin[0].prevout = COutPoint(txFirst[2]->GetId(), 0);
tx.vout.resize(2);
tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI;
// 1BCC output.
tx.vout[1].nValue = 100000000 * SATOSHI;
TxId freeTxId2 = tx.GetId();
g_mempool.addUnchecked(
freeTxId2, entry.Fee(Amount::zero()).SpendsCoinbase(true).FromTx(tx));
// This tx can't be mined by itself.
tx.vin[0].prevout = COutPoint(freeTxId2, 0);
tx.vout.resize(1);
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI - feeToUse;
TxId lowFeeTxId2 = tx.GetId();
g_mempool.addUnchecked(
lowFeeTxId2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
// Verify that this tx isn't selected.
for (const auto &txn : pblocktemplate->block.vtx) {
BOOST_CHECK(txn->GetId() != freeTxId2);
BOOST_CHECK(txn->GetId() != lowFeeTxId2);
}
// This tx will be mineable, and should cause lowFeeTxId2 to be selected as
// well.
tx.vin[0].prevout = COutPoint(freeTxId2, 1);
// 10k satoshi fee.
tx.vout[0].nValue = (100000000 - 10000) * SATOSHI;
g_mempool.addUnchecked(tx.GetId(), entry.Fee(10000 * SATOSHI).FromTx(tx));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == lowFeeTxId2);
}
void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg) {
GlobalConfig config;
config.SetMaxBlockSize(eb);
CScript scriptPubKey =
CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
"a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
"de5c384df7ba0b8d578a4c702b6bf11d5f")
<< OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
CBlock *pblock = &pblocktemplate->block;
// IncrementExtraNonce creates a valid coinbase and merkleRoot
unsigned int extraNonce = 0;
IncrementExtraNonce(config, pblock, chainActive.Tip(), extraNonce);
unsigned int nHeight = chainActive.Tip()->nHeight + 1;
std::vector<uint8_t> vec(cbmsg.begin(), cbmsg.end());
BOOST_CHECK(pblock->vtx[0]->vin[0].scriptSig ==
((CScript() << nHeight << CScriptNum(extraNonce) << vec) +
COINBASE_FLAGS));
}
// Coinbase scriptSig has to contains the correct EB value
// converted to MB, rounded down to the first decimal
BOOST_AUTO_TEST_CASE(CheckCoinbase_EB) {
TestCoinbaseMessageEB(1000001, "/EB1.0/");
TestCoinbaseMessageEB(2000000, "/EB2.0/");
TestCoinbaseMessageEB(8000000, "/EB8.0/");
TestCoinbaseMessageEB(8320000, "/EB8.3/");
}
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) {
// Note that by default, these tests run with size accounting enabled.
CScript scriptPubKey =
CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
"a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
"de5c384df7ba0b8d578a4c702b6bf11d5f")
<< OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblocktemplate;
CMutableTransaction tx, tx2;
CScript script;
uint256 hash;
TestMemPoolEntryHelper entry;
entry.nFee = 11 * SATOSHI;
entry.dPriority = 111.0;
entry.nHeight = 11;
fCheckpointsEnabled = false;
GlobalConfig config;
// Simple block creation, nothing special yet:
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
// We can't make transactions until we have inputs. Therefore, load 100
// blocks :)
int baseheight = 0;
std::vector<CTransactionRef> txFirst;
for (size_t i = 0; i < sizeof(blockinfo) / sizeof(*blockinfo); ++i) {
// pointer for convenience.
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast() + 1;
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
txCoinbase.vout.resize(1);
txCoinbase.vout[0].scriptPubKey = CScript();
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
if (txFirst.size() == 0) {
baseheight = chainActive.Height();
}
if (txFirst.size() < 4) {
txFirst.push_back(pblock->vtx[0]);
}
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
}
std::shared_ptr<const CBlock> shared_pblock =
std::make_shared<const CBlock>(*pblock);
BOOST_CHECK(ProcessNewBlock(config, shared_pblock, true, nullptr));
pblock->hashPrevBlock = pblock->GetHash();
}
LOCK(cs_main);
// Just to make sure we can still make simple blocks.
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
const Amount BLOCKSUBSIDY = 50 * COIN;
const Amount LOWFEE = CENT;
const Amount HIGHFEE = COIN;
const Amount HIGHERFEE = 4 * COIN;
// block sigops > limit: 1000 CHECKMULTISIG + 1
tx.vin.resize(1);
// 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
<< OP_CHECKMULTISIG << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout.resize(1);
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i) {
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
// Only first tx spends coinbase.
bool spendsCoinbase = (i == 0) ? true : false;
// If we don't set the # of sig ops in the CTxMemPoolEntry, template
// creation fails.
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE)
.Time(GetTime())
.SpendsCoinbase(spendsCoinbase)
.FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
}
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 1001; ++i) {
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
// Only first tx spends coinbase.
bool spendsCoinbase = (i == 0) ? true : false;
// If we do set the # of sig ops in the CTxMemPoolEntry, template
// creation passes.
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE)
.Time(GetTime())
.SpendsCoinbase(spendsCoinbase)
.SigOpsCost(80)
.FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
g_mempool.clear();
// block size > limit
tx.vin[0].scriptSig = CScript();
// 18 * (520char + DROP) + OP_1 = 9433 bytes
std::vector<uint8_t> vchData(520);
for (unsigned int i = 0; i < 18; ++i) {
tx.vin[0].scriptSig << vchData << OP_DROP;
}
tx.vin[0].scriptSig << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vout[0].nValue = BLOCKSUBSIDY;
for (unsigned int i = 0; i < 128; ++i) {
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
// Only first tx spends coinbase.
bool spendsCoinbase = (i == 0) ? true : false;
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE)
.Time(GetTime())
.SpendsCoinbase(spendsCoinbase)
.FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
g_mempool.clear();
// Orphan in mempool, template creation fails.
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
// Child with higher priority than parent.
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
tx.vin.resize(2);
tx.vin[1].scriptSig = CScript() << OP_1;
tx.vin[1].prevout = COutPoint(txFirst[0]->GetId(), 0);
// First txn output + fresh coinbase - new txn fee.
tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
g_mempool.clear();
// Coinbase in mempool, template creation fails.
tx.vin.resize(1);
tx.vin[0].prevout = COutPoint();
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
tx.vout[0].nValue = Amount::zero();
hash = tx.GetId();
// Give it a fee so it'll get mined.
g_mempool.addUnchecked(
hash,
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
// Invalid (pre-p2sh) txn in mempool, template creation fails.
std::array<int64_t, CBlockIndex::nMedianTimeSpan> times;
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Trick the MedianTimePast.
times[i] = chainActive.Tip()
->GetAncestor(chainActive.Tip()->nHeight - i)
->nTime;
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime =
P2SH_ACTIVATION_TIME;
}
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE;
script = CScript() << OP_0;
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout = COutPoint(hash, 0);
tx.vin[0].scriptSig = CScript()
<< std::vector<uint8_t>(script.begin(), script.end());
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Restore the MedianTimePast.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime =
times[i];
}
// Double spend txn pair in mempool, template creation fails.
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
tx.vout[0].scriptPubKey = CScript() << OP_1;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK_THROW(
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey),
std::runtime_error);
g_mempool.clear();
// Subsidy changing.
int nHeight = chainActive.Height();
// Create an actual 209999-long block chain (without valid blocks).
while (chainActive.Tip()->nHeight < 209999) {
CBlockIndex *prev = chainActive.Tip();
CBlockIndex *next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
chainActive.SetTip(next);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
// Extend to a 210000-long block chain.
while (chainActive.Tip()->nHeight < 210000) {
CBlockIndex *prev = chainActive.Tip();
CBlockIndex *next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
chainActive.SetTip(next);
}
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
// Delete the dummy blocks again.
while (chainActive.Tip()->nHeight > nHeight) {
CBlockIndex *del = chainActive.Tip();
chainActive.SetTip(del->pprev);
pcoinsTip->SetBestBlock(del->pprev->GetBlockHash());
delete del->phashBlock;
delete del;
}
// non-final txs in mempool
SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);
uint32_t flags = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST;
// height map
std::vector<int> prevheights;
// Relative height locked.
tx.nVersion = 2;
tx.vin.resize(1);
prevheights.resize(1);
// Only 1 transaction.
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vin[0].scriptSig = CScript() << OP_1;
// txFirst[0] is the 2nd block
tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1;
prevheights[0] = baseheight + 1;
tx.vout.resize(1);
tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE;
tx.vout[0].scriptPubKey = CScript() << OP_1;
tx.nLockTime = 0;
hash = tx.GetId();
g_mempool.addUnchecked(
hash,
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
{
// Locktime passes.
CValidationState state;
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
}
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
// Sequence locks pass on 2nd block.
BOOST_CHECK(
SequenceLocks(CTransaction(tx), flags, &prevheights,
CreateBlockIndex(chainActive.Tip()->nHeight + 2)));
// Relative time locked.
tx.vin[0].prevout = COutPoint(txFirst[1]->GetId(), 0);
// txFirst[1] is the 3rd block.
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG |
(((chainActive.Tip()->GetMedianTimePast() + 1 -
chainActive[1]->GetMedianTimePast()) >>
CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) +
1);
prevheights[0] = baseheight + 2;
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
{
// Locktime passes.
CValidationState state;
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
}
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Trick the MedianTimePast.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime +=
512;
}
// Sequence locks pass 512 seconds later.
BOOST_CHECK(
SequenceLocks(CTransaction(tx), flags, &prevheights,
CreateBlockIndex(chainActive.Tip()->nHeight + 1)));
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Undo tricked MTP.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -=
512;
}
// Absolute height locked.
tx.vin[0].prevout = COutPoint(txFirst[2]->GetId(), 0);
tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1;
prevheights[0] = baseheight + 3;
tx.nLockTime = chainActive.Tip()->nHeight + 1;
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
{
// Locktime fails.
CValidationState state;
BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
}
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
{
// Locktime passes on 2nd block.
CValidationState state;
int64_t nMedianTimePast = chainActive.Tip()->GetMedianTimePast();
BOOST_CHECK(ContextualCheckTransaction(
config, CTransaction(tx), state, chainActive.Tip()->nHeight + 2,
nMedianTimePast, nMedianTimePast));
}
// Absolute time locked.
tx.vin[0].prevout = COutPoint(txFirst[3]->GetId(), 0);
tx.nLockTime = chainActive.Tip()->GetMedianTimePast();
prevheights.resize(1);
prevheights[0] = baseheight + 4;
hash = tx.GetId();
g_mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
{
// Locktime fails.
CValidationState state;
BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal");
}
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
{
// Locktime passes 1 second later.
CValidationState state;
int64_t nMedianTimePast = chainActive.Tip()->GetMedianTimePast() + 1;
BOOST_CHECK(ContextualCheckTransaction(
config, CTransaction(tx), state, chainActive.Tip()->nHeight + 1,
nMedianTimePast, nMedianTimePast));
}
// mempool-dependent transactions (not added)
tx.vin[0].prevout = COutPoint(hash, 0);
prevheights[0] = chainActive.Tip()->nHeight + 1;
tx.nLockTime = 0;
tx.vin[0].nSequence = 0;
{
// Locktime passes.
CValidationState state;
BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(
config, CTransaction(tx), state, flags));
}
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
tx.vin[0].nSequence = 1;
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;
// Sequence locks pass.
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags));
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
// Sequence locks fail.
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags));
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate);
// None of the of the absolute height/time locked tx should have made it
// into the template because we still check IsFinalTx in CreateNewBlock, but
// relative locked txs will if inconsistently added to g_mempool. For now
// these will still generate a valid template until BIP68 soft fork.
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3UL);
// However if we advance height by 1 and time by 512, all of them should be
// mined.
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) {
// Trick the MedianTimePast.
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime +=
512;
}
chainActive.Tip()->nHeight++;
SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);
BOOST_CHECK(
pblocktemplate =
BlockAssembler(config, g_mempool).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL);
chainActive.Tip()->nHeight--;
SetMockTime(0);
g_mempool.clear();
TestPackageSelection(config, scriptPubKey, txFirst);
fCheckpointsEnabled = true;
}
void CheckBlockMaxSize(const Config &config, uint64_t size, uint64_t expected) {
gArgs.ForceSetArg("-blockmaxsize", std::to_string(size));
BlockAssembler ba(config, g_mempool);
BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected);
}
BOOST_AUTO_TEST_CASE(BlockAssembler_construction) {
GlobalConfig config;
// We are working on a fake chain and need to protect ourselves.
LOCK(cs_main);
// Test around historical 1MB (plus one byte because that's mandatory)
config.SetMaxBlockSize(ONE_MEGABYTE + 1);
CheckBlockMaxSize(config, 0, 1000);
CheckBlockMaxSize(config, 1000, 1000);
CheckBlockMaxSize(config, 1001, 1001);
CheckBlockMaxSize(config, 12345, 12345);
CheckBlockMaxSize(config, ONE_MEGABYTE - 1001, ONE_MEGABYTE - 1001);
CheckBlockMaxSize(config, ONE_MEGABYTE - 1000, ONE_MEGABYTE - 1000);
CheckBlockMaxSize(config, ONE_MEGABYTE - 999, ONE_MEGABYTE - 999);
CheckBlockMaxSize(config, ONE_MEGABYTE, ONE_MEGABYTE - 999);
// Test around default cap
config.SetMaxBlockSize(DEFAULT_MAX_BLOCK_SIZE);
// Now we can use the default max block size.
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE - 1001,
DEFAULT_MAX_BLOCK_SIZE - 1001);
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE - 1000,
DEFAULT_MAX_BLOCK_SIZE - 1000);
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE - 999,
DEFAULT_MAX_BLOCK_SIZE - 1000);
CheckBlockMaxSize(config, DEFAULT_MAX_BLOCK_SIZE,
DEFAULT_MAX_BLOCK_SIZE - 1000);
// If the parameter is not specified, we use
// DEFAULT_MAX_GENERATED_BLOCK_SIZE
{
gArgs.ClearArg("-blockmaxsize");
BlockAssembler ba(config, g_mempool);
BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(),
DEFAULT_MAX_GENERATED_BLOCK_SIZE);
}
}
BOOST_AUTO_TEST_SUITE_END()

File Metadata

Mime Type
text/x-c
Expires
Mon, Nov 17, 01:09 (8 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
6990175
Default Alt Text
miner_tests.cpp (30 KB)

Event Timeline