Repository: bitcoin/bitcoin
File: src/node/interfaces.cpp (C++)

Code before:
    }

    std::optional<uint256> getTipHash() override
    {
        LOCK(::cs_main);
        CBlockIndex* tip{chainman().ActiveChain().Tip()};
        if (!tip) return {};
        return tip->GetBlockHash();
    }

    bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override
    {
        return chainman().ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/new_block);
    }

    unsigned int getTransactionsUpdated() override
    {
        return context()->mempool->GetTransactionsUpdated();
    }

    bool testBlockValidity(BlockValidationState& state, const CBlock& block, bool check_merkle_root) override
    {
        LOCK(::cs_main);
        return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, chainman().ActiveChain().Tip(), /*fCheckPOW=*/false, check_merkle_root);
    }

    std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool) override
    {
        BlockAssembler::Options options;
        ApplyArgsManOptions(gArgs, options);

        LOCK(::cs_main);
        return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key);
    }

    NodeContext* context() override { return &m_node; }
    ChainstateManager& chainman() { return *Assert(m_node.chainman); }
    NodeContext& m_node;
};
} // namespace
} // namespace node

namespace interfaces {
std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
std::unique_ptr<Chain> MakeChain(node::NodeContext& context) { return std::make_unique<node::ChainImpl>(context); }
std::unique_ptr<Mining> MakeMining(node::NodeContext& context) { return std::make_unique<node::MinerImpl>(context); }
} // namespace interfaces


Review comment (bug):
nit: In the RPC error you'll give `state.ToString()` as the failure reason, but if this tip check fails that'll be the default `BLOCK_RESULT_UNSET`.

better suggestion https://github.com/bitcoin/bitcoin/pull/30335#discussion_r1654864264 ~~Seems correct to fail if the tip has updated to avoid building a fork on an older block, but I can't see a `BlockValidationResult` that would make sense here other than maybe stretching the meaning of `BLOCK_INVALID_HEADER` -- perhaps you could add another that only makes sense in a templating context like `BLOCK_NOT_TIP` (or wrap `BlockValidationState` in something like `BlockTemplateValidationState` allowing for other template-specific reults but that might be too messy?)~~

Code after:
    }

    std::optional<uint256> getTipHash() override
    {
        LOCK(::cs_main);
        CBlockIndex* tip{chainman().ActiveChain().Tip()};
        if (!tip) return {};
        return tip->GetBlockHash();
    }

    bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override
    {
        return chainman().ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/new_block);
    }

    unsigned int getTransactionsUpdated() override
    {
        return context()->mempool->GetTransactionsUpdated();
    }

    bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override
    {
        LOCK(cs_main);
        CBlockIndex* tip{chainman().ActiveChain().Tip()};
        // Fail if the tip updated before the lock was taken
        if (block.hashPrevBlock != tip->GetBlockHash()) {
            state.Error("Block does not connect to current chain tip.");
            return false;
        }

        return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
    }

    std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool) override
    {
        BlockAssembler::Options options;
        ApplyArgsManOptions(gArgs, options);

        return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key);
    }

    NodeContext* context() override { return &m_node; }
    ChainstateManager& chainman() { return *Assert(m_node.chainman); }
    NodeContext& m_node;
};
} // namespace
} // namespace node

namespace interfaces {
std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
std::unique_ptr<Chain> MakeChain(node::NodeContext& context) { return std::make_unique<node::ChainImpl>(context); }