git / moonbite-core / src/consensus/validation.h · raw

// Copyright (c) 2009-2010 Satoshi Nakamoto// Copyright (c) 2009-2019 The Bitcoin Core developers// Distributed under the MIT software license, see the accompanying// file COPYING or http://www.opensource.org/licenses/mit-license.php.#ifndef BITCOIN_CONSENSUS_VALIDATION_H#define BITCOIN_CONSENSUS_VALIDATION_H#include <string>#include <version.h>#include <consensus/consensus.h>#include <primitives/transaction.h>#include <primitives/block.h>/** Index marker for when no witness commitment is present in a coinbase transaction. */static constexpr int NO_WITNESS_COMMITMENT{-1};/** Minimum size of a witness commitment structure. Defined in BIP 141. **/static constexpr size_t MINIMUM_WITNESS_COMMITMENT{38};/** A "reason" why a transaction was invalid, suitable for determining whether the  * provider of the transaction should be banned/ignored/disconnected/etc.  */enum class TxValidationResult {    TX_RESULT_UNSET = 0,     //!< initial value. Tx has not yet been rejected    TX_CONSENSUS,            //!< invalid by consensus rules    /**     * Invalid by a change to consensus rules more recent than SegWit.     * Currently unused as there are no such consensus rule changes, and any download     * sources realistically need to support SegWit in order to provide useful data,     * so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork     * is uninteresting.     */    TX_RECENT_CONSENSUS_CHANGE,    TX_INPUTS_NOT_STANDARD,   //!< inputs (covered by txid) failed policy rules    TX_NOT_STANDARD,          //!< otherwise didn't meet our local policy rules    TX_MISSING_INPUTS,        //!< transaction was missing some of its inputs    TX_PREMATURE_SPEND,       //!< transaction spends a coinbase too early, or violates locktime/sequence locks    /**     * Transaction might have a witness prior to SegWit     * activation, or witness may have been malleated (which includes     * non-standard witnesses).     */    TX_WITNESS_MUTATED,    /**     * Transaction is missing a witness.     */    TX_WITNESS_STRIPPED,    /**     * Tx already in mempool or conflicts with a tx in the chain     * (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)     * Currently this is only used if the transaction already exists in the mempool or on chain.     */    TX_CONFLICT,    TX_MEMPOOL_POLICY,        //!< violated mempool's fee/size/descendant/RBF/etc limits};/** A "reason" why a block was invalid, suitable for determining whether the  * provider of the block should be banned/ignored/disconnected/etc.  * These are much more granular than the rejection codes, which may be more  * useful for some other use-cases.  */enum class BlockValidationResult {    BLOCK_RESULT_UNSET = 0,  //!< initial value. Block has not yet been rejected    BLOCK_CONSENSUS,         //!< invalid by consensus rules (excluding any below reasons)    /**     * Invalid by a change to consensus rules more recent than SegWit.     * Currently unused as there are no such consensus rule changes, and any download     * sources realistically need to support SegWit in order to provide useful data,     * so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork     * is uninteresting.     */    BLOCK_RECENT_CONSENSUS_CHANGE,    BLOCK_CACHED_INVALID,    //!< this block was cached as being invalid and we didn't store the reason why    BLOCK_INVALID_HEADER,    //!< invalid proof of work or time too old    BLOCK_MUTATED,           //!< the block's data didn't match the data committed to by the PoW    BLOCK_MISSING_PREV,      //!< We don't have the previous block the checked one is built on    BLOCK_INVALID_PREV,      //!< A block this one builds on is invalid    BLOCK_TIME_FUTURE,       //!< block timestamp was > 2 hours in the future (or our clock is bad)    BLOCK_CHECKPOINT,        //!< the block failed to meet one of our checkpoints};/** Template for capturing information about block/transaction validation. This is instantiated *  by TxValidationState and BlockValidationState for validation information on transactions *  and blocks respectively. */template <typename Result>class ValidationState{private:    enum class ModeState {        M_VALID,   //!< everything ok        M_INVALID, //!< network rule violation (DoS value may be set)        M_ERROR,   //!< run-time error    } m_mode{ModeState::M_VALID};    Result m_result{};    std::string m_reject_reason;    std::string m_debug_message;public:    bool Invalid(Result result,                 const std::string& reject_reason = "",                 const std::string& debug_message = "")    {        m_result = result;        m_reject_reason = reject_reason;        m_debug_message = debug_message;        if (m_mode != ModeState::M_ERROR) m_mode = ModeState::M_INVALID;        return false;    }    bool Error(const std::string& reject_reason)    {        if (m_mode == ModeState::M_VALID)            m_reject_reason = reject_reason;        m_mode = ModeState::M_ERROR;        return false;    }    bool IsValid() const { return m_mode == ModeState::M_VALID; }    bool IsInvalid() const { return m_mode == ModeState::M_INVALID; }    bool IsError() const { return m_mode == ModeState::M_ERROR; }    Result GetResult() const { return m_result; }    std::string GetRejectReason() const { return m_reject_reason; }    std::string GetDebugMessage() const { return m_debug_message; }    std::string ToString() const    {        if (IsValid()) {            return "Valid";        }        if (!m_debug_message.empty()) {            return m_reject_reason + ", " + m_debug_message;        }        return m_reject_reason;    }};class TxValidationState : public ValidationState<TxValidationResult> {};class BlockValidationState : public ValidationState<BlockValidationResult> {};// These implement the weight = (stripped_size * 4) + witness_size formula,// using only serialization with and without witness data. As witness_size// is equal to total_size - stripped_size, this formula is identical to:// weight = (stripped_size * 3) + total_size.static inline int64_t GetTransactionWeight(const CTransaction& tx){    size_t pegout_weight = 0;    for (const PegOutCoin& pegout : tx.mweb_tx.GetPegOuts()) {        CTxOut pegout_output(pegout.GetAmount(), pegout.GetScriptPubKey());        pegout_weight += ::GetSerializeSize(pegout_output, PROTOCOL_VERSION) * WITNESS_SCALE_FACTOR;    }    if (tx.IsMWEBOnly()) {        return pegout_weight;    }    // Pegin inputs are 41 bytes each (::GetSerializeSize(CTxIn(), PROTOCOL_VERSION)). 41 * WITNESS_SCALE_FACTOR (4) = 164 weight    size_t pegin_weight = 164 * tx.mweb_tx.GetPegIns().size();    size_t weight = ::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS | SERIALIZE_NO_MWEB) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_NO_MWEB);        return weight + pegout_weight + pegin_weight;}static inline int64_t GetBlockWeight(const CBlock& block){    return ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS | SERIALIZE_NO_MWEB) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_NO_MWEB);}static inline int64_t GetTransactionInputWeight(const CTxIn& txin){    // scriptWitness size is added here because witnesses and txins are split up in segwit serialization.    return ::GetSerializeSize(txin, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS | SERIALIZE_NO_MWEB) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(txin, PROTOCOL_VERSION) + ::GetSerializeSize(txin.scriptWitness.stack, PROTOCOL_VERSION);}/** Compute at which vout of the block's coinbase transaction the witness commitment occurs, or -1 if not found */inline int GetWitnessCommitmentIndex(const CBlock& block){    int commitpos = NO_WITNESS_COMMITMENT;    if (!block.vtx.empty()) {        for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {            const CTxOut& vout = block.vtx[0]->vout[o];            if (vout.scriptPubKey.size() >= MINIMUM_WITNESS_COMMITMENT &&                vout.scriptPubKey[0] == OP_RETURN &&                vout.scriptPubKey[1] == 0x24 &&                vout.scriptPubKey[2] == 0xaa &&                vout.scriptPubKey[3] == 0x21 &&                vout.scriptPubKey[4] == 0xa9 &&                vout.scriptPubKey[5] == 0xed) {                commitpos = o;            }        }    }    return commitpos;}#endif // BITCOIN_CONSENSUS_VALIDATION_H