aboutsummaryrefslogtreecommitdiff
path: root/src/validation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/validation.cpp')
-rw-r--r--src/validation.cpp147
1 files changed, 47 insertions, 100 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index d4463bf17b..8c87c53ac7 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -384,7 +384,7 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
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);
@@ -463,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
@@ -558,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
@@ -692,7 +690,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
// Check for non-standard pay-to-script-hash in inputs
- if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
+ const auto& params = args.m_chainparams.GetConsensus();
+ auto taproot_state = VersionBitsState(::ChainActive().Tip(), params, Consensus::DEPLOYMENT_TAPROOT, versionbitscache);
+ if (fRequireStandard && !AreInputsStandard(tx, m_view, taproot_state == ThresholdState::ACTIVE)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
}
@@ -729,10 +729,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) {
@@ -1065,10 +1061,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, CAmount* fee_out=nullptr) 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, fee_out };
+ 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;
@@ -1087,10 +1083,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, CAmount* fee_out)
+ 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, fee_out);
+ 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)
@@ -1316,8 +1312,6 @@ bool CChainState::IsInitialBlockDownload() const
return false;
}
-static CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
-
static void AlertNotify(const std::string& strMessage)
{
uiInterface.NotifyAlertChanged();
@@ -1343,73 +1337,16 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
// (we assume we don't get stuck on a fork before finishing our initial sync)
- if (::ChainstateActive().IsInitialBlockDownload())
+ if (::ChainstateActive().IsInitialBlockDownload()) {
return;
-
- // If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
- // of our head, drop it
- if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72)
- pindexBestForkTip = nullptr;
-
- if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6)))
- {
- if (!GetfLargeWorkForkFound() && pindexBestForkBase)
- {
- std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
- pindexBestForkBase->phashBlock->ToString() + std::string("'");
- AlertNotify(warning);
- }
- if (pindexBestForkTip && pindexBestForkBase)
- {
- LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__,
- pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(),
- pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString());
- SetfLargeWorkForkFound(true);
- }
- else
- {
- LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__);
- SetfLargeWorkInvalidChainFound(true);
- }
- }
- else
- {
- SetfLargeWorkForkFound(false);
- SetfLargeWorkInvalidChainFound(false);
}
-}
-static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
-{
- AssertLockHeld(cs_main);
- // If we are on a fork that is sufficiently large, set a warning flag
- CBlockIndex* pfork = pindexNewForkTip;
- CBlockIndex* plonger = ::ChainActive().Tip();
- while (pfork && pfork != plonger)
- {
- while (plonger && plonger->nHeight > pfork->nHeight)
- plonger = plonger->pprev;
- if (pfork == plonger)
- break;
- pfork = pfork->pprev;
- }
-
- // We define a condition where we should warn the user about as a fork of at least 7 blocks
- // with a tip within 72 blocks (+/- 12 hours if no one mines it) of ours
- // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network
- // hash rate operating on the fork.
- // or a chain that is entirely longer than ours and invalid (note that this should be detected by both)
- // We define it this way because it allows us to only store the highest fork tip (+ base) which meets
- // the 7-block condition and from this always have the most-likely-to-cause-warning fork
- if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) &&
- pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) &&
- ::ChainActive().Height() - pindexNewForkTip->nHeight < 72)
- {
- pindexBestForkTip = pindexNewForkTip;
- pindexBestForkBase = pfork;
+ if (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6)) {
+ LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__);
+ SetfLargeWorkInvalidChainFound(true);
+ } else {
+ SetfLargeWorkInvalidChainFound(false);
}
-
- CheckForkWarningConditions();
}
// Called both upon regular invalid block discovery *and* InvalidateBlock
@@ -1538,14 +1475,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
@@ -1554,7 +1498,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());
@@ -1568,7 +1512,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())));
@@ -1913,6 +1857,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;
@@ -2449,9 +2398,9 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C
}
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);
@@ -2470,11 +2419,9 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C
{
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,
@@ -2482,6 +2429,10 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C
FormatISO8601DateTime(pindexNew->GetBlockTime()),
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.
@@ -2736,8 +2687,8 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
AssertLockHeld(cs_main);
AssertLockHeld(m_mempool.cs);
- const CBlockIndex *pindexOldTip = m_chain.Tip();
- const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork);
+ const CBlockIndex* pindexOldTip = m_chain.Tip();
+ const CBlockIndex* pindexFork = m_chain.FindFork(pindexMostWork);
// Disconnect active blocks which are no longer in the best chain.
bool fBlocksDisconnected = false;
@@ -2757,7 +2708,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
fBlocksDisconnected = true;
}
- // Build list of new blocks to connect.
+ // Build list of new blocks to connect (in descending height order).
std::vector<CBlockIndex*> vpindexToConnect;
bool fContinue = true;
int nHeight = pindexFork ? pindexFork->nHeight : -1;
@@ -2767,7 +2718,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight);
vpindexToConnect.clear();
vpindexToConnect.reserve(nTargetHeight - nHeight);
- CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight);
+ CBlockIndex* pindexIter = pindexMostWork->GetAncestor(nTargetHeight);
while (pindexIter && pindexIter->nHeight != nHeight) {
vpindexToConnect.push_back(pindexIter);
pindexIter = pindexIter->pprev;
@@ -2775,7 +2726,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
nHeight = nTargetHeight;
// Connect new blocks.
- for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) {
+ for (CBlockIndex* pindexConnect : reverse_iterate(vpindexToConnect)) {
if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
@@ -2811,11 +2762,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
}
m_mempool.check(&CoinsTip());
- // Callbacks/notifications for a new best chain.
- if (fInvalidFound)
- CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());
- else
- CheckForkWarningConditions();
+ CheckForkWarningConditions();
return true;
}
@@ -5074,10 +5021,10 @@ bool LoadMempool(CTxMemPool& pool)
pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
}
TxValidationState state;
- if (nTime + nExpiryTimeout > nNow) {
+ if (nTime > nNow - nExpiryTimeout) {
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;