git / moonbite-core / src/libmw/include/mw/node/CoinsView.h · raw

#pragma once#include <mw/common/Macros.h>#include <mw/models/block/Header.h>#include <mw/models/block/Block.h>#include <mw/models/block/BlockUndo.h>#include <mw/models/tx/Transaction.h>#include <mw/models/tx/UTXO.h>#include <mw/mmr/MMR.h>#include <mw/mmr/LeafSet.h>#include <mw/interfaces/db_interface.h>#include <memory>// Forward Declarationsclass CoinDB;class CoinsViewUpdates;MW_NAMESPACE//// An interface for the various views of the extension block's UTXO set.// This is similar to CCoinsView in the main codebase, and in fact, each CCoinsView// should also hold an instance of a mw::ICoinsView for use with MWEB-related logic.//class ICoinsView : public std::enable_shared_from_this<ICoinsView>{public:    using Ptr = std::shared_ptr<ICoinsView>;    using CPtr = std::shared_ptr<const ICoinsView>;    ICoinsView(const mw::Header::CPtr& pHeader, const std::shared_ptr<mw::DBWrapper>& pDBWrapper)        : m_pHeader(pHeader), m_pDatabase(pDBWrapper) { }    virtual ~ICoinsView() = default;    void SetBestHeader(const mw::Header::CPtr& pHeader) noexcept { m_pHeader = pHeader; }    mw::Header::CPtr GetBestHeader() const noexcept { return m_pHeader; }    const std::shared_ptr<mw::DBWrapper>& GetDatabase() const noexcept { return m_pDatabase; }    void SetDatabase(const std::shared_ptr<mw::DBWrapper>& pDBWrapper) noexcept { m_pDatabase = pDBWrapper; }    virtual bool IsCache() const noexcept = 0;    // Virtual functions    virtual UTXO::CPtr GetUTXO(const mw::Hash& output_id) const = 0;    virtual void WriteBatch(        const mw::DBBatch::UPtr& pBatch,        const CoinsViewUpdates& updates,        const mw::Header::CPtr& pHeader    ) = 0;    virtual ILeafSet::Ptr GetLeafSet() const noexcept = 0;    virtual IMMR::Ptr GetOutputPMMR() const noexcept = 0;    /// <summary>    /// Checks if there's a unspent coin in the view with a matching commitment.    /// </summary>    /// <param name="output_id">The output ID of the UTXO to look for.</param>    /// <returns>True if there's a matching unspent coin. Otherwise, false.</returns>    bool HasCoin(const mw::Hash& output_id) const noexcept { return GetUTXO(output_id) != nullptr; }    /// <summary>    /// Checks if there's a unspent coin with a matching commitment in the view that has not been flushed to the parent.    /// This is useful for checking if a coin is in the mempool but not yet on chain.    /// </summary>    /// <param name="output_id">The output ID of the coin to look for.</param>    /// <returns>True if there's a matching unspent coin. Otherwise, false.</returns>    virtual bool HasCoinInCache(const mw::Hash& output_id) const noexcept = 0;    /// <summary>    /// Cleanup any old MMR files that no longer reflect the latest flushed state.    /// </summary>    virtual void Compact() const = 0;private:    mw::Header::CPtr m_pHeader;    std::shared_ptr<mw::DBWrapper> m_pDatabase;};class CoinsViewCache : public mw::ICoinsView{public:    using Ptr = std::shared_ptr<CoinsViewCache>;    using CPtr = std::shared_ptr<const CoinsViewCache>;    explicit CoinsViewCache(const ICoinsView::Ptr& pBase);    bool IsCache() const noexcept final { return true; }    UTXO::CPtr GetUTXO(const mw::Hash& output_id) const noexcept final;    /// <summary>    /// Validates and connects the block to the end of the chain.    /// Consumer is required to call ValidateBlock first.    /// </summary>    /// <pre>Block must be validated via CheckBlock before connecting it to the chain.</pre>    /// <param name="pBlock">The block to connect. Must not be null.</param>    /// <throws>ValidationException if consensus rules are not met.</throws>    mw::BlockUndo::CPtr ApplyBlock(const mw::Block::CPtr& pBlock, const bool allow_historical_metadata_mismatch = false);    void AddTx(const mw::Transaction::CPtr& pTx);    /// <summary>    /// Removes a block from the end of the chain.    /// </summary>    /// <param name="pUndo">The MWEB undo data to apply. Must not be null.</param>    void UndoBlock(const mw::BlockUndo::CPtr& pUndo);    void WriteBatch(        const mw::DBBatch::UPtr& pBatch,        const CoinsViewUpdates& updates,        const mw::Header::CPtr& pHeader    ) final;    void Compact() const final { m_pBase->Compact(); }    /// <summary>    /// Commits the changes from the cached CoinsView to the base CoinsView.    /// Adds the cached updates to the database if the base CoinsView is a DB view.    /// </summary>    /// <param name="pBatch">The optional DB batch. This must be non-null when the base CoinsView is a DB view.</param>    void Flush(const mw::DBBatch::UPtr& pBatch = nullptr);    mw::Block::Ptr BuildNextBlock(const uint64_t height, const std::vector<mw::Transaction::CPtr>& transactions);    bool HasCoinInCache(const mw::Hash& output_id) const noexcept final;    bool HasSpendInCache(const mw::Hash& output_id) const noexcept;    ILeafSet::Ptr GetLeafSet() const noexcept final { return m_pLeafSet; }    IMMR::Ptr GetOutputPMMR() const noexcept final { return m_pOutputPMMR; }private:    mw::BlockUndo::CPtr ApplyBlockChanges(const mw::Block::CPtr& pBlock, const bool allow_historical_metadata_mismatch);    void AddUTXO(const uint64_t header_height, const Output& output);    UTXO SpendUTXO(const mw::Hash& output_id);    ICoinsView::Ptr m_pBase;    LeafSetCache::Ptr m_pLeafSet;    PMMRCache::Ptr m_pOutputPMMR;    std::shared_ptr<CoinsViewUpdates> m_pUpdates;};class CoinsViewDB : public mw::ICoinsView{public:    using Ptr = std::shared_ptr<CoinsViewDB>;    static CoinsViewDB::Ptr Open(        const FilePath& datadir,        const mw::Header::CPtr& pBestHeader,        const mw::DBWrapper::Ptr& pDBWrapper    );    bool IsCache() const noexcept final { return false; }    UTXO::CPtr GetUTXO(const mw::Hash& output_id) const final;    void WriteBatch(        const mw::DBBatch::UPtr& pBatch,        const CoinsViewUpdates& updates,        const mw::Header::CPtr& pHeader    ) final;    void Compact() const final;    ILeafSet::Ptr GetLeafSet() const noexcept final { return m_pLeafSet; }    IMMR::Ptr GetOutputPMMR() const noexcept final { return m_pOutputPMMR; }    bool HasCoinInCache(const mw::Hash& output_id) const noexcept final { return false; }private:    CoinsViewDB(        const mw::Header::CPtr& pBestHeader,        const mw::DBWrapper::Ptr& pDBWrapper,        const LeafSet::Ptr& pLeafSet,        const PMMR::Ptr& pOutputPMMR    ) : ICoinsView(pBestHeader, pDBWrapper),        m_pLeafSet(pLeafSet),        m_pOutputPMMR(pOutputPMMR) { }    void AddUTXO(CoinDB& coinDB, const Output& output);    void AddUTXO(CoinDB& coinDB, const UTXO::CPtr& pUTXO);    void SpendUTXO(CoinDB& coinDB, const mw::Hash& output_id);    UTXO::CPtr GetUTXO(const CoinDB& coinDB, const mw::Hash& output_id) const;    LeafSet::Ptr m_pLeafSet;    PMMR::Ptr m_pOutputPMMR;};END_NAMESPACE