diff --git a/src/policy/block/minerfund.cpp b/src/policy/block/minerfund.cpp index 67b864a05..916b412f4 100644 --- a/src/policy/block/minerfund.cpp +++ b/src/policy/block/minerfund.cpp @@ -1,21 +1,27 @@ // Copyright (c) 2023 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include -bool MinerFundPolicy::operator()() { +bool MinerFundPolicy::operator()(BlockPolicyValidationState &state) { if (!m_blockIndex.pprev || !IsWellingtonEnabled(m_consensusParams, m_blockIndex.pprev)) { // Do not apply the miner fund policy before Wellington activates. return true; } assert(m_block.vtx.size()); - return CheckMinerFund(m_consensusParams, m_blockIndex.pprev, - m_block.vtx[0]->vout, m_blockReward); + if (!CheckMinerFund(m_consensusParams, m_blockIndex.pprev, + m_block.vtx[0]->vout, m_blockReward)) { + return state.Invalid(BlockPolicyValidationResult::POLICY_VIOLATION, + "policy-bad-miner-fund", + strprintf("Block %s violates miner fund policy", + m_blockIndex.GetBlockHash().ToString())); + } + return true; } diff --git a/src/policy/block/minerfund.h b/src/policy/block/minerfund.h index 8b9579ae6..af95c61a9 100644 --- a/src/policy/block/minerfund.h +++ b/src/policy/block/minerfund.h @@ -1,35 +1,35 @@ // Copyright (c) 2023 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_POLICY_BLOCK_MINERFUND_H #define BITCOIN_POLICY_BLOCK_MINERFUND_H #include #include #include class CBlockIndex; namespace Consensus { struct Params; } class MinerFundPolicy : public ParkingPolicy { private: const CBlock &m_block; const Amount &m_blockReward; const Consensus::Params &m_consensusParams; const CBlockIndex &m_blockIndex; public: MinerFundPolicy(const Consensus::Params &consensusParams, const CBlockIndex &blockIndex, const CBlock &block, const Amount &blockReward) : m_block(block), m_blockReward(blockReward), m_consensusParams(consensusParams), m_blockIndex(blockIndex) {} - bool operator()() override; + bool operator()(BlockPolicyValidationState &state) override; }; #endif // BITCOIN_POLICY_BLOCK_MINERFUND_H diff --git a/src/policy/block/parkingpolicy.h b/src/policy/block/parkingpolicy.h index be7fe5b3a..e69e8d67d 100644 --- a/src/policy/block/parkingpolicy.h +++ b/src/policy/block/parkingpolicy.h @@ -1,15 +1,30 @@ // Copyright (c) 2023 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_POLICY_BLOCK_PARKINGPOLICY_H #define BITCOIN_POLICY_BLOCK_PARKINGPOLICY_H +#include + +/** + * A "reason" why a block did not pass block policy checks. + */ +enum class BlockPolicyValidationResult { + //! Initial value. Policy rule has not yet been violated. + POLICY_RESULT_UNSET = 0, + //! A block policy rule was violated. This block should be parked. + POLICY_VIOLATION, +}; + +class BlockPolicyValidationState + : public ValidationState {}; + struct ParkingPolicy { virtual ~ParkingPolicy() {} // Return true if a policy succeeds. False will park the block. - virtual bool operator()() = 0; + virtual bool operator()(BlockPolicyValidationState &state) = 0; }; #endif // BITCOIN_POLICY_BLOCK_PARKINGPOLICY_H diff --git a/src/test/policy_block_tests.cpp b/src/test/policy_block_tests.cpp index feecc8a31..ba9ed306e 100644 --- a/src/test/policy_block_tests.cpp +++ b/src/test/policy_block_tests.cpp @@ -1,124 +1,135 @@ // Copyright (c) 2023 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include BOOST_FIXTURE_TEST_SUITE(policy_block_tests, BasicTestingSetup) static CBlock Block(const Amount &amount, const CScript &script) { CBlock block; CMutableTransaction coinbaseTx; coinbaseTx.vout.resize(1); coinbaseTx.vout[0].nValue = amount; coinbaseTx.vout[0].scriptPubKey = script; block.vtx.push_back(MakeTransactionRef(std::move(coinbaseTx))); return block; } static CBlock BlockWithoutMinerFund(const Amount &amount) { return Block(amount, CScript() << OP_TRUE); } static CBlock BlockWithMinerFund(const CChainParams &chainparams, const Amount &minerFundAmount) { const auto minerFund = DecodeDestination( "ecash:prfhcnyqnl5cgrnmlfmms675w93ld7mvvqd0y8lz07", chainparams); return Block(minerFundAmount, GetScriptForDestination(minerFund)); } BOOST_AUTO_TEST_CASE(policy_minerfund) { const CChainParams &chainparams = Params(); const Consensus::Params &consensusParams = chainparams.GetConsensus(); + std::array blockhashes; std::array blocks; for (size_t i = 1; i < blocks.size(); ++i) { + blockhashes[i] = BlockHash(uint256(i)); + blocks[i].phashBlock = &blockhashes[i]; blocks[i].pprev = &blocks[i - 1]; blocks[i].nHeight = consensusParams.gluonHeight + i; } CBlockIndex &lastBlockIndexRef = blocks.back(); const Amount blockReward = GetBlockSubsidy(lastBlockIndexRef.nHeight, consensusParams); const Amount minerFund = GetMinerFundAmount(blockReward); const auto wellingtonActivation = gArgs.GetIntArg( "-wellingtonactivationtime", consensusParams.wellingtonActivationTime); auto checkEarlyBlocks = [&]() { // Check genesis block (pprev is nullptr) and early blocks before // Wellington rules are enforced. We skip the last block index // because we explicitly test activation cases with it. BOOST_CHECK(!blocks[0].pprev); for (size_t i = 0; i < blocks.size() - 2; i++) { const CBlockIndex &blockIndex = blocks[i]; BOOST_CHECK( !IsWellingtonEnabled(consensusParams, blockIndex.pprev)); CBlock block = BlockWithoutMinerFund(blockReward); MinerFundPolicy check(consensusParams, blockIndex, block, blockReward); - BOOST_CHECK(check()); + + BlockPolicyValidationState state; + BOOST_CHECK(check(state)); + BOOST_CHECK(state.IsValid()); } }; auto checkMinerFundPolicy = [&](CBlock block, bool expected) { + BlockPolicyValidationState state; BOOST_CHECK_EQUAL(MinerFundPolicy(consensusParams, lastBlockIndexRef, - block, blockReward)(), + block, blockReward)(state), expected); + BOOST_CHECK_EQUAL(state.IsValid(), expected); + if (!expected) { + BOOST_CHECK_EQUAL(state.GetRejectReason(), "policy-bad-miner-fund"); + } }; const std::vector minerFundsTooSmall = {1 * SATOSHI, minerFund / 2, minerFund - 1 * SATOSHI}; const std::vector minerFundsSufficient = { minerFund, minerFund + 1 * SATOSHI, blockReward}; // Miner fund policy always passes prior to Wellington rules enforcement. // Note that Wellington rules are enforced on the block after activation. for (auto activation : {wellingtonActivation - 1, wellingtonActivation}) { SetMTP(blocks, activation); BOOST_CHECK_EQUAL( IsWellingtonEnabled(consensusParams, &lastBlockIndexRef), activation == wellingtonActivation); checkEarlyBlocks(); checkMinerFundPolicy(BlockWithoutMinerFund(blockReward), true); // Blocks with miner fund of various amounts for (const Amount &amount : Cat(minerFundsTooSmall, minerFundsSufficient)) { checkMinerFundPolicy(BlockWithMinerFund(chainparams, amount), true); } } // Wellington rules are now enforced. Miner fund checks are now applied. SetMTP(blocks, wellingtonActivation + 1); BOOST_CHECK(IsWellingtonEnabled(consensusParams, &lastBlockIndexRef)); checkEarlyBlocks(); checkMinerFundPolicy(BlockWithoutMinerFund(blockReward), false); // Blocks with not enough miner fund for (const Amount &amount : minerFundsTooSmall) { checkMinerFundPolicy(BlockWithMinerFund(chainparams, amount), false); } // Blocks with sufficient miner fund for (const Amount &amount : minerFundsSufficient) { checkMinerFundPolicy(BlockWithMinerFund(chainparams, amount), true); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/validation.cpp b/src/validation.cpp index 207042fff..1e997c051 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,6229 +1,6238 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2018 The Bitcoin Core developers // Copyright (c) 2017-2020 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include