#ifndef BITCOIN_VALIDATION_H
#define BITCOIN_VALIDATION_H
#include <arith_uint256.h>
#include <attributes.h>
#include <chain.h>
#include <checkqueue.h>
#include <consensus/amount.h>
#include <cuckoocache.h>
#include <deploymentstatus.h>
#include <kernel/chain.h>
#include <kernel/chainparams.h>
#include <kernel/chainstatemanager_opts.h>
#include <kernel/cs_main.h>
#include <node/blockstorage.h>
#include <policy/feerate.h>
#include <policy/packages.h>
#include <policy/policy.h>
#include <script/script_error.h>
#include <script/sigcache.h>
#include <script/verify_flags.h>
#include <sync.h>
#include <txdb.h>
#include <txmempool.h>
#include <uint256.h>
#include <util/byte_units.h>
#include <util/check.h>
#include <util/fs.h>
#include <util/hasher.h>
#include <util/result.h>
#include <util/time.h>
#include <util/translation.h>
#include <versionbits.h>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <span>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
class Chainstate;
class CTxMemPool;
class ChainstateManager;
struct ChainTxData;
class DisconnectedBlockTransactions;
struct PrecomputedTransactionData;
struct LockPoints;
struct AssumeutxoData;
namespace kernel {
struct ChainstateRole;
} namespace node {
class SnapshotMetadata;
} namespace Consensus {
struct Params;
} namespace util {
class SignalInterrupt;
}
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static constexpr int DEFAULT_CHECKLEVEL{3};
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
static constexpr int MAX_SCRIPTCHECK_THREADS{15};
enum class SynchronizationState {
INIT_REINDEX,
INIT_DOWNLOAD,
POST_INIT
};
extern const std::vector<std::string> CHECKLEVEL_DOC;
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
bool FatalError(kernel::Notifications& notifications, BlockValidationState& state, const bilingual_str& message);
void PruneBlockFilesManual(Chainstate& active_chainstate, int nManualPruneHeight);
struct MempoolAcceptResult {
enum class ResultType {
VALID, INVALID, MEMPOOL_ENTRY, DIFFERENT_WITNESS, };
const ResultType m_result_type;
const TxValidationState m_state;
const std::list<CTransactionRef> m_replaced_transactions;
const std::optional<int64_t> m_vsize;
const std::optional<CAmount> m_base_fees;
const std::optional<CFeeRate> m_effective_feerate;
const std::optional<std::vector<Wtxid>> m_wtxids_fee_calculations;
const std::optional<Wtxid> m_other_wtxid;
static MempoolAcceptResult Failure(TxValidationState state) {
return MempoolAcceptResult(state);
}
static MempoolAcceptResult FeeFailure(TxValidationState state,
CFeeRate effective_feerate,
const std::vector<Wtxid>& wtxids_fee_calculations) {
return MempoolAcceptResult(state, effective_feerate, wtxids_fee_calculations);
}
static MempoolAcceptResult Success(std::list<CTransactionRef>&& replaced_txns,
int64_t vsize,
CAmount fees,
CFeeRate effective_feerate,
const std::vector<Wtxid>& wtxids_fee_calculations) {
return MempoolAcceptResult(std::move(replaced_txns), vsize, fees,
effective_feerate, wtxids_fee_calculations);
}
static MempoolAcceptResult MempoolTx(int64_t vsize, CAmount fees) {
return MempoolAcceptResult(vsize, fees);
}
static MempoolAcceptResult MempoolTxDifferentWitness(const Wtxid& other_wtxid) {
return MempoolAcceptResult(other_wtxid);
}
private:
explicit MempoolAcceptResult(TxValidationState state)
: m_result_type(ResultType::INVALID), m_state(state) {
Assume(!state.IsValid()); }
explicit MempoolAcceptResult(std::list<CTransactionRef>&& replaced_txns,
int64_t vsize,
CAmount fees,
CFeeRate effective_feerate,
const std::vector<Wtxid>& wtxids_fee_calculations)
: m_result_type(ResultType::VALID),
m_replaced_transactions(std::move(replaced_txns)),
m_vsize{vsize},
m_base_fees(fees),
m_effective_feerate(effective_feerate),
m_wtxids_fee_calculations(wtxids_fee_calculations) {}
explicit MempoolAcceptResult(TxValidationState state,
CFeeRate effective_feerate,
const std::vector<Wtxid>& wtxids_fee_calculations)
: m_result_type(ResultType::INVALID),
m_state(state),
m_effective_feerate(effective_feerate),
m_wtxids_fee_calculations(wtxids_fee_calculations) {}
explicit MempoolAcceptResult(int64_t vsize, CAmount fees)
: m_result_type(ResultType::MEMPOOL_ENTRY), m_vsize{vsize}, m_base_fees(fees) {}
explicit MempoolAcceptResult(const Wtxid& other_wtxid)
: m_result_type(ResultType::DIFFERENT_WITNESS), m_other_wtxid(other_wtxid) {}
};
struct PackageMempoolAcceptResult
{
PackageValidationState m_state;
std::map<Wtxid, MempoolAcceptResult> m_tx_results;
explicit PackageMempoolAcceptResult(PackageValidationState state,
std::map<Wtxid, MempoolAcceptResult>&& results)
: m_state{state}, m_tx_results(std::move(results)) {}
explicit PackageMempoolAcceptResult(PackageValidationState state, CFeeRate feerate,
std::map<Wtxid, MempoolAcceptResult>&& results)
: m_state{state}, m_tx_results(std::move(results)) {}
explicit PackageMempoolAcceptResult(const Wtxid& wtxid, const MempoolAcceptResult& result)
: m_tx_results{ {wtxid, result} } {}
};
MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx,
int64_t accept_time, bool bypass_limits, bool test_accept)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool,
const Package& txns, bool test_accept, const std::optional<CFeeRate>& client_maxfeerate)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
std::optional<LockPoints> CalculateLockPointsAtTip(
CBlockIndex* tip,
const CCoinsView& coins_view,
const CTransaction& tx);
bool CheckSequenceLocksAtTip(CBlockIndex* tip,
const LockPoints& lock_points);
class CScriptCheck
{
private:
CTxOut m_tx_out;
const CTransaction *ptxTo;
unsigned int nIn;
script_verify_flags m_flags;
bool cacheStore;
PrecomputedTransactionData *txdata;
SignatureCache* m_signature_cache;
public:
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, script_verify_flags flags, bool cacheIn, PrecomputedTransactionData* txdataIn) :
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), m_flags(flags), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
CScriptCheck(const CScriptCheck&) = delete;
CScriptCheck& operator=(const CScriptCheck&) = delete;
CScriptCheck(CScriptCheck&&) = default;
CScriptCheck& operator=(CScriptCheck&&) = default;
std::optional<std::pair<ScriptError, std::string>> operator()();
};
static_assert(std::is_nothrow_move_assignable_v<CScriptCheck>);
static_assert(std::is_nothrow_move_constructible_v<CScriptCheck>);
static_assert(std::is_nothrow_destructible_v<CScriptCheck>);
class ValidationCache
{
private:
CSHA256 m_script_execution_cache_hasher;
public:
CuckooCache::cache<uint256, SignatureCacheHasher> m_script_execution_cache;
SignatureCache m_signature_cache;
ValidationCache(size_t script_execution_cache_bytes, size_t signature_cache_bytes);
ValidationCache(const ValidationCache&) = delete;
ValidationCache& operator=(const ValidationCache&) = delete;
CSHA256 ScriptExecutionCacheHasher() const { return m_script_execution_cache_hasher; }
};
bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
BlockValidationState TestBlockValidity(
Chainstate& chainstate,
const CBlock& block,
bool check_pow,
bool check_merkle_root) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool HasValidProofOfWork(std::span<const CBlockHeader> headers, const Consensus::Params& consensusParams);
bool IsBlockMutated(const CBlock& block, bool check_witness_root);
arith_uint256 CalculateClaimedHeadersWork(std::span<const CBlockHeader> headers);
enum class VerifyDBResult {
SUCCESS,
CORRUPTED_BLOCK_DB,
INTERRUPTED,
SKIPPED_L3_CHECKS,
SKIPPED_MISSING_BLOCKS,
};
class CVerifyDB
{
private:
kernel::Notifications& m_notifications;
public:
explicit CVerifyDB(kernel::Notifications& notifications);
~CVerifyDB();
[[nodiscard]] VerifyDBResult VerifyDB(
Chainstate& chainstate,
const Consensus::Params& consensus_params,
CCoinsView& coinsview,
int nCheckLevel,
int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
};
enum DisconnectResult
{
DISCONNECT_OK, DISCONNECT_UNCLEAN, DISCONNECT_FAILED };
class ConnectTrace;
inline constexpr std::array FlushStateModeNames{"NONE", "IF_NEEDED", "PERIODIC", "ALWAYS"};
enum class FlushStateMode: uint8_t {
NONE,
IF_NEEDED,
PERIODIC,
ALWAYS
};
class CoinsViews {
public:
CCoinsViewDB m_dbview GUARDED_BY(cs_main);
CCoinsViewErrorCatcher m_catcherview GUARDED_BY(cs_main);
std::unique_ptr<CCoinsViewCache> m_cacheview GUARDED_BY(cs_main);
CoinsViews(DBParams db_params, CoinsViewOptions options);
void InitCache() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
};
enum class CoinsCacheSizeState
{
CRITICAL = 2,
LARGE = 1,
OK = 0
};
constexpr int64_t LargeCoinsCacheThreshold(int64_t total_space) noexcept
{
constexpr int64_t MAX_BLOCK_COINSDB_USAGE_BYTES{int64_t(10_MiB)};
return std::max((total_space * 9) / 10,
total_space - MAX_BLOCK_COINSDB_USAGE_BYTES);
}
enum class Assumeutxo {
VALIDATED,
UNVALIDATED,
INVALID,
};
class Chainstate
{
protected:
Mutex m_chainstate_mutex;
CTxMemPool* m_mempool;
std::unique_ptr<CoinsViews> m_coins_views;
mutable const CBlockIndex* m_cached_snapshot_base GUARDED_BY(::cs_main){nullptr};
mutable const CBlockIndex* m_cached_target_block GUARDED_BY(::cs_main){nullptr};
std::optional<const char*> m_last_script_check_reason_logged GUARDED_BY(::cs_main){};
public:
node::BlockManager& m_blockman;
ChainstateManager& m_chainman;
explicit Chainstate(
CTxMemPool* mempool,
node::BlockManager& blockman,
ChainstateManager& chainman,
std::optional<uint256> from_snapshot_blockhash = std::nullopt);
fs::path StoragePath() const;
kernel::ChainstateRole GetRole() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
void InitCoinsDB(
size_t cache_size_bytes,
bool in_memory,
bool should_wipe);
void InitCoinsCache(size_t cache_size_bytes) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
return m_coins_views && m_coins_views->m_cacheview;
}
CChain m_chain;
Assumeutxo m_assumeutxo GUARDED_BY(::cs_main);
const std::optional<uint256> m_from_snapshot_blockhash;
std::optional<uint256> m_target_blockhash GUARDED_BY(::cs_main);
std::optional<AssumeutxoHash> m_target_utxohash GUARDED_BY(::cs_main);
const CBlockIndex* SnapshotBase() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
const CBlockIndex* TargetBlock() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
void SetTargetBlock(CBlockIndex* block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
void SetTargetBlockHash(uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool ReachedTarget() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
const CBlockIndex* target_block{TargetBlock()};
assert(!target_block || target_block->GetAncestor(m_chain.Height()) == m_chain.Tip());
return target_block && target_block == m_chain.Tip();
}
std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates;
CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
Assert(m_coins_views);
return *Assert(m_coins_views->m_cacheview);
}
CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
return Assert(m_coins_views)->m_dbview;
}
CTxMemPool* GetMempool()
{
return m_mempool;
}
CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
return Assert(m_coins_views)->m_catcherview;
}
void ResetCoinsViews() { m_coins_views.reset(); }
size_t m_coinsdb_cache_size_bytes{0};
size_t m_coinstip_cache_size_bytes{0};
bool ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool FlushStateToDisk(
BlockValidationState& state,
FlushStateMode mode,
int nManualPruneHeight = 0);
void ForceFlushStateToDisk();
void PruneAndFlush();
bool ActivateBestChain(
BlockValidationState& state,
std::shared_ptr<const CBlock> pblock = nullptr)
EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex)
LOCKS_EXCLUDED(::cs_main);
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex,
CCoinsViewCache& view, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool DisconnectTip(BlockValidationState& state, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex)
LOCKS_EXCLUDED(::cs_main);
bool InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex)
EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex)
LOCKS_EXCLUDED(::cs_main);
void SetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ReplayBlocks();
[[nodiscard]] bool NeedsRedownload() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool LoadGenesisBlock();
void TryAddBlockIndexCandidate(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void PruneBlockIndexCandidates();
void ClearBlockIndexCandidates() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
const CBlockIndex* FindForkInGlobalIndex(const CBlockLocator& locator) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool LoadChainTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CoinsCacheSizeState GetCoinsCacheSizeState() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
CoinsCacheSizeState GetCoinsCacheSizeState(
size_t max_coins_cache_size_bytes,
size_t max_mempool_size_bytes) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
RecursiveMutex* MempoolMutex() const LOCK_RETURNED(m_mempool->cs)
{
return m_mempool ? &m_mempool->cs : nullptr;
}
std::pair<int, int> GetPruneRange(int last_height_can_prune) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
protected:
bool ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
bool ConnectTip(
BlockValidationState& state,
CBlockIndex* pindexNew,
std::shared_ptr<const CBlock> block_to_connect,
ConnectTrace& connectTrace,
DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
void InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void MaybeUpdateMempoolForReorg(
DisconnectedBlockTransactions& disconnectpool,
bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
void UpdateTip(const CBlockIndex* pindexNew)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
NodeClock::time_point m_next_write{NodeClock::time_point::max()};
[[nodiscard]] util::Result<void> InvalidateCoinsDBOnDisk() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
friend ChainstateManager;
};
enum class SnapshotCompletionResult {
SUCCESS,
SKIPPED,
MISSING_CHAINPARAMS,
STATS_FAILED,
HASH_MISMATCH,
};
class ChainstateManager
{
private:
CBlockIndex* m_last_notified_header GUARDED_BY(GetMutex()){nullptr};
bool NotifyHeaderTip() LOCKS_EXCLUDED(GetMutex());
[[nodiscard]] util::Result<void> PopulateAndValidateSnapshot(
Chainstate& snapshot_chainstate,
AutoFile& coins_file,
const node::SnapshotMetadata& metadata);
bool AcceptBlockHeader(
const CBlockHeader& block,
BlockValidationState& state,
CBlockIndex** ppindex,
bool min_pow_checked) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
friend Chainstate;
MockableSteadyClock::time_point m_last_presync_update GUARDED_BY(GetMutex()){};
CCheckQueue<CScriptCheck> m_script_check_queue;
SteadyClock::duration GUARDED_BY(::cs_main) time_check{};
SteadyClock::duration GUARDED_BY(::cs_main) time_forks{};
SteadyClock::duration GUARDED_BY(::cs_main) time_connect{};
SteadyClock::duration GUARDED_BY(::cs_main) time_verify{};
SteadyClock::duration GUARDED_BY(::cs_main) time_undo{};
SteadyClock::duration GUARDED_BY(::cs_main) time_index{};
SteadyClock::duration GUARDED_BY(::cs_main) time_total{};
int64_t GUARDED_BY(::cs_main) num_blocks_total{0};
SteadyClock::duration GUARDED_BY(::cs_main) time_connect_total{};
SteadyClock::duration GUARDED_BY(::cs_main) time_flush{};
SteadyClock::duration GUARDED_BY(::cs_main) time_chainstate{};
SteadyClock::duration GUARDED_BY(::cs_main) time_post_connect{};
protected:
CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
public:
using Options = kernel::ChainstateManagerOpts;
explicit ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options);
std::function<void()> snapshot_download_completed = std::function<void()>();
const CChainParams& GetParams() const { return m_options.chainparams; }
const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); }
bool ShouldCheckBlockIndex() const;
const arith_uint256& MinimumChainWork() const { return *Assert(m_options.minimum_chain_work); }
const uint256& AssumedValidBlock() const { return *Assert(m_options.assumed_valid_block); }
kernel::Notifications& GetNotifications() const { return m_options.notifications; };
void CheckBlockIndex() const;
RecursiveMutex& GetMutex() const LOCK_RETURNED(::cs_main) { return ::cs_main; }
const util::SignalInterrupt& m_interrupt;
const Options m_options;
node::BlockManager m_blockman;
ValidationCache m_validation_cache;
mutable std::atomic<bool> m_cached_finished_ibd{false};
int32_t nBlockSequenceId GUARDED_BY(::cs_main) = SEQ_ID_INIT_FROM_DISK + 1;
int32_t nBlockReverseSequenceId = -1;
arith_uint256 nLastPreciousChainwork = 0;
void ResetBlockSequenceCounters() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
nBlockSequenceId = SEQ_ID_INIT_FROM_DISK + 1;
nBlockReverseSequenceId = -1;
}
CBlockIndex* m_best_header GUARDED_BY(::cs_main){nullptr};
size_t m_total_coinstip_cache{0};
size_t m_total_coinsdb_cache{0};
Chainstate& InitializeChainstate(CTxMemPool* mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
[[nodiscard]] util::Result<CBlockIndex*> ActivateSnapshot(
AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
SnapshotCompletionResult MaybeValidateSnapshot(Chainstate& validated_cs, Chainstate& unvalidated_cs) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
Chainstate& CurrentChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
{
for (auto& cs : m_chainstates) {
if (cs && cs->m_assumeutxo != Assumeutxo::INVALID && !cs->m_target_blockhash) return *cs;
}
abort();
}
Chainstate* HistoricalChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
{
for (auto& cs : m_chainstates) {
if (cs && cs->m_assumeutxo != Assumeutxo::INVALID && cs->m_target_blockhash && !cs->m_target_utxohash) return cs.get();
}
return nullptr;
}
Chainstate& ValidatedChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
{
for (auto* cs : {&CurrentChainstate(), HistoricalChainstate()}) {
if (cs && cs->m_assumeutxo == Assumeutxo::VALIDATED) return *cs;
}
abort();
}
std::unique_ptr<Chainstate> RemoveChainstate(Chainstate& chainstate) EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
{
auto it{std::find_if(m_chainstates.begin(), m_chainstates.end(), [&](auto& cs) { return cs.get() == &chainstate; })};
if (it != m_chainstates.end()) {
auto ret{std::move(*it)};
m_chainstates.erase(it);
return ret;
}
return nullptr;
}
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)
{
AssertLockHeld(::cs_main);
return m_blockman.m_block_index;
}
mutable VersionBitsCache m_versionbitscache;
bool IsInitialBlockDownload() const;
double GuessVerificationProgress(const CBlockIndex* pindex) const EXCLUSIVE_LOCKS_REQUIRED(GetMutex());
void LoadExternalBlockFile(
AutoFile& file_in,
FlatFilePos* dbp = nullptr,
std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent = nullptr);
bool ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked, bool* new_block) LOCKS_EXCLUDED(cs_main);
bool ProcessNewBlockHeaders(std::span<const CBlockHeader> headers, bool min_pow_checked, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(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);
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
[[nodiscard]] MempoolAcceptResult ProcessTransaction(const CTransactionRef& tx, bool test_accept=false)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev) const;
std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev) const;
void ReportHeadersPresync(int64_t height, int64_t timestamp);
Chainstate* LoadAssumeutxoChainstate() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
Chainstate& AddChainstate(std::unique_ptr<Chainstate> chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
void ResetChainstates() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
[[nodiscard]] bool DeleteChainstate(Chainstate& chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool ValidatedSnapshotCleanup(Chainstate& validated_cs, Chainstate& unvalidated_cs) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
std::optional<std::pair<const CBlockIndex*, const CBlockIndex*>> GetHistoricalBlockRange() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
util::Result<void> ActivateBestChains() LOCKS_EXCLUDED(::cs_main);
void RecalculateBestHeader() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
CCheckQueue<CScriptCheck>& GetCheckQueue() { return m_script_check_queue; }
~ChainstateManager();
std::vector<std::unique_ptr<Chainstate>> m_chainstates GUARDED_BY(::cs_main);
};
template<typename DEP>
bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const ChainstateManager& chainman, DEP dep)
{
return DeploymentActiveAfter(pindexPrev, chainman.GetConsensus(), dep, chainman.m_versionbitscache);
}
template<typename DEP>
bool DeploymentActiveAt(const CBlockIndex& index, const ChainstateManager& chainman, DEP dep)
{
return DeploymentActiveAt(index, chainman.GetConsensus(), dep, chainman.m_versionbitscache);
}
template<typename DEP>
bool DeploymentEnabled(const ChainstateManager& chainman, DEP dep)
{
return DeploymentEnabled(chainman.GetConsensus(), dep);
}
bool IsBIP30Repeat(const CBlockIndex& block_index);
bool IsBIP30Unspendable(const uint256& block_hash, int block_height);
script_verify_flags GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman);
#endif