#pragma once #include #include #include #include #include #include #include #include #include #include // Forward Declarations class 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 { public: using Ptr = std::shared_ptr; using CPtr = std::shared_ptr; ICoinsView(const mw::Header::CPtr& pHeader, const std::shared_ptr& 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& GetDatabase() const noexcept { return m_pDatabase; } void SetDatabase(const std::shared_ptr& 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; /// /// Checks if there's a unspent coin in the view with a matching commitment. /// /// The output ID of the UTXO to look for. /// True if there's a matching unspent coin. Otherwise, false. bool HasCoin(const mw::Hash& output_id) const noexcept { return GetUTXO(output_id) != nullptr; } /// /// 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. /// /// The output ID of the coin to look for. /// True if there's a matching unspent coin. Otherwise, false. virtual bool HasCoinInCache(const mw::Hash& output_id) const noexcept = 0; /// /// Cleanup any old MMR files that no longer reflect the latest flushed state. /// virtual void Compact() const = 0; private: mw::Header::CPtr m_pHeader; std::shared_ptr m_pDatabase; }; class CoinsViewCache : public mw::ICoinsView { public: using Ptr = std::shared_ptr; using CPtr = std::shared_ptr; explicit CoinsViewCache(const ICoinsView::Ptr& pBase); bool IsCache() const noexcept final { return true; } UTXO::CPtr GetUTXO(const mw::Hash& output_id) const noexcept final; /// /// Validates and connects the block to the end of the chain. /// Consumer is required to call ValidateBlock first. /// ///
Block must be validated via CheckBlock before connecting it to the chain.
/// The block to connect. Must not be null. /// ValidationException if consensus rules are not met. mw::BlockUndo::CPtr ApplyBlock(const mw::Block::CPtr& pBlock, const bool allow_historical_metadata_mismatch = false); void AddTx(const mw::Transaction::CPtr& pTx); /// /// Removes a block from the end of the chain. /// /// The MWEB undo data to apply. Must not be null. 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(); } /// /// 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. /// /// The optional DB batch. This must be non-null when the base CoinsView is a DB view. void Flush(const mw::DBBatch::UPtr& pBatch = nullptr); mw::Block::Ptr BuildNextBlock(const uint64_t height, const std::vector& 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 m_pUpdates; }; class CoinsViewDB : public mw::ICoinsView { public: using Ptr = std::shared_ptr; 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