aboutsummaryrefslogtreecommitdiff
path: root/src/validation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/validation.cpp')
-rw-r--r--src/validation.cpp258
1 files changed, 124 insertions, 134 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index cf2f9dde62..423b93479a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -33,6 +33,7 @@
#include <script/script.h>
#include <script/sigcache.h>
#include <shutdown.h>
+#include <signet.h>
#include <timedata.h>
#include <tinyformat.h>
#include <txdb.h>
@@ -148,7 +149,6 @@ arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CBlockPolicyEstimator feeEstimator;
-CTxMemPool mempool(&feeEstimator);
// Internal stuff
namespace {
@@ -198,9 +198,6 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
std::unique_ptr<CBlockTreeDB> pblocktree;
-// See definition for documentation
-static void FindFilesToPruneManual(ChainstateManager& chainman, std::set<int>& setFilesToPrune, int nManualPruneHeight);
-static void FindFilesToPrune(ChainstateManager& chainman, std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false);
static FlatFileSeq BlockFileSeq();
@@ -370,9 +367,10 @@ static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
* and instead just erase from the mempool as needed.
*/
-static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs)
+static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, mempool.cs)
{
AssertLockHeld(cs_main);
+ AssertLockHeld(mempool.cs);
std::vector<uint256> vHashUpdate;
// disconnectpool's insertion_order index sorts the entries from
// oldest to newest, but the oldest entry will be the last tx from the
@@ -386,7 +384,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
TxValidationState stateDummy;
if (!fAddToMempool || (*it)->IsCoinBase() ||
!AcceptToMemoryPool(mempool, stateDummy, *it,
- nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ nullptr /* plTxnReplaced */, true /* bypass_limits */)) {
// If the transaction doesn't make it in to the mempool, remove any
// transactions that depend on it (which would now be orphans).
mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
@@ -465,7 +463,6 @@ public:
const int64_t m_accept_time;
std::list<CTransactionRef>* m_replaced_transactions;
const bool m_bypass_limits;
- const CAmount& m_absurd_fee;
/*
* Return any outpoints which were not previously present in the coins
* cache, but were added as a result of validating the tx for mempool
@@ -475,6 +472,7 @@ public:
*/
std::vector<COutPoint>& m_coins_to_uncache;
const bool m_test_accept;
+ CAmount* m_fee_out;
};
// Single transaction acceptance
@@ -559,7 +557,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
TxValidationState &state = args.m_state;
const int64_t nAcceptTime = args.m_accept_time;
const bool bypass_limits = args.m_bypass_limits;
- const CAmount& nAbsurdFee = args.m_absurd_fee;
std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache;
// Alias what we need out of ws
@@ -687,6 +684,11 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return false; // state filled in by CheckTxInputs
}
+ // If fee_out is passed, return the fee to the caller
+ if (args.m_fee_out) {
+ *args.m_fee_out = nFees;
+ }
+
// Check for non-standard pay-to-script-hash in inputs
if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
@@ -725,10 +727,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// blocks
if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false;
- if (nAbsurdFee && nFees > nAbsurdFee)
- return state.Invalid(TxValidationResult::TX_NOT_STANDARD,
- "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
-
const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts);
// Calculate in-mempool ancestors, up to a limit.
if (setConflicts.size() == 1) {
@@ -1051,7 +1049,7 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
if (!Finalize(args, workspace)) return false;
- GetMainSignals().TransactionAddedToMempool(ptx);
+ GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
return true;
}
@@ -1061,10 +1059,10 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
/** (try to) add transaction to memory pool with a specified acceptance time **/
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ bool bypass_limits, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
std::vector<COutPoint> coins_to_uncache;
- MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept };
+ MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, coins_to_uncache, test_accept, fee_out };
bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
if (!res) {
// Remove coins that were not present in the coins cache before calling ATMPW;
@@ -1083,10 +1081,10 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept)
+ bool bypass_limits, bool test_accept, CAmount* fee_out)
{
const CChainParams& chainparams = Params();
- return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept);
+ return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, test_accept, fee_out);
}
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
@@ -1163,6 +1161,11 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
+ // Signet only: check block solution
+ if (consensusParams.signet_blocks && !CheckSignetBlockSolution(block, consensusParams)) {
+ return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString());
+ }
+
return true;
}
@@ -1254,8 +1257,9 @@ void CoinsViews::InitCache()
m_cacheview = MakeUnique<CCoinsViewCache>(&m_catcherview);
}
-CChainState::CChainState(BlockManager& blockman, uint256 from_snapshot_blockhash)
+CChainState::CChainState(CTxMemPool& mempool, BlockManager& blockman, uint256 from_snapshot_blockhash)
: m_blockman(blockman),
+ m_mempool(mempool),
m_from_snapshot_blockhash(from_snapshot_blockhash) {}
void CChainState::InitCoinsDB(
@@ -1528,14 +1532,21 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
return true;
}
- if (!txdata.m_ready) {
- txdata.Init(tx);
+ if (!txdata.m_spent_outputs_ready) {
+ std::vector<CTxOut> spent_outputs;
+ spent_outputs.reserve(tx.vin.size());
+
+ for (const auto& txin : tx.vin) {
+ const COutPoint& prevout = txin.prevout;
+ const Coin& coin = inputs.AccessCoin(prevout);
+ assert(!coin.IsSpent());
+ spent_outputs.emplace_back(coin.out);
+ }
+ txdata.Init(tx, std::move(spent_outputs));
}
+ assert(txdata.m_spent_outputs.size() == tx.vin.size());
for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const COutPoint &prevout = tx.vin[i].prevout;
- const Coin& coin = inputs.AccessCoin(prevout);
- assert(!coin.IsSpent());
// We very carefully only pass in things to CScriptCheck which
// are clearly committed to by tx' witness hash. This provides
@@ -1544,7 +1555,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
// spent being checked as a part of CScriptCheck.
// Verify signature
- CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata);
+ CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -1558,7 +1569,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
// splitting the network between upgraded and
// non-upgraded nodes by banning CONSENSUS-failing
// data providers.
- CScriptCheck check2(coin.out, tx, i,
+ CScriptCheck check2(txdata.m_spent_outputs[i], tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
if (check2())
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
@@ -1903,6 +1914,11 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
}
+ // Start enforcing Taproot using versionbits logic.
+ if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_TAPROOT, versionbitscache) == ThresholdState::ACTIVE) {
+ flags |= SCRIPT_VERIFY_TAPROOT;
+ }
+
// Start enforcing BIP147 NULLDUMMY (activated simultaneously with segwit)
if (IsWitnessEnabled(pindex->pprev, consensusparams)) {
flags |= SCRIPT_VERIFY_NULLDUMMY;
@@ -2280,17 +2296,17 @@ bool CChainState::FlushStateToDisk(
{
bool fFlushForPrune = false;
bool fDoFullFlush = false;
- CoinsCacheSizeState cache_state = GetCoinsCacheSizeState(&::mempool);
+ CoinsCacheSizeState cache_state = GetCoinsCacheSizeState(&m_mempool);
LOCK(cs_LastBlockFile);
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
if (nManualPruneHeight > 0) {
LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune (manual)", BCLog::BENCH);
- FindFilesToPruneManual(g_chainman, setFilesToPrune, nManualPruneHeight);
+ m_blockman.FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight, m_chain.Height());
} else {
LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH);
- FindFilesToPrune(g_chainman, setFilesToPrune, chainparams.PruneAfterHeight());
+ m_blockman.FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight(), m_chain.Height(), IsInitialBlockDownload());
fCheckForPruning = false;
}
if (!setFilesToPrune.empty()) {
@@ -2426,7 +2442,7 @@ static void AppendWarning(bilingual_str& res, const bilingual_str& warn)
}
/** Check warning conditions and do some notifications on new chain tip set. */
-void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainParams)
+static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const CChainParams& chainParams)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
// New best block
@@ -2439,9 +2455,9 @@ void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainPar
}
bilingual_str warning_messages;
+ int num_unexpected_version = 0;
if (!::ChainstateActive().IsInitialBlockDownload())
{
- int nUpgraded = 0;
const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
@@ -2460,11 +2476,9 @@ void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainPar
{
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0)
- ++nUpgraded;
+ ++num_unexpected_version;
pindex = pindex->pprev;
}
- if (nUpgraded > 0)
- AppendWarning(warning_messages, strprintf(_("%d of last 100 blocks have unexpected version"), nUpgraded));
}
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
@@ -2473,6 +2487,9 @@ void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainPar
GuessVerificationProgress(chainParams.TxData(), pindexNew), ::ChainstateActive().CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), ::ChainstateActive().CoinsTip().GetCacheSize(),
!warning_messages.empty() ? strprintf(" warning='%s'", warning_messages.original) : "");
+ if (num_unexpected_version > 0) {
+ LogPrint(BCLog::VALIDATION, "%d of last 100 blocks have unexpected version\n", num_unexpected_version);
+ }
}
/** Disconnect m_chain's tip.
@@ -2485,8 +2502,11 @@ void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainPar
* disconnectpool (note that the caller is responsible for mempool consistency
* in any case).
*/
-bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
+bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool)
{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(m_mempool.cs);
+
CBlockIndex *pindexDelete = m_chain.Tip();
assert(pindexDelete);
// Read block from disk.
@@ -2517,14 +2537,14 @@ bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams&
while (disconnectpool->DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE * 1000) {
// Drop the earliest entry, and remove its children from the mempool.
auto it = disconnectpool->queuedTx.get<insertion_order>().begin();
- mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
+ m_mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
disconnectpool->removeEntry(it);
}
}
m_chain.SetTip(pindexDelete->pprev);
- UpdateTip(pindexDelete->pprev, chainparams);
+ UpdateTip(m_mempool, pindexDelete->pprev, chainparams);
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
GetMainSignals().BlockDisconnected(pblock, pindexDelete);
@@ -2585,6 +2605,9 @@ public:
*/
bool CChainState::ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(m_mempool.cs);
+
assert(pindexNew->pprev == m_chain.Tip());
// Read block from disk.
int64_t nTime1 = GetTimeMicros();
@@ -2625,11 +2648,11 @@ bool CChainState::ConnectTip(BlockValidationState& state, const CChainParams& ch
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
// Remove conflicting transactions from the mempool.;
- mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
+ m_mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
disconnectpool.removeForBlock(blockConnecting.vtx);
// Update m_chain & related variables.
m_chain.SetTip(pindexNew);
- UpdateTip(pindexNew, chainparams);
+ UpdateTip(m_mempool, pindexNew, chainparams);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal);
@@ -2719,6 +2742,7 @@ void CChainState::PruneBlockIndexCandidates() {
bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
{
AssertLockHeld(cs_main);
+ AssertLockHeld(m_mempool.cs);
const CBlockIndex *pindexOldTip = m_chain.Tip();
const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork);
@@ -2730,7 +2754,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
if (!DisconnectTip(state, chainparams, &disconnectpool)) {
// This is likely a fatal error, but keep the mempool consistent,
// just in case. Only remove from the mempool in this case.
- UpdateMempoolForReorg(disconnectpool, false);
+ UpdateMempoolForReorg(m_mempool, disconnectpool, false);
// If we're unable to disconnect a block during normal operation,
// then that is a failure of our local system -- we should abort
@@ -2774,7 +2798,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
// A system error occurred (disk space, database error, ...).
// Make the mempool consistent with the current tip, just in case
// any observers try to use it before shutdown.
- UpdateMempoolForReorg(disconnectpool, false);
+ UpdateMempoolForReorg(m_mempool, disconnectpool, false);
return false;
}
} else {
@@ -2791,9 +2815,9 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
if (fBlocksDisconnected) {
// If any blocks were disconnected, disconnectpool may be non empty. Add
// any disconnected transactions back to the mempool.
- UpdateMempoolForReorg(disconnectpool, true);
+ UpdateMempoolForReorg(m_mempool, disconnectpool, true);
}
- mempool.check(&CoinsTip());
+ m_mempool.check(&CoinsTip());
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
@@ -2867,7 +2891,8 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar
LimitValidationInterfaceQueue();
{
- LOCK2(cs_main, ::mempool.cs); // Lock transaction pool for at least as long as it takes for connectTrace to be consumed
+ LOCK(cs_main);
+ LOCK(m_mempool.cs); // Lock transaction pool for at least as long as it takes for connectTrace to be consumed
CBlockIndex* starting_tip = m_chain.Tip();
bool blocks_connected = false;
do {
@@ -3020,7 +3045,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParam
LimitValidationInterfaceQueue();
LOCK(cs_main);
- LOCK(::mempool.cs); // Lock for as long as disconnectpool is in scope to make sure UpdateMempoolForReorg is called after DisconnectTip without unlocking in between
+ LOCK(m_mempool.cs); // Lock for as long as disconnectpool is in scope to make sure UpdateMempoolForReorg is called after DisconnectTip without unlocking in between
if (!m_chain.Contains(pindex)) break;
pindex_was_in_chain = true;
CBlockIndex *invalid_walk_tip = m_chain.Tip();
@@ -3034,7 +3059,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParam
// transactions back to the mempool if disconnecting was successful,
// and we're not doing a very deep invalidation (in which case
// keeping the mempool up to date is probably futile anyway).
- UpdateMempoolForReorg(disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret);
+ UpdateMempoolForReorg(m_mempool, disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret);
if (!ret) return false;
assert(invalid_walk_tip->pprev == m_chain.Tip());
@@ -3332,6 +3357,11 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
return false;
+ // Signet only: check block solution
+ if (consensusParams.signet_blocks && fCheckPOW && !CheckSignetBlockSolution(block, consensusParams)) {
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-signet-blksig", "signet block signature validation failure");
+ }
+
// Check the merkle root.
if (fCheckMerkleRoot) {
bool mutated;
@@ -3395,31 +3425,11 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
return (height >= params.SegwitHeight);
}
-int GetWitnessCommitmentIndex(const CBlock& block)
-{
- int commitpos = -1;
- if (!block.vtx.empty()) {
- for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
- const CTxOut& vout = block.vtx[0]->vout[o];
- if (vout.scriptPubKey.size() >= MINIMUM_WITNESS_COMMITMENT &&
- vout.scriptPubKey[0] == OP_RETURN &&
- vout.scriptPubKey[1] == 0x24 &&
- vout.scriptPubKey[2] == 0xaa &&
- vout.scriptPubKey[3] == 0x21 &&
- vout.scriptPubKey[4] == 0xa9 &&
- vout.scriptPubKey[5] == 0xed) {
- commitpos = o;
- }
- }
- }
- return commitpos;
-}
-
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams)
{
int commitpos = GetWitnessCommitmentIndex(block);
static const std::vector<unsigned char> nonce(32, 0x00);
- if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness()) {
+ if (commitpos != NO_WITNESS_COMMITMENT && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness()) {
CMutableTransaction tx(*block.vtx[0]);
tx.vin[0].scriptWitness.stack.resize(1);
tx.vin[0].scriptWitness.stack[0] = nonce;
@@ -3433,7 +3443,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
int commitpos = GetWitnessCommitmentIndex(block);
std::vector<unsigned char> ret(32, 0x00);
if (consensusParams.SegwitHeight != std::numeric_limits<int>::max()) {
- if (commitpos == -1) {
+ if (commitpos == NO_WITNESS_COMMITMENT) {
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
CHash256().Write(witnessroot).Write(ret).Finalize(witnessroot);
CTxOut out;
@@ -3571,7 +3581,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
bool fHaveWitness = false;
if (nHeight >= consensusParams.SegwitHeight) {
int commitpos = GetWitnessCommitmentIndex(block);
- if (commitpos != -1) {
+ if (commitpos != NO_WITNESS_COMMITMENT) {
bool malleated = false;
uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated);
// The malleation check is ignored; as the transaction tree itself
@@ -3904,12 +3914,12 @@ uint64_t CalculateCurrentUsage()
return retval;
}
-void ChainstateManager::PruneOneBlockFile(const int fileNumber)
+void BlockManager::PruneOneBlockFile(const int fileNumber)
{
AssertLockHeld(cs_main);
LOCK(cs_LastBlockFile);
- for (const auto& entry : m_blockman.m_block_index) {
+ for (const auto& entry : m_block_index) {
CBlockIndex* pindex = entry.second;
if (pindex->nFile == fileNumber) {
pindex->nStatus &= ~BLOCK_HAVE_DATA;
@@ -3923,12 +3933,12 @@ void ChainstateManager::PruneOneBlockFile(const int fileNumber)
// to be downloaded again in order to consider its chain, at which
// point it would be considered as a candidate for
// m_blocks_unlinked or setBlockIndexCandidates.
- auto range = m_blockman.m_blocks_unlinked.equal_range(pindex->pprev);
+ auto range = m_blocks_unlinked.equal_range(pindex->pprev);
while (range.first != range.second) {
std::multimap<CBlockIndex *, CBlockIndex *>::iterator _it = range.first;
range.first++;
if (_it->second == pindex) {
- m_blockman.m_blocks_unlinked.erase(_it);
+ m_blocks_unlinked.erase(_it);
}
}
}
@@ -3949,22 +3959,23 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
}
}
-/* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */
-static void FindFilesToPruneManual(ChainstateManager& chainman, std::set<int>& setFilesToPrune, int nManualPruneHeight)
+void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height)
{
assert(fPruneMode && nManualPruneHeight > 0);
LOCK2(cs_main, cs_LastBlockFile);
- if (::ChainActive().Tip() == nullptr)
+ if (chain_tip_height < 0) {
return;
+ }
// last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)
- unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP);
- int count=0;
+ unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP);
+ int count = 0;
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {
- if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
+ if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
continue;
- chainman.PruneOneBlockFile(fileNumber);
+ }
+ PruneOneBlockFile(fileNumber);
setFilesToPrune.insert(fileNumber);
count++;
}
@@ -3982,46 +3993,31 @@ void PruneBlockFilesManual(int nManualPruneHeight)
}
}
-/**
- * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target.
- * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new
- * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex
- * (which in this case means the blockchain must be re-downloaded.)
- *
- * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set.
- * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)
- * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest).
- * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.
- * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.
- * A db flag records the fact that at least some block files have been pruned.
- *
- * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned
- */
-static void FindFilesToPrune(ChainstateManager& chainman, std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight)
+void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, bool is_ibd)
{
LOCK2(cs_main, cs_LastBlockFile);
- if (::ChainActive().Tip() == nullptr || nPruneTarget == 0) {
+ if (chain_tip_height < 0 || nPruneTarget == 0) {
return;
}
- if ((uint64_t)::ChainActive().Tip()->nHeight <= nPruneAfterHeight) {
+ if ((uint64_t)chain_tip_height <= nPruneAfterHeight) {
return;
}
- unsigned int nLastBlockWeCanPrune = ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP;
+ unsigned int nLastBlockWeCanPrune = chain_tip_height - MIN_BLOCKS_TO_KEEP;
uint64_t nCurrentUsage = CalculateCurrentUsage();
// We don't check to prune until after we've allocated new space for files
// So we should leave a buffer under our target to account for another allocation
// before the next pruning.
uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE;
uint64_t nBytesToPrune;
- int count=0;
+ int count = 0;
if (nCurrentUsage + nBuffer >= nPruneTarget) {
// On a prune event, the chainstate DB is flushed.
// To avoid excessive prune events negating the benefit of high dbcache
// values, we should not prune too rapidly.
// So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
- if (::ChainstateActive().IsInitialBlockDownload()) {
+ if (is_ibd) {
// Since this is only relevant during IBD, we use a fixed 10%
nBuffer += nPruneTarget / 10;
}
@@ -4029,17 +4025,20 @@ static void FindFilesToPrune(ChainstateManager& chainman, std::set<int>& setFile
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {
nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize;
- if (vinfoBlockFile[fileNumber].nSize == 0)
+ if (vinfoBlockFile[fileNumber].nSize == 0) {
continue;
+ }
- if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target?
+ if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target?
break;
+ }
// don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
- if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
+ if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
continue;
+ }
- chainman.PruneOneBlockFile(fileNumber);
+ PruneOneBlockFile(fileNumber);
// Queue up the files for removal
setFilesToPrune.insert(fileNumber);
nCurrentUsage -= nBytesToPrune;
@@ -4218,6 +4217,14 @@ bool static LoadBlockIndexDB(ChainstateManager& chainman, const CChainParams& ch
return true;
}
+void CChainState::LoadMempool(const ArgsManager& args)
+{
+ if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ ::LoadMempool(m_mempool);
+ }
+ m_mempool.SetIsLoaded(!ShutdownRequested());
+}
+
bool CChainState::LoadChainTip(const CChainParams& chainparams)
{
AssertLockHeld(cs_main);
@@ -4517,7 +4524,8 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
// Loop until the tip is below nHeight, or we reach a pruned block.
while (!ShutdownRequested()) {
{
- LOCK2(cs_main, ::mempool.cs);
+ LOCK(cs_main);
+ LOCK(m_mempool.cs);
// Make sure nothing changed from under us (this won't happen because RewindBlockIndex runs before importing/network are active)
assert(tip == m_chain.Tip());
if (tip == nullptr || tip->nHeight < nHeight) break;
@@ -4588,10 +4596,10 @@ void CChainState::UnloadBlockIndex() {
// May NOT be used after any connections are up as much
// of the peer-processing logic assumes a consistent
// block index state
-void UnloadBlockIndex(CTxMemPool* mempool)
+void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
{
LOCK(cs_main);
- g_chainman.Unload();
+ chainman.Unload();
pindexBestInvalid = nullptr;
pindexBestHeader = nullptr;
if (mempool) mempool->clear();
@@ -5077,7 +5085,7 @@ bool LoadMempool(CTxMemPool& pool)
if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nTime,
- nullptr /* plTxnReplaced */, false /* bypass_limits */, 0 /* nAbsurdFee */,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */,
false /* test_accept */);
if (state.IsValid()) {
++count;
@@ -5106,7 +5114,7 @@ bool LoadMempool(CTxMemPool& pool)
}
// TODO: remove this try except in v0.22
- std::map<uint256, uint256> unbroadcast_txids;
+ std::set<uint256> unbroadcast_txids;
try {
file >> unbroadcast_txids;
unbroadcast = unbroadcast_txids.size();
@@ -5114,13 +5122,10 @@ bool LoadMempool(CTxMemPool& pool)
// mempool.dat files created prior to v0.21 will not have an
// unbroadcast set. No need to log a failure if parsing fails here.
}
- for (const auto& elem : unbroadcast_txids) {
- // Don't add unbroadcast transactions that didn't get back into the
- // mempool.
- const CTransactionRef& added_tx = pool.get(elem.first);
- if (added_tx != nullptr) {
- pool.AddUnbroadcastTx(elem.first, added_tx->GetWitnessHash());
- }
+ for (const auto& txid : unbroadcast_txids) {
+ // Ensure transactions were accepted to mempool then add to
+ // unbroadcast set.
+ if (pool.get(txid) != nullptr) pool.AddUnbroadcastTx(txid);
}
} catch (const std::exception& e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
@@ -5137,7 +5142,7 @@ bool DumpMempool(const CTxMemPool& pool)
std::map<uint256, CAmount> mapDeltas;
std::vector<TxMempoolInfo> vinfo;
- std::map<uint256, uint256> unbroadcast_txids;
+ std::set<uint256> unbroadcast_txids;
static Mutex dump_mutex;
LOCK(dump_mutex);
@@ -5209,20 +5214,6 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin
return std::min<double>(pindex->nChainTx / fTxTotal, 1.0);
}
-class CMainCleanup
-{
-public:
- CMainCleanup() {}
- ~CMainCleanup() {
- // block headers
- BlockMap::iterator it1 = g_chainman.BlockIndex().begin();
- for (; it1 != g_chainman.BlockIndex().end(); it1++)
- delete (*it1).second;
- g_chainman.BlockIndex().clear();
- }
-};
-static CMainCleanup instance_of_cmaincleanup;
-
Optional<uint256> ChainstateManager::SnapshotBlockhash() const {
if (m_active_chainstate != nullptr) {
// If a snapshot chainstate exists, it will always be our active.
@@ -5246,7 +5237,7 @@ std::vector<CChainState*> ChainstateManager::GetAll()
return out;
}
-CChainState& ChainstateManager::InitializeChainstate(const uint256& snapshot_blockhash)
+CChainState& ChainstateManager::InitializeChainstate(CTxMemPool& mempool, const uint256& snapshot_blockhash)
{
bool is_snapshot = !snapshot_blockhash.IsNull();
std::unique_ptr<CChainState>& to_modify =
@@ -5255,8 +5246,7 @@ CChainState& ChainstateManager::InitializeChainstate(const uint256& snapshot_blo
if (to_modify) {
throw std::logic_error("should not be overwriting a chainstate");
}
-
- to_modify.reset(new CChainState(m_blockman, snapshot_blockhash));
+ to_modify.reset(new CChainState(mempool, m_blockman, snapshot_blockhash));
// Snapshot chainstates and initial IBD chaintates always become active.
if (is_snapshot || (!is_snapshot && !m_active_chainstate)) {