Changeset View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 304 Lines • ▼ Show 20 Lines | static bool IsCurrentForFeeEstimation() { | ||||
return true; | return true; | ||||
} | } | ||||
static bool IsMagneticAnomalyEnabledForCurrentBlock(const Config &config) { | static bool IsMagneticAnomalyEnabledForCurrentBlock(const Config &config) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
return IsMagneticAnomalyEnabled(config, chainActive.Tip()); | return IsMagneticAnomalyEnabled(config, chainActive.Tip()); | ||||
} | } | ||||
static bool IsGreatWallEnabledForCurrentBlock(const Config &config) { | |||||
AssertLockHeld(cs_main); | |||||
return IsGreatWallEnabled(config, chainActive.Tip()); | |||||
} | |||||
// Command-line argument "-replayprotectionactivationtime=<timestamp>" will | // Command-line argument "-replayprotectionactivationtime=<timestamp>" will | ||||
// cause the node to switch to replay protected SigHash ForkID value when the | // cause the node to switch to replay protected SigHash ForkID value when the | ||||
// median timestamp of the previous 11 blocks is greater than or equal to | // median timestamp of the previous 11 blocks is greater than or equal to | ||||
// <timestamp>. Defaults to the pre-defined timestamp when not set. | // <timestamp>. Defaults to the pre-defined timestamp when not set. | ||||
static bool IsReplayProtectionEnabled(const Config &config, | static bool IsReplayProtectionEnabled(const Config &config, | ||||
int64_t nMedianTimePast) { | int64_t nMedianTimePast) { | ||||
return nMedianTimePast >= | return nMedianTimePast >= | ||||
gArgs.GetArg( | gArgs.GetArg( | ||||
▲ Show 20 Lines • Show All 309 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
if (IsReplayProtectionEnabledForCurrentBlock(config)) { | if (IsReplayProtectionEnabledForCurrentBlock(config)) { | ||||
extraFlags |= SCRIPT_ENABLE_REPLAY_PROTECTION; | extraFlags |= SCRIPT_ENABLE_REPLAY_PROTECTION; | ||||
} | } | ||||
if (IsMagneticAnomalyEnabledForCurrentBlock(config)) { | if (IsMagneticAnomalyEnabledForCurrentBlock(config)) { | ||||
extraFlags |= SCRIPT_ENABLE_CHECKDATASIG; | extraFlags |= SCRIPT_ENABLE_CHECKDATASIG; | ||||
} | } | ||||
if (IsGreatWallEnabledForCurrentBlock(config)) { | |||||
extraFlags |= SCRIPT_ENABLE_SCHNORR; | |||||
} | |||||
// Check inputs based on the set of flags we activate. | // Check inputs based on the set of flags we activate. | ||||
uint32_t scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; | uint32_t scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; | ||||
if (!config.GetChainParams().RequireStandard()) { | if (!config.GetChainParams().RequireStandard()) { | ||||
scriptVerifyFlags = | scriptVerifyFlags = | ||||
SCRIPT_ENABLE_SIGHASH_FORKID | | SCRIPT_ENABLE_SIGHASH_FORKID | | ||||
gArgs.GetArg("-promiscuousmempoolflags", scriptVerifyFlags); | gArgs.GetArg("-promiscuousmempoolflags", scriptVerifyFlags); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 544 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
// script verification check, such as non-standard DER encodings | // script verification check, such as non-standard DER encodings | ||||
// or non-null dummy arguments; if so, don't trigger DoS | // or non-null dummy arguments; if so, don't trigger DoS | ||||
// protection to avoid splitting the network between upgraded | // protection to avoid splitting the network between upgraded | ||||
// and non-upgraded nodes. | // and non-upgraded nodes. | ||||
// | // | ||||
// We also check activating the monolith opcodes as it is a | // We also check activating the monolith opcodes as it is a | ||||
// strictly additive change and we would not like to ban some of | // strictly additive change and we would not like to ban some of | ||||
// our peer that are ahead of us and are considering the fork | // our peer that are ahead of us and are considering the fork | ||||
// as activated. | // as activated. | ||||
deadalnix: Interesting, this comment is not actually accurate, but give some hints about what needs to… | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsOne step ahead of you https://reviews.bitcoinabc.org/D2511 :-) markblundeberg: One step ahead of you https://reviews.bitcoinabc.org/D2511 :-) | |||||
CScriptCheck check2(scriptPubKey, amount, tx, i, | CScriptCheck check2(scriptPubKey, amount, tx, i, | ||||
flags & | flags & | ||||
~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, | ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, | ||||
sigCacheStore, txdata); | sigCacheStore, txdata); | ||||
if (check2()) { | if (check2()) { | ||||
return state.Invalid( | return state.Invalid( | ||||
false, REJECT_NONSTANDARD, | false, REJECT_NONSTANDARD, | ||||
strprintf("non-mandatory-script-verify-flag (%s)", | strprintf("non-mandatory-script-verify-flag (%s)", | ||||
ScriptErrorString(check.GetScriptError()))); | ScriptErrorString(check.GetScriptError()))); | ||||
} | } | ||||
} | } | ||||
// We also, regardless, need to check whether the transaction would | |||||
// be valid on the other side of the upgrade, so as to avoid | |||||
// splitting the network between upgraded and non-upgraded nodes. | |||||
// Note that this will create strange error messages like | |||||
// "non-mandatory-script-verify-flag (Non-canonical DER signature)" | |||||
// -- the tx was refused entry due to STRICTENC, a mandatory flag, | |||||
// but after the upgrade the signature would have been interpreted | |||||
// as valid Schnorr and thus STRICTENC would not happen. | |||||
CScriptCheck check3(scriptPubKey, amount, tx, i, | |||||
(flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) ^ | |||||
SCRIPT_ENABLE_SCHNORR, | |||||
sigCacheStore, txdata); | |||||
if (check3()) { | |||||
return state.Invalid( | |||||
false, REJECT_NONSTANDARD, | |||||
strprintf("non-mandatory-script-verify-flag (%s)", | |||||
ScriptErrorString(check.GetScriptError()))); | |||||
} | |||||
// Failures of other flags indicate a transaction that is invalid in | // Failures of other flags indicate a transaction that is invalid in | ||||
// new blocks, e.g. a invalid P2SH. We DoS ban such nodes as they | // new blocks, e.g. a invalid P2SH. We DoS ban such nodes as they | ||||
// are not following the protocol. That said during an upgrade | // are not following the protocol. That said during an upgrade | ||||
// careful thought should be taken as to the correct behavior - we | // careful thought should be taken as to the correct behavior - we | ||||
// may want to continue peering with non-upgraded nodes even after | // may want to continue peering with non-upgraded nodes even after | ||||
// soft-fork super-majority signaling has occurred. | // soft-fork super-majority signaling has occurred. | ||||
return state.DoS( | return state.DoS( | ||||
100, false, REJECT_INVALID, | 100, false, REJECT_INVALID, | ||||
▲ Show 20 Lines • Show All 351 Lines • ▼ Show 20 Lines | static uint32_t GetBlockScriptFlags(const Config &config, | ||||
// alternative. We also start enforcing push only signatures and | // alternative. We also start enforcing push only signatures and | ||||
// clean stack. | // clean stack. | ||||
if (IsMagneticAnomalyEnabled(config, pChainTip)) { | if (IsMagneticAnomalyEnabled(config, pChainTip)) { | ||||
flags |= SCRIPT_ENABLE_CHECKDATASIG; | flags |= SCRIPT_ENABLE_CHECKDATASIG; | ||||
flags |= SCRIPT_VERIFY_SIGPUSHONLY; | flags |= SCRIPT_VERIFY_SIGPUSHONLY; | ||||
flags |= SCRIPT_VERIFY_CLEANSTACK; | flags |= SCRIPT_VERIFY_CLEANSTACK; | ||||
} | } | ||||
// When the great wall fork is enabled, we start accepting 65/64-byte | |||||
// Schnorr signatures in CHECKSIG and CHECKDATASIG respectively, and their | |||||
// verify variants. We also stop accepting 65 byte signatures in | |||||
// CHECKMULTISIG and its verify variant. | |||||
if (IsGreatWallEnabled(config, pChainTip)) { | |||||
flags |= SCRIPT_ENABLE_SCHNORR; | |||||
} | |||||
// We make sure this node will have replay protection during the next hard | // We make sure this node will have replay protection during the next hard | ||||
// fork. | // fork. | ||||
if (IsReplayProtectionEnabled(config, pChainTip)) { | if (IsReplayProtectionEnabled(config, pChainTip)) { | ||||
flags |= SCRIPT_ENABLE_REPLAY_PROTECTION; | flags |= SCRIPT_ENABLE_REPLAY_PROTECTION; | ||||
} | } | ||||
return flags; | return flags; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 631 Lines • ▼ Show 20 Lines | if (IsReplayProtectionEnabled(config, pindexDelete) && | ||||
// While not strictly necessary, clearing the disconnect pool is also | // While not strictly necessary, clearing the disconnect pool is also | ||||
// beneficial so we don't try to reuse its content at the end of the | // beneficial so we don't try to reuse its content at the end of the | ||||
// reorg, which we know will fail. | // reorg, which we know will fail. | ||||
if (disconnectpool) { | if (disconnectpool) { | ||||
disconnectpool->clear(); | disconnectpool->clear(); | ||||
} | } | ||||
} | } | ||||
if ((IsGreatWallEnabled(config, pindexDelete) && | |||||
deadalnixUnsubmitted Done Inline ActionsMove that before the replay protection code. deadalnix: Move that before the replay protection code. | |||||
markblundebergAuthorUnsubmitted Done Inline Actionsk markblundeberg: k | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsInterestingly, now that it is flag-based and before the replay protection code, that replay protection part is redundant. (I would also argue it's incorrect for it to clear out disconnectpool in that replay deactivation, since normally a reorg that dips before the activation will anyway end up landing on another new tip that is still after the activation.) markblundeberg: Interestingly, now that it is flag-based and before the replay protection code, that replay… | |||||
!IsGreatWallEnabled(config, pindexDelete->pprev))) { | |||||
deadalnixUnsubmitted Done Inline ActionsUse the flags definition rather than this, so this code will keep working and not be tied up to this specific fork. deadalnix: Use the flags definition rather than this, so this code will keep working and not be tied up to… | |||||
markblundebergAuthorUnsubmitted Done Inline Actionshmm OK 👍 markblundeberg: hmm OK 👍 | |||||
// We are de-activating a consensus upgrade with new abilities. | |||||
// To be safe, we need to re-assess the entire mempool. | |||||
// Abilities that do not exist before the upgrade: | |||||
// - Schnorr signatures allowed. | |||||
LogPrint(BCLog::MEMPOOL, | |||||
"Re-validating mempool for Great Wall downgrade"); | |||||
disconnectpool->addForBlock(g_mempool.takeAll()); | |||||
deadalnixUnsubmitted Done Inline ActionsThis is not the proper way to do it because topology is all wrong. deadalnix: This is not the proper way to do it because topology is all wrong. | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsHow so? My understanding is that disconnectpool is happy to accept transactions in any non-topological order (such as LTOR) and it builds a topological structure for when it comes time to re-insert. markblundeberg: How so? My understanding is that disconnectpool is happy to accept transactions in any non… | |||||
} | |||||
if (disconnectpool) { | if (disconnectpool) { | ||||
disconnectpool->addForBlock(block.vtx); | disconnectpool->addForBlock(block.vtx); | ||||
} | } | ||||
// If the tip is finalized, then undo it. | // If the tip is finalized, then undo it. | ||||
if (pindexFinalized == pindexDelete) { | if (pindexFinalized == pindexDelete) { | ||||
pindexFinalized = pindexDelete->pprev; | pindexFinalized = pindexDelete->pprev; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | static bool ConnectTip(const Config &config, CValidationState &state, | ||||
LogPrint(BCLog::BENCH, | LogPrint(BCLog::BENCH, | ||||
" - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", | " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", | ||||
(nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, | (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, | ||||
nTimeChainState * MILLI / nBlocksTotal); | nTimeChainState * MILLI / nBlocksTotal); | ||||
// Remove conflicting transactions from the mempool.; | // Remove conflicting transactions from the mempool.; | ||||
g_mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); | g_mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); | ||||
disconnectpool.removeForBlock(blockConnecting.vtx); | disconnectpool.removeForBlock(blockConnecting.vtx); | ||||
if ((IsGreatWallEnabled(config, pindexNew) && | |||||
!IsGreatWallEnabled(config, pindexNew->pprev))) { | |||||
// We are activating a consensus upgrade that contains restrictions. | |||||
// To be safe, we need to re-assess the entire mempool. | |||||
// Abilities that do not exist after the upgrade: | |||||
// - 64/65-byte ECDSA signatures allowed. | |||||
LogPrint(BCLog::MEMPOOL, | |||||
"Re-validating mempool for Great Wall upgrade"); | |||||
disconnectpool.addForBlock(g_mempool.takeAll()); | |||||
deadalnixUnsubmitted Done Inline Actionsdito deadalnix: dito | |||||
} | |||||
// Update chainActive & related variables. | // Update chainActive & related variables. | ||||
UpdateTip(config, pindexNew); | UpdateTip(config, pindexNew); | ||||
int64_t nTime6 = GetTimeMicros(); | int64_t nTime6 = GetTimeMicros(); | ||||
nTimePostConnect += nTime6 - nTime5; | nTimePostConnect += nTime6 - nTime5; | ||||
nTimeTotal += nTime6 - nTime1; | nTimeTotal += nTime6 - nTime1; | ||||
LogPrint(BCLog::BENCH, | LogPrint(BCLog::BENCH, | ||||
" - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", | " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", | ||||
▲ Show 20 Lines • Show All 252 Lines • ▼ Show 20 Lines | while (fContinue && nHeight != pindexMostWork->nHeight) { | ||||
// temporarily to release the lock. | // temporarily to release the lock. | ||||
fContinue = false; | fContinue = false; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (fBlocksDisconnected) { | if (fBlocksDisconnected || !disconnectpool.isEmpty()) { | ||||
// If any blocks were disconnected, disconnectpool may be non empty. Add | // If any blocks were disconnected, we need to update the mempool even | ||||
// any disconnected transactions back to the mempool. | // if disconnectpool is empty. The disconnectpool may also be non-empty | ||||
// if there was a rule-restricting consensus upgrade. | |||||
deadalnixUnsubmitted Done Inline ActionsI don't see any point changing this. deadalnix: I don't see any point changing this. | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsWhen the GreatWall upgrade happens, we need to run updateMempoolForReorg() since the whole mempool just got dumped into disconnectpool and we want to get those txns back. However, fBlocksDisconnected is only flagged True if a block was disconnected. markblundeberg: When the GreatWall upgrade happens, we need to run updateMempoolForReorg() since the whole… | |||||
disconnectpool.updateMempoolForReorg(config, true); | disconnectpool.updateMempoolForReorg(config, true); | ||||
} | } | ||||
g_mempool.check(pcoinsTip.get()); | g_mempool.check(pcoinsTip.get()); | ||||
// Callbacks/notifications for a new best chain. | // Callbacks/notifications for a new best chain. | ||||
if (fInvalidFound) { | if (fInvalidFound) { | ||||
CheckForkWarningConditionsOnNewFork(pindexMostWork); | CheckForkWarningConditionsOnNewFork(pindexMostWork); | ||||
▲ Show 20 Lines • Show All 2,765 Lines • Show Last 20 Lines |
Interesting, this comment is not actually accurate, but give some hints about what needs to happen :)
This is worth cleaning up.