Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ BITCOIN_CORE_H = \
util/error.h \
util/fees.h \
util/golombrice.h \
util/hash_type.h \
util/irange.h \
util/spanparsing.h \
util/system.h \
Expand Down
13 changes: 13 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,27 @@ class CBlockIndex

//! Number of transactions in this block.
//! Note: in a potential headers-first mode, this number cannot be relied upon
//! Note: this value is faked during UTXO snapshot load to ensure that
//! LoadBlockIndex() will load index entries for blocks that we lack data for.
//! @sa ActivateSnapshot
unsigned int nTx{0};

//! (memory only) Number of transactions in the chain up to and including this block.
//! This value will be non-zero only if and only if transactions for this block and all its parents are available.
//! Change to 64-bit type when necessary; won't happen before 2030
//!
//! Note: this value is faked during use of a UTXO snapshot because we don't
//! have the underlying block data available during snapshot load.
//! @sa AssumeutxoData
//! @sa ActivateSnapshot
unsigned int nChainTx{0};

//! Verification status of this block. See enum BlockStatus
//!
//! Note: this value is modified to show BLOCK_OPT_WITNESS during UTXO snapshot
//! load to avoid the block index being spuriously rewound.
//! @sa RewindBlockIndex
//! @sa ActivateSnapshot
uint32_t nStatus{0};

//! block header
Expand Down
20 changes: 19 additions & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <chainparamsseeds.h>
#include <consensus/merkle.h>
#include <llmq/params.h>
#include <tinyformat.h>
#include <util/ranges.h>
#include <util/system.h>
#include <util/underlying.h>
Expand Down Expand Up @@ -311,6 +310,10 @@ class CMainParams : public CChainParams {
}
};

m_assumeutxo_data = MapAssumeutxo{
// TODO to be specified in a future patch.
};

// getchaintxstats 17280 00000000000000261bdbe99c01fcba992e577efa6cc41aae564b8ca9f112b2a3
chainTxData = ChainTxData{
1680866408, // * UNIX timestamp of last known number of transactions (Block 1718597)
Expand Down Expand Up @@ -477,6 +480,10 @@ class CTestNetParams : public CChainParams {
}
};

m_assumeutxo_data = MapAssumeutxo{
// TODO to be specified in a future patch.
};

// getchaintxstats 17280 0000005c35514190ef3c38d322f69412553dc7e1107ed5f92adc2935b90acc51
chainTxData = ChainTxData{
1680868209, // * UNIX timestamp of last known number of transactions (Block 771537)
Expand Down Expand Up @@ -846,6 +853,17 @@ class CRegTestParams : public CChainParams {
}
};

m_assumeutxo_data = MapAssumeutxo{
{
110,
{AssumeutxoHash{uint256S("0x9b2a277a3e3b979f1a539d57e949495d7f8247312dbc32bce6619128c192b44b")}, 110},
},
{
210,
{AssumeutxoHash{uint256S("0xd4c97d32882583b057efc3dce673e44204851435e6ffcef20346e69cddc7c91e")}, 210},
},
};

chainTxData = ChainTxData{
0,
0,
Expand Down
29 changes: 29 additions & 0 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <llmq/params.h>
#include <primitives/block.h>
#include <protocol.h>
#include <util/hash_type.h>

#include <memory>
#include <vector>
Expand All @@ -26,6 +27,28 @@ struct CCheckpointData {
MapCheckpoints mapCheckpoints;
};

struct AssumeutxoHash : public BaseHash<uint256> {
explicit AssumeutxoHash(const uint256& hash) : BaseHash(hash) {}
};

/**
* Holds configuration for use during UTXO snapshot load and validation. The contents
* here are security critical, since they dictate which UTXO snapshots are recognized
* as valid.
*/
struct AssumeutxoData {
//! The expected hash of the deserialized UTXO set.
const AssumeutxoHash hash_serialized;

//! Used to populate the nChainTx value, which is used during BlockManager::LoadBlockIndex().
//!
//! We need to hardcode the value here because this is computed cumulatively using block data,
//! which we do not necessarily have at the time of snapshot load.
const unsigned int nChainTx;
};

using MapAssumeutxo = std::map<int, const AssumeutxoData>;

/**
* Holds various statistics on transactions within a chain. Used to estimate
* verification progress during chain sync.
Expand Down Expand Up @@ -97,6 +120,11 @@ class CChainParams
int ExtCoinType() const { return nExtCoinType; }
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }

//! Get allowed assumeutxo configuration.
//! @see ChainstateManager
const MapAssumeutxo& Assumeutxo() const { return m_assumeutxo_data; }

const ChainTxData& TxData() const { return chainTxData; }
void UpdateDIP3Parameters(int nActivationHeight, int nEnforcementHeight);
void UpdateDIP8Parameters(int nActivationHeight);
Expand Down Expand Up @@ -139,6 +167,7 @@ class CChainParams
bool m_is_mockable_chain;
int nLLMQConnectionRetryTimeout;
CCheckpointData checkpointData;
MapAssumeutxo m_assumeutxo_data;
ChainTxData chainTxData;
int nPoolMinParticipants;
int nPoolMaxParticipants;
Expand Down
8 changes: 8 additions & 0 deletions src/coins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
}

void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) {
cachedCoinsUsage += coin.DynamicMemoryUsage();
cacheCoins.emplace(
std::piecewise_construct,
std::forward_as_tuple(std::move(outpoint)),
std::forward_as_tuple(std::move(coin), CCoinsCacheEntry::DIRTY));
}

void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite) {
bool fCoinbase = tx.IsCoinBase();
const uint256& txid = tx.GetHash();
Expand Down
10 changes: 10 additions & 0 deletions src/coins.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ struct CCoinsCacheEntry

CCoinsCacheEntry() : flags(0) {}
explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}
CCoinsCacheEntry(Coin&& coin_, unsigned char flag) : coin(std::move(coin_)), flags(flag) {}
};

typedef std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher> CCoinsMap;
Expand Down Expand Up @@ -292,6 +293,15 @@ class CCoinsViewCache : public CCoinsViewBacked
*/
void AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite);

/**
* Emplace a coin into cacheCoins without performing any checks, marking
* the emplaced coin as dirty.
*
* NOT FOR GENERAL USE. Used only when loading coins from a UTXO snapshot.
* @sa ChainstateManager::PopulateAndValidateSnapshot()
*/
void EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin);

/**
* Spend a coin. Pass moveto in order to get the deleted data.
* If no unspent output exists for the passed outpoint, this call
Expand Down
21 changes: 10 additions & 11 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,6 @@ static void CleanupBlockRevFiles()

static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args)
{
const CChainParams& chainparams = Params();
ScheduleBatchPriority();

{
Expand All @@ -901,7 +900,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
if (!file)
break; // This error is logged in OpenBlockFile
LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
::ChainstateActive().LoadExternalBlockFile(chainparams, file, &pos);
::ChainstateActive().LoadExternalBlockFile(file, &pos);
if (ShutdownRequested()) {
LogPrintf("Shutdown requested. Exit %s\n", __func__);
return;
Expand All @@ -912,15 +911,15 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
fReindex = false;
LogPrintf("Reindexing finished\n");
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
::ChainstateActive().LoadGenesisBlock(chainparams);
::ChainstateActive().LoadGenesisBlock();
}

// -loadblock=
for (const fs::path& path : vImportFiles) {
FILE *file = fsbridge::fopen(path, "rb");
if (file) {
LogPrintf("Importing blocks file %s...\n", path.string());
::ChainstateActive().LoadExternalBlockFile(chainparams, file);
::ChainstateActive().LoadExternalBlockFile(file);
if (ShutdownRequested()) {
LogPrintf("Shutdown requested. Exit %s\n", __func__);
return;
Expand All @@ -937,7 +936,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
// the relevant pointers before the ABC call.
for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
BlockValidationState state;
if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) {
if (!chainstate->ActivateBestChain(state, nullptr)) {
LogPrintf("Failed to connect best block (%s)\n", state.ToString());
StartShutdown();
return;
Expand Down Expand Up @@ -985,7 +984,7 @@ static void PeriodicStats(ArgsManager& args, const CTxMemPool& mempool)
assert(args.GetBoolArg("-statsenabled", DEFAULT_STATSD_ENABLE));
CCoinsStats stats;
::ChainstateActive().ForceFlushStateToDisk();
if (WITH_LOCK(cs_main, return GetUTXOStats(&::ChainstateActive().CoinsDB(), stats, CoinStatsHashType::NONE, RpcInterruptionPoint))) {
if (WITH_LOCK(cs_main, return GetUTXOStats(&::ChainstateActive().CoinsDB(), std::ref(g_chainman.m_blockman), stats, CoinStatsHashType::NONE, RpcInterruptionPoint))) {
statsClient.gauge("utxoset.tx", stats.nTransactions, 1.0f);
statsClient.gauge("utxoset.txOutputs", stats.nTransactionOutputs, 1.0f);
statsClient.gauge("utxoset.dbSizeBytes", stats.nDiskSize, 1.0f);
Expand Down Expand Up @@ -2025,7 +2024,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
node.evodb = std::make_unique<CEvoDB>(nEvoDbCache, false, fReset || fReindexChainState);

chainman.Reset();
chainman.InitializeChainstate(llmq::chainLocksHandler, llmq::quorumInstantSendManager, llmq::quorumBlockProcessor, *node.evodb, *Assert(node.mempool));
chainman.InitializeChainstate(Assert(node.mempool.get()), *node.evodb, llmq::chainLocksHandler, llmq::quorumInstantSendManager, llmq::quorumBlockProcessor);
chainman.m_total_coinstip_cache = nCoinCacheUsage;
chainman.m_total_coinsdb_cache = nCoinDBCache;

Expand Down Expand Up @@ -2057,7 +2056,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
// block file from disk.
// Note that it also sets fReindex based on the disk flag!
// From here on out fReindex and fReset mean something different!
if (!chainman.LoadBlockIndex(chainparams)) {
if (!chainman.LoadBlockIndex()) {
if (ShutdownRequested()) break;
strLoadError = _("Error loading block database");
break;
Expand Down Expand Up @@ -2108,7 +2107,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
// If we're not mid-reindex (based on disk + args), add a genesis block on disk
// (otherwise we use the one already on disk).
// This is called again in ThreadImport after the reindex completes.
if (!fReindex && !::ChainstateActive().LoadGenesisBlock(chainparams)) {
if (!fReindex && !::ChainstateActive().LoadGenesisBlock()) {
strLoadError = _("Error initializing block database");
break;
}
Expand Down Expand Up @@ -2138,7 +2137,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
}

// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!chainstate->ReplayBlocks(chainparams)) {
if (!chainstate->ReplayBlocks()) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
failed_chainstate_init = true;
break;
Expand All @@ -2160,7 +2159,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc

if (!is_coinsview_empty(chainstate)) {
// LoadChainTip initializes the chain based on CoinsTip()'s best block
if (!chainstate->LoadChainTip(chainparams)) {
if (!chainstate->LoadChainTip()) {
strLoadError = _("Error initializing block database");
failed_chainstate_init = true;
break; // out of the per-chainstate loop
Expand Down
5 changes: 2 additions & 3 deletions src/llmq/chainlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,18 +502,17 @@ void CChainLocksHandler::EnforceBestChainLock()
}

BlockValidationState dummy_state;
const auto &params = Params();

// Go backwards through the chain referenced by clsig until we find a block that is part of the main chain.
// For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig
// and mark all of them as conflicting.
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString());
::ChainstateActive().EnforceBlock(dummy_state, params, pindex);
::ChainstateActive().EnforceBlock(dummy_state, pindex);

bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex;

if (activateNeeded) {
if (!::ChainstateActive().ActivateBestChain(dummy_state, params)) {
if (!::ChainstateActive().ActivateBestChain(dummy_state)) {
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, dummy_state.ToString());
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/llmq/instantsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const
BlockValidationState state;
// need non-const pointer
auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash()));
if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) {
if (!::ChainstateActive().InvalidateBlock(state, pindex2)) {
LogPrintf("CInstantSendManager::%s -- InvalidateBlock failed: %s\n", __func__, state.ToString());
// This should not have happened and we are in a state were it's not safe to continue anymore
assert(false);
Expand All @@ -1495,7 +1495,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const

if (activateBestChain) {
BlockValidationState state;
if (!::ChainstateActive().ActivateBestChain(state, Params())) {
if (!::ChainstateActive().ActivateBestChain(state)) {
LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, state.ToString());
// This should not have happened and we are in a state were it's not safe to continue anymore
assert(false);
Expand Down
17 changes: 9 additions & 8 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ BlockAssembler::Options::Options() {

BlockAssembler::BlockAssembler(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
const llmq::CQuorumBlockProcessor& quorumBlockProcessor, llmq::CChainLocksHandler& clhandler,
llmq::CInstantSendManager& isman, CEvoDB& evoDb, const CTxMemPool& mempool, const CChainParams& params, const Options& options) :
llmq::CInstantSendManager& isman, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options) :
chainparams(params),
m_mempool(mempool),
m_chainstate(chainstate),
spork_manager(sporkManager),
governance_manager(governanceManager),
quorum_block_processor(quorumBlockProcessor),
Expand Down Expand Up @@ -91,8 +92,8 @@ static BlockAssembler::Options DefaultOptions()

BlockAssembler::BlockAssembler(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
const llmq::CQuorumBlockProcessor& quorumBlockProcessor, llmq::CChainLocksHandler& clhandler,
llmq::CInstantSendManager& isman, CEvoDB& evoDb, const CTxMemPool& mempool, const CChainParams& params)
: BlockAssembler(sporkManager, governanceManager, quorumBlockProcessor, clhandler, isman, evoDb, mempool, params, DefaultOptions()) {}
llmq::CInstantSendManager& isman, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params)
: BlockAssembler(sporkManager, governanceManager, quorumBlockProcessor, clhandler, isman, evoDb, chainstate, mempool, params, DefaultOptions()) {}

void BlockAssembler::resetBlock()
{
Expand All @@ -107,7 +108,7 @@ void BlockAssembler::resetBlock()
nFees = 0;
}

std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn)
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
{
int64_t nTimeStart = GetTimeMicros();

Expand All @@ -125,8 +126,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
pblocktemplate->vTxSigOps.push_back(-1); // updated at end

LOCK2(cs_main, m_mempool.cs);
assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*chainstate.m_chain.Tip()));
CBlockIndex* pindexPrev = chainstate.m_chain.Tip();
assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*m_chainstate.m_chain.Tip()));
CBlockIndex* pindexPrev = m_chainstate.m_chain.Tip();
assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;

Expand Down Expand Up @@ -243,9 +244,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
pblocktemplate->nPrevBits = pindexPrev->nBits;
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]);

assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
BlockValidationState state;
if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, chainstate, *pblock, pindexPrev, false, false)) {
assert(std::addressof(::ChainstateActive()) == std::addressof(m_chainstate));
if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
}
int64_t nTime2 = GetTimeMicros();
Expand Down
Loading