Removing the target, subsidy or padding line here leaves blockfilter_index_tests and baseindex_tests green, so nothing on that side covers what the branch changes. The new assertions in MinerTestingSetup::Block catch the subsidy and the padding, and the target has nothing anywhere.
These two cover all four fields, if they are worth having. The target one calls the helper directly, which is the only way in, since on regtest the recalculated target always equals the template's and no chain can tell the line apart. The coinbase one passes here and fails on master, first on the script length and then at the halving block. Both compile in blockfilter_index_tests.cpp.
BOOST_FIXTURE_TEST_CASE(rebuild_block_for_parent_target, RegTestingSetup)
{
const auto& consensus{Params().GetConsensus()};
const auto genesis{Params().GenesisBlock()};
const auto parent_hash{genesis.GetHash()};
CBlockIndex parent{genesis};
parent.phashBlock = &parent_hash;
--parent.nBits; // A valid target, different from the one the template carries.
// Regtest allows min-difficulty blocks, and parent has no pprev, so
// GetNextWorkRequired returns the parent's target below the threshold and the
// pow limit above it.
const auto threshold{uint32_t(2 * consensus.nPowTargetSpacing)};
for (const auto delay : {1U, threshold, threshold + 1}) {
CBlock block{genesis};
RebuildBlockForParent(block, parent, parent.nTime + delay, consensus);
BOOST_CHECK_EQUAL(block.nBits, delay > threshold ? genesis.nBits : parent.nBits);
}
}
BOOST_FIXTURE_TEST_CASE(rebuild_block_for_parent_coinbase, TestChain100Setup)
{
const auto& consensus{Params().GetConsensus()};
auto process = [&](const std::vector<std::shared_ptr<CBlock>>& chain) {
for (const auto& block : chain) {
BOOST_CHECK(m_node.chainman->ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr));
}
};
// A fork rooted below height 17 needs the dummy OP_0, since the BIP34
// height alone is one byte there (bad-cb-length).
{
const CBlockIndex* genesis{WITH_LOCK(cs_main, return m_node.chainman->ActiveChain().Genesis())};
std::vector<std::shared_ptr<CBlock>> fork;
BOOST_REQUIRE(BuildChain(m_node, genesis, CScript() << OP_TRUE, 3, fork));
BOOST_CHECK_EQUAL(fork.front()->vtx[0]->vin[0].scriptSig.size(), 2U);
process(fork);
}
// BuildChain only submits headers, so every template keeps being built on
// the active tip. A chain long enough to pass the halving would otherwise
// carry the tip's subsidy and fail to connect (bad-cb-amount).
{
const CBlockIndex* tip{WITH_LOCK(cs_main, return m_node.chainman->ActiveChain().Tip())};
const int start{tip->nHeight};
const int length{consensus.nSubsidyHalvingInterval + 10 - start};
BOOST_REQUIRE(length > 0);
std::vector<std::shared_ptr<CBlock>> chain;
BOOST_REQUIRE(BuildChain(m_node, tip, CScript() << OP_TRUE, length, chain));
for (int i = 0; i < length; ++i) {
BOOST_CHECK_EQUAL(chain.at(i)->vtx[0]->vout[0].nValue, GetBlockSubsidy(start + 1 + i, consensus));
}
process(chain);
BOOST_CHECK_EQUAL(WITH_LOCK(cs_main, return m_node.chainman->ActiveChain().Height()), start + length);
}
}