Changeset View
Changeset View
Standalone View
Standalone View
src/test/miner_tests.cpp
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup) | BOOST_FIXTURE_TEST_SUITE(miner_tests, MinerTestingSetup) | ||||
static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); | static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); | ||||
BlockAssembler MinerTestingSetup::AssemblerForTest(const CChainParams ¶ms) { | BlockAssembler MinerTestingSetup::AssemblerForTest(const CChainParams ¶ms) { | ||||
BlockAssembler::Options options; | BlockAssembler::Options options; | ||||
options.blockMinFeeRate = blockMinFeeRate; | options.blockMinFeeRate = blockMinFeeRate; | ||||
return BlockAssembler(params, *m_node.mempool, options); | return BlockAssembler(::ChainstateActive(), params, *m_node.mempool, | ||||
options); | |||||
} | } | ||||
constexpr static struct { | constexpr static struct { | ||||
uint8_t extranonce; | uint8_t extranonce; | ||||
uint32_t nonce; | uint32_t nonce; | ||||
} blockinfo[] = { | } blockinfo[] = { | ||||
{4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5}, | {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5}, | ||||
{2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84}, | {2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84}, | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | void MinerTestingSetup::TestPackageSelection( | ||||
tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI; | tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI; | ||||
TxId highFeeTxId = tx.GetId(); | TxId highFeeTxId = tx.GetId(); | ||||
m_node.mempool->addUnchecked(entry.Fee(50000 * SATOSHI) | m_node.mempool->addUnchecked(entry.Fee(50000 * SATOSHI) | ||||
.Time(GetTime()) | .Time(GetTime()) | ||||
.SpendsCoinbase(false) | .SpendsCoinbase(false) | ||||
.FromTx(tx)); | .FromTx(tx)); | ||||
std::unique_ptr<CBlockTemplate> pblocktemplate = | std::unique_ptr<CBlockTemplate> pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey); | |||||
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == parentTxId); | BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == parentTxId); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == highFeeTxId); | BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == highFeeTxId); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == mediumFeeTxId); | BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == mediumFeeTxId); | ||||
// 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 = COutPoint(highFeeTxId, 0); | tx.vin[0].prevout = COutPoint(highFeeTxId, 0); | ||||
// 0 fee. | // 0 fee. | ||||
tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI; | tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI; | ||||
TxId freeTxId = tx.GetId(); | TxId freeTxId = tx.GetId(); | ||||
m_node.mempool->addUnchecked(entry.Fee(Amount::zero()).FromTx(tx)); | m_node.mempool->addUnchecked(entry.Fee(Amount::zero()).FromTx(tx)); | ||||
size_t freeTxSize = GetSerializeSize(tx, PROTOCOL_VERSION); | size_t freeTxSize = GetSerializeSize(tx, 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). | ||||
Amount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize) - SATOSHI; | Amount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize) - SATOSHI; | ||||
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(); | ||||
m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx)); | m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx)); | ||||
pblocktemplate = AssemblerForTest(chainparams) | pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); | ||||
.CreateNewBlock(::ChainstateActive(), 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 (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 | ||||
m_node.mempool->removeRecursive(CTransaction(tx), | m_node.mempool->removeRecursive(CTransaction(tx), | ||||
MemPoolRemovalReason::REPLACED); | MemPoolRemovalReason::REPLACED); | ||||
// 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 * SATOSHI; | tx.vout[0].nValue -= 2 * SATOSHI; | ||||
lowFeeTxId = tx.GetId(); | lowFeeTxId = tx.GetId(); | ||||
m_node.mempool->addUnchecked(entry.Fee(feeToUse + 2 * SATOSHI).FromTx(tx)); | m_node.mempool->addUnchecked(entry.Fee(feeToUse + 2 * SATOSHI).FromTx(tx)); | ||||
pblocktemplate = AssemblerForTest(chainparams) | pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey); | |||||
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == freeTxId); | BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == freeTxId); | ||||
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == lowFeeTxId); | BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == lowFeeTxId); | ||||
// 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 = COutPoint(txFirst[2]->GetId(), 0); | tx.vin[0].prevout = COutPoint(txFirst[2]->GetId(), 0); | ||||
tx.vout.resize(2); | tx.vout.resize(2); | ||||
tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI; | tx.vout[0].nValue = int64_t(5000000000LL - 100000000) * SATOSHI; | ||||
// 1BCC output. | // 1BCC output. | ||||
tx.vout[1].nValue = 100000000 * SATOSHI; | tx.vout[1].nValue = 100000000 * SATOSHI; | ||||
TxId freeTxId2 = tx.GetId(); | TxId freeTxId2 = tx.GetId(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
entry.Fee(Amount::zero()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(Amount::zero()).SpendsCoinbase(true).FromTx(tx)); | ||||
// This tx can't be mined by itself. | // This tx can't be mined by itself. | ||||
tx.vin[0].prevout = COutPoint(freeTxId2, 0); | tx.vin[0].prevout = COutPoint(freeTxId2, 0); | ||||
tx.vout.resize(1); | tx.vout.resize(1); | ||||
feeToUse = blockMinFeeRate.GetFee(freeTxSize); | feeToUse = blockMinFeeRate.GetFee(freeTxSize); | ||||
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(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); | entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); | ||||
pblocktemplate = AssemblerForTest(chainparams) | pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey); | |||||
// Verify that this tx isn't selected. | // Verify that this tx isn't selected. | ||||
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); | ||||
// 10k satoshi fee. | // 10k satoshi fee. | ||||
tx.vout[0].nValue = (100000000 - 10000) * SATOSHI; | tx.vout[0].nValue = (100000000 - 10000) * SATOSHI; | ||||
m_node.mempool->addUnchecked(entry.Fee(10000 * SATOSHI).FromTx(tx)); | m_node.mempool->addUnchecked(entry.Fee(10000 * SATOSHI).FromTx(tx)); | ||||
pblocktemplate = AssemblerForTest(chainparams) | pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey); | |||||
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == lowFeeTxId2); | BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == lowFeeTxId2); | ||||
} | } | ||||
void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg, | void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg, | ||||
const CTxMemPool &mempool) { | const CTxMemPool &mempool) { | ||||
GlobalConfig config; | GlobalConfig config; | ||||
config.SetMaxBlockSize(eb); | config.SetMaxBlockSize(eb); | ||||
CScript scriptPubKey = | CScript scriptPubKey = | ||||
CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" | ||||
"a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112" | "a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112" | ||||
"de5c384df7ba0b8d578a4c702b6bf11d5f") | "de5c384df7ba0b8d578a4c702b6bf11d5f") | ||||
<< OP_CHECKSIG; | << OP_CHECKSIG; | ||||
std::unique_ptr<CBlockTemplate> pblocktemplate = | std::unique_ptr<CBlockTemplate> pblocktemplate = | ||||
BlockAssembler(config, mempool) | BlockAssembler(config, ::ChainstateActive(), mempool) | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey); | .CreateNewBlock(scriptPubKey); | ||||
CBlock *pblock = &pblocktemplate->block; | CBlock *pblock = &pblocktemplate->block; | ||||
// IncrementExtraNonce creates a valid coinbase and merkleRoot | // IncrementExtraNonce creates a valid coinbase and merkleRoot | ||||
unsigned int extraNonce = 0; | unsigned int extraNonce = 0; | ||||
IncrementExtraNonce(pblock, ::ChainActive().Tip(), config.GetMaxBlockSize(), | IncrementExtraNonce(pblock, ::ChainActive().Tip(), config.GetMaxBlockSize(), | ||||
extraNonce); | extraNonce); | ||||
unsigned int nHeight = ::ChainActive().Tip()->nHeight + 1; | unsigned int nHeight = ::ChainActive().Tip()->nHeight + 1; | ||||
Show All 27 Lines | BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { | ||||
TestMemPoolEntryHelper entry; | TestMemPoolEntryHelper entry; | ||||
entry.nFee = 11 * SATOSHI; | entry.nFee = 11 * SATOSHI; | ||||
entry.nHeight = 11; | entry.nHeight = 11; | ||||
fCheckpointsEnabled = false; | fCheckpointsEnabled = false; | ||||
// Simple block creation, nothing special yet: | // Simple block creation, nothing special yet: | ||||
BOOST_CHECK(pblocktemplate = | BOOST_CHECK(pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey)); | |||||
// We can't make transactions until we have inputs. | // We can't make transactions until we have inputs. | ||||
// Therefore, load 110 blocks :) | // Therefore, load 110 blocks :) | ||||
static_assert(std::size(blockinfo) == 110, | static_assert(std::size(blockinfo) == 110, | ||||
"Should have 110 blocks to import"); | "Should have 110 blocks to import"); | ||||
int baseheight = 0; | int baseheight = 0; | ||||
std::vector<CTransactionRef> txFirst; | std::vector<CTransactionRef> txFirst; | ||||
for (const auto &bi : blockinfo) { | for (const auto &bi : blockinfo) { | ||||
Show All 28 Lines | for (const auto &bi : blockinfo) { | ||||
pblock->hashPrevBlock = pblock->GetHash(); | pblock->hashPrevBlock = pblock->GetHash(); | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
LOCK(m_node.mempool->cs); | LOCK(m_node.mempool->cs); | ||||
// Just to make sure we can still make simple blocks. | // Just to make sure we can still make simple blocks. | ||||
BOOST_CHECK(pblocktemplate = | BOOST_CHECK(pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey)); | |||||
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 size > limit | // block size > limit | ||||
tx.vin.resize(1); | tx.vin.resize(1); | ||||
Show All 16 Lines | for (unsigned int i = 0; i < 128; ++i) { | ||||
m_node.mempool->addUnchecked(entry.Fee(LOWFEE) | m_node.mempool->addUnchecked(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(pblocktemplate = | BOOST_CHECK(pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey)); | |||||
m_node.mempool->clear(); | m_node.mempool->clear(); | ||||
// Orphan in mempool, template creation fails. | // Orphan in mempool, template creation fails. | ||||
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); | m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); | ||||
BOOST_CHECK_EXCEPTION( | BOOST_CHECK_EXCEPTION( | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey), | |||||
std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); | std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); | ||||
m_node.mempool->clear(); | m_node.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 txid = tx.GetId(); | TxId txid = tx.GetId(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
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(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
BOOST_CHECK(pblocktemplate = | BOOST_CHECK(pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey)); | |||||
m_node.mempool->clear(); | m_node.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. | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | ||||
// Should throw bad-tx-coinbase | // Should throw bad-tx-coinbase | ||||
BOOST_CHECK_EXCEPTION( | BOOST_CHECK_EXCEPTION( | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey), | |||||
std::runtime_error, HasReason("bad-tx-coinbase")); | std::runtime_error, HasReason("bad-tx-coinbase")); | ||||
m_node.mempool->clear(); | m_node.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(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
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(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
BOOST_CHECK_EXCEPTION( | BOOST_CHECK_EXCEPTION( | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey), | |||||
std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); | std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); | ||||
m_node.mempool->clear(); | m_node.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(); | ||||
next->phashBlock = new BlockHash(InsecureRand256()); | next->phashBlock = new BlockHash(InsecureRand256()); | ||||
::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash()); | ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash()); | ||||
next->pprev = prev; | next->pprev = prev; | ||||
next->nHeight = prev->nHeight + 1; | next->nHeight = prev->nHeight + 1; | ||||
next->BuildSkip(); | next->BuildSkip(); | ||||
::ChainActive().SetTip(next); | ::ChainActive().SetTip(next); | ||||
} | } | ||||
BOOST_CHECK(pblocktemplate = | BOOST_CHECK(pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey)); | |||||
// Extend to a 210000-long block chain. | // Extend to a 210000-long block chain. | ||||
while (::ChainActive().Tip()->nHeight < 210000) { | while (::ChainActive().Tip()->nHeight < 210000) { | ||||
CBlockIndex *prev = ::ChainActive().Tip(); | CBlockIndex *prev = ::ChainActive().Tip(); | ||||
CBlockIndex *next = new CBlockIndex(); | CBlockIndex *next = new CBlockIndex(); | ||||
next->phashBlock = new BlockHash(InsecureRand256()); | next->phashBlock = new BlockHash(InsecureRand256()); | ||||
::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash()); | ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash()); | ||||
next->pprev = prev; | next->pprev = prev; | ||||
next->nHeight = prev->nHeight + 1; | next->nHeight = prev->nHeight + 1; | ||||
next->BuildSkip(); | next->BuildSkip(); | ||||
::ChainActive().SetTip(next); | ::ChainActive().SetTip(next); | ||||
} | } | ||||
BOOST_CHECK(pblocktemplate = | BOOST_CHECK(pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey)); | |||||
// Invalid p2sh txn in mempool, template creation fails | // Invalid p2sh txn 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 - LOWFEE; | tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE; | ||||
script = CScript() << OP_0; | script = CScript() << OP_0; | ||||
tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); | tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); | ||||
txid = tx.GetId(); | txid = tx.GetId(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); | ||||
tx.vin[0].prevout = COutPoint(txid, 0); | tx.vin[0].prevout = COutPoint(txid, 0); | ||||
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(); | ||||
m_node.mempool->addUnchecked( | m_node.mempool->addUnchecked( | ||||
entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); | ||||
// Should throw blk-bad-inputs | // Should throw blk-bad-inputs | ||||
BOOST_CHECK_EXCEPTION( | BOOST_CHECK_EXCEPTION( | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey), | |||||
std::runtime_error, HasReason("blk-bad-inputs")); | std::runtime_error, HasReason("blk-bad-inputs")); | ||||
m_node.mempool->clear(); | m_node.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); | ||||
::ChainstateActive().CoinsTip().SetBestBlock( | ::ChainstateActive().CoinsTip().SetBestBlock( | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { | ||||
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); | BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); | ||||
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; | tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; | ||||
// Sequence locks pass. | // Sequence locks pass. | ||||
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); | BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); | ||||
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; | tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; | ||||
// Sequence locks fail. | // Sequence locks fail. | ||||
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); | BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); | ||||
pblocktemplate = AssemblerForTest(chainparams) | pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey); | |||||
BOOST_CHECK(pblocktemplate); | BOOST_CHECK(pblocktemplate); | ||||
// None of the of the absolute height/time locked tx should have made it | // 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 | // into the template because we still check IsFinalTx in CreateNewBlock, but | ||||
// relative locked txs will if inconsistently added to g_mempool. For now | // relative locked txs will if inconsistently added to g_mempool. For now | ||||
// these will still generate a valid template until BIP68 soft fork. | // these will still generate a valid template until BIP68 soft fork. | ||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3UL); | BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3UL); | ||||
// However if we advance height by 1 and time by 512, all of them should be | // However if we advance height by 1 and time by 512, all of them should be | ||||
// mined. | // mined. | ||||
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { | for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { | ||||
// Trick the MedianTimePast. | // Trick the MedianTimePast. | ||||
::ChainActive() | ::ChainActive() | ||||
.Tip() | .Tip() | ||||
->GetAncestor(::ChainActive().Tip()->nHeight - i) | ->GetAncestor(::ChainActive().Tip()->nHeight - i) | ||||
->nTime += 512; | ->nTime += 512; | ||||
} | } | ||||
::ChainActive().Tip()->nHeight++; | ::ChainActive().Tip()->nHeight++; | ||||
SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1); | SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1); | ||||
BOOST_CHECK(pblocktemplate = | BOOST_CHECK(pblocktemplate = | ||||
AssemblerForTest(chainparams) | AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); | ||||
.CreateNewBlock(::ChainstateActive(), scriptPubKey)); | |||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL); | BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL); | ||||
::ChainActive().Tip()->nHeight--; | ::ChainActive().Tip()->nHeight--; | ||||
SetMockTime(0); | SetMockTime(0); | ||||
m_node.mempool->clear(); | m_node.mempool->clear(); | ||||
TestPackageSelection(chainparams, scriptPubKey, txFirst); | TestPackageSelection(chainparams, scriptPubKey, txFirst); | ||||
fCheckpointsEnabled = true; | fCheckpointsEnabled = true; | ||||
} | } | ||||
void CheckBlockMaxSize(const Config &config, const CTxMemPool &mempool, | void CheckBlockMaxSize(const Config &config, const CTxMemPool &mempool, | ||||
uint64_t size, uint64_t expected) { | uint64_t size, uint64_t expected) { | ||||
gArgs.ForceSetArg("-blockmaxsize", ToString(size)); | gArgs.ForceSetArg("-blockmaxsize", ToString(size)); | ||||
BlockAssembler ba(config, mempool); | BlockAssembler ba(config, ::ChainstateActive(), mempool); | ||||
BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected); | BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(BlockAssembler_construction) { | BOOST_AUTO_TEST_CASE(BlockAssembler_construction) { | ||||
GlobalConfig config; | GlobalConfig config; | ||||
// We are working on a fake chain and need to protect ourselves. | // We are working on a fake chain and need to protect ourselves. | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Show All 26 Lines | CheckBlockMaxSize(config, *m_node.mempool, DEFAULT_MAX_BLOCK_SIZE - 999, | ||||
DEFAULT_MAX_BLOCK_SIZE - 1000); | DEFAULT_MAX_BLOCK_SIZE - 1000); | ||||
CheckBlockMaxSize(config, *m_node.mempool, DEFAULT_MAX_BLOCK_SIZE, | CheckBlockMaxSize(config, *m_node.mempool, DEFAULT_MAX_BLOCK_SIZE, | ||||
DEFAULT_MAX_BLOCK_SIZE - 1000); | DEFAULT_MAX_BLOCK_SIZE - 1000); | ||||
// If the parameter is not specified, we use | // If the parameter is not specified, we use | ||||
// DEFAULT_MAX_GENERATED_BLOCK_SIZE | // DEFAULT_MAX_GENERATED_BLOCK_SIZE | ||||
{ | { | ||||
gArgs.ClearForcedArg("-blockmaxsize"); | gArgs.ClearForcedArg("-blockmaxsize"); | ||||
BlockAssembler ba(config, *m_node.mempool); | BlockAssembler ba(config, ::ChainstateActive(), *m_node.mempool); | ||||
BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), | BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), | ||||
DEFAULT_MAX_GENERATED_BLOCK_SIZE); | DEFAULT_MAX_GENERATED_BLOCK_SIZE); | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(TestCBlockTemplateEntry) { | BOOST_AUTO_TEST_CASE(TestCBlockTemplateEntry) { | ||||
const CTransaction tx; | const CTransaction tx; | ||||
CTransactionRef txRef = MakeTransactionRef(tx); | CTransactionRef txRef = MakeTransactionRef(tx); | ||||
CBlockTemplateEntry txEntry(txRef, 1 * SATOSHI, 10); | CBlockTemplateEntry txEntry(txRef, 1 * SATOSHI, 10); | ||||
BOOST_CHECK_MESSAGE(txEntry.tx == txRef, "Transactions did not match"); | BOOST_CHECK_MESSAGE(txEntry.tx == txRef, "Transactions did not match"); | ||||
BOOST_CHECK_EQUAL(txEntry.fees, 1 * SATOSHI); | BOOST_CHECK_EQUAL(txEntry.fees, 1 * SATOSHI); | ||||
BOOST_CHECK_EQUAL(txEntry.sigOpCount, 10); | BOOST_CHECK_EQUAL(txEntry.sigOpCount, 10); | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |