diff options
Diffstat (limited to 'src/validation.h')
-rw-r--r-- | src/validation.h | 114 |
1 files changed, 75 insertions, 39 deletions
diff --git a/src/validation.h b/src/validation.h index 7c0294d1ad..9ba206855f 100644 --- a/src/validation.h +++ b/src/validation.h @@ -43,7 +43,7 @@ #include <utility> #include <vector> -class CChainState; +class Chainstate; class CBlockTreeDB; class CTxMemPool; class ChainstateManager; @@ -127,7 +127,7 @@ bool AbortNode(BlockValidationState& state, const std::string& strMessage, const double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex); /** Prune block files up to a given height */ -void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight); +void PruneBlockFilesManual(Chainstate& active_chainstate, int nManualPruneHeight); /** * Validation result for a single transaction mempool acceptance. @@ -147,7 +147,7 @@ struct MempoolAcceptResult { const TxValidationState m_state; // The following fields are only present when m_result_type = ResultType::VALID or MEMPOOL_ENTRY - /** Mempool transactions replaced by the tx per BIP 125 rules. */ + /** Mempool transactions replaced by the tx. */ const std::optional<std::list<CTransactionRef>> m_replaced_transactions; /** Virtual size as used by the mempool, calculated using serialized size and sigops. */ const std::optional<int64_t> m_vsize; @@ -240,7 +240,7 @@ struct PackageMempoolAcceptResult * * @returns a MempoolAcceptResult indicating whether the transaction was accepted/rejected with reason. */ -MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx, +MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx, int64_t accept_time, bool bypass_limits, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -252,7 +252,7 @@ MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTr * If a transaction fails, validation will exit early and some results may be missing. It is also * possible for the package to be partially submitted. */ -PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool, +PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool, const Package& txns, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -261,7 +261,7 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx /** * Check if transaction will be final in the next block to be created. */ -bool CheckFinalTxAtTip(const CBlockIndex* active_chain_tip, const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); +bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /** * Check if transaction will be BIP68 final in the next block to be created on top of tip. @@ -333,20 +333,26 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu /** Check a block is completely valid from start to finish (only works on top of our current best block) */ bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainparams, - CChainState& chainstate, + Chainstate& chainstate, const CBlock& block, CBlockIndex* pindexPrev, - const std::function<int64_t()>& adjusted_time_callback, + const std::function<NodeClock::time_point()>& adjusted_time_callback, bool fCheckPOW = true, bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +/** Check with the proof of work on each blockheader matches the value in nBits */ +bool HasValidProofOfWork(const std::vector<CBlockHeader>& headers, const Consensus::Params& consensusParams); + +/** Return the sum of the work on a given set of headers */ +arith_uint256 CalculateHeadersWork(const std::vector<CBlockHeader>& headers); + /** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ class CVerifyDB { public: CVerifyDB(); ~CVerifyDB(); bool VerifyDB( - CChainState& chainstate, + Chainstate& chainstate, const Consensus::Params& consensus_params, CCoinsView& coinsview, int nCheckLevel, @@ -362,7 +368,7 @@ enum DisconnectResult class ConnectTrace; -/** @see CChainState::FlushStateToDisk */ +/** @see Chainstate::FlushStateToDisk */ enum class FlushStateMode { NONE, IF_NEEDED, @@ -415,7 +421,7 @@ enum class CoinsCacheSizeState }; /** - * CChainState stores and provides an API to update our local knowledge of the + * Chainstate stores and provides an API to update our local knowledge of the * current best chain. * * Eventually, the API here is targeted at being exposed externally as a @@ -428,7 +434,7 @@ enum class CoinsCacheSizeState * whereas block information and metadata independent of the current tip is * kept in `BlockManager`. */ -class CChainState +class Chainstate { protected: /** @@ -466,7 +472,7 @@ protected: public: //! Reference to a BlockManager instance which itself is shared across all - //! CChainState instances. + //! Chainstate instances. node::BlockManager& m_blockman; /** Chain parameters for this chainstate */ @@ -478,7 +484,7 @@ public: //! chainstate within deeply nested method calls. ChainstateManager& m_chainman; - explicit CChainState( + explicit Chainstate( CTxMemPool* mempool, node::BlockManager& blockman, ChainstateManager& chainman, @@ -650,7 +656,7 @@ public: EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) LOCKS_EXCLUDED(::cs_main); - bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock, bool min_pow_checked) EXCLUSIVE_LOCKS_REQUIRED(cs_main); // Block (dis)connection on a given view: DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) @@ -808,7 +814,7 @@ private: //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - std::unique_ptr<CChainState> m_ibd_chainstate GUARDED_BY(::cs_main); + std::unique_ptr<Chainstate> m_ibd_chainstate GUARDED_BY(::cs_main); //! A chainstate initialized on the basis of a UTXO snapshot. If this is //! non-null, it is always our active chainstate. @@ -819,7 +825,7 @@ private: //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - std::unique_ptr<CChainState> m_snapshot_chainstate GUARDED_BY(::cs_main); + std::unique_ptr<Chainstate> m_snapshot_chainstate GUARDED_BY(::cs_main); //! Points to either the ibd or snapshot chainstate; indicates our //! most-work chain. @@ -830,7 +836,7 @@ private: //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - CChainState* m_active_chainstate GUARDED_BY(::cs_main) {nullptr}; + Chainstate* m_active_chainstate GUARDED_BY(::cs_main) {nullptr}; //! If true, the assumed-valid chainstate has been fully validated //! by the background validation chainstate. @@ -838,36 +844,54 @@ private: CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr}; - const CChainParams m_chainparams; - - const std::function<int64_t()> m_adjusted_time_callback; - //! Internal helper for ActivateSnapshot(). [[nodiscard]] bool PopulateAndValidateSnapshot( - CChainState& snapshot_chainstate, + Chainstate& snapshot_chainstate, AutoFile& coins_file, const node::SnapshotMetadata& metadata); /** * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure * that it doesn't descend from an invalid block, and then add it to m_block_index. + * Caller must set min_pow_checked=true in order to add a new header to the + * block index (permanent memory storage), indicating that the header is + * known to be part of a sufficiently high-work chain (anti-dos check). */ bool AcceptBlockHeader( const CBlockHeader& block, BlockValidationState& state, - CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - friend CChainState; + CBlockIndex** ppindex, + bool min_pow_checked) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + friend Chainstate; + + /** Most recent headers presync progress update, for rate-limiting. */ + std::chrono::time_point<std::chrono::steady_clock> m_last_presync_update GUARDED_BY(::cs_main) {}; public: using Options = kernel::ChainstateManagerOpts; - explicit ChainstateManager(const Options& opts) - : m_chainparams{opts.chainparams}, - m_adjusted_time_callback{Assert(opts.adjusted_time_callback)} {}; + explicit ChainstateManager(Options options) : m_options{std::move(options)} + { + Assert(m_options.adjusted_time_callback); + } - const CChainParams& GetParams() const { return m_chainparams; } - const Consensus::Params& GetConsensus() const { return m_chainparams.GetConsensus(); } + const CChainParams& GetParams() const { return m_options.chainparams; } + const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); } + /** + * Alias for ::cs_main. + * Should be used in new code to make it easier to make ::cs_main a member + * of this class. + * Generally, methods of this class should be annotated to require this + * mutex. This will make calling code more verbose, but also help to: + * - Clarify that the method will acquire a mutex that heavily affects + * overall performance. + * - Force call sites to think how long they need to acquire the mutex to + * get consistent results. + */ + RecursiveMutex& GetMutex() const LOCK_RETURNED(::cs_main) { return ::cs_main; } + + const Options m_options; std::thread m_load_block; //! A single BlockManager instance is shared across each constructed //! chainstate to avoid duplicating block metadata. @@ -912,19 +936,19 @@ public: // constructor //! @param[in] snapshot_blockhash If given, signify that this chainstate //! is based on a snapshot. - CChainState& InitializeChainstate( + Chainstate& InitializeChainstate( CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash = std::nullopt) LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(::cs_main); //! Get all chainstates currently being used. - std::vector<CChainState*> GetAll(); + std::vector<Chainstate*> GetAll(); //! Construct and activate a Chainstate on the basis of UTXO snapshot data. //! //! Steps: //! - //! - Initialize an unused CChainState. + //! - Initialize an unused Chainstate. //! - Load its `CoinsViews` contents from `coins_file`. //! - Verify that the hash of the resulting coinsdb matches the expected hash //! per assumeutxo chain parameters. @@ -937,10 +961,10 @@ public: AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory); //! The most-work chain. - CChainState& ActiveChainstate() const; - CChain& ActiveChain() const { return ActiveChainstate().m_chain; } - int ActiveHeight() const { return ActiveChain().Height(); } - CBlockIndex* ActiveTip() const { return ActiveChain().Tip(); } + Chainstate& ActiveChainstate() const; + CChain& ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChainstate().m_chain; } + int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Height(); } + CBlockIndex* ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Tip(); } node::BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { @@ -978,10 +1002,15 @@ public: * * @param[in] block The block we want to process. * @param[in] force_processing Process this block even if unrequested; used for non-network block sources. + * @param[in] min_pow_checked True if proof-of-work anti-DoS checks have + * been done by caller for headers chain + * (note: only affects headers acceptance; if + * block header is already present in block + * index then this parameter has no effect) * @param[out] new_block A boolean which is set to indicate if the block was first received via this call * @returns If the block was processed, independently of block validity */ - bool ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked, bool* new_block) LOCKS_EXCLUDED(cs_main); /** * Process incoming block headers. @@ -990,10 +1019,11 @@ public: * validationinterface callback. * * @param[in] block The block headers themselves + * @param[in] min_pow_checked True if proof-of-work anti-DoS checks have been done by caller for headers chain * @param[out] state This may be set to an Error state if any error occurred processing them * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers */ - bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main); /** * Try to add a transaction to the memory pool. @@ -1017,6 +1047,12 @@ public: /** Produce the necessary coinbase commitment for a block (modifies the hash, don't call for mined blocks). */ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev) const; + /** This is used by net_processing to report pre-synchronization progress of headers, as + * headers are not yet fed to validation during that time, but validation is (for now) + * responsible for logging and signalling through NotifyHeaderTip, so it needs this + * information. */ + void ReportHeadersPresync(const arith_uint256& work, int64_t height, int64_t timestamp); + ~ChainstateManager(); }; |