Changeset View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 3,761 Lines • ▼ Show 20 Lines | bool ContextualCheckTransactionForCurrentBlock(const Config &config, | ||||
const int64_t nLockTimeCutoff = (flags & LOCKTIME_MEDIAN_TIME_PAST) | const int64_t nLockTimeCutoff = (flags & LOCKTIME_MEDIAN_TIME_PAST) | ||||
? chainActive.Tip()->GetMedianTimePast() | ? chainActive.Tip()->GetMedianTimePast() | ||||
: GetAdjustedTime(); | : GetAdjustedTime(); | ||||
return ContextualCheckTransaction(config, tx, state, nBlockHeight, | return ContextualCheckTransaction(config, tx, state, nBlockHeight, | ||||
nLockTimeCutoff); | nLockTimeCutoff); | ||||
} | } | ||||
static bool ContextualCheckBlock(const Config &config, const CBlock &block, | static bool ContextualCheckBlock(const Config &config, const CBlock &block, | ||||
schancel: Can we get a comment here as to what "Contextual" means at least, as compared to checkblock? | |||||
deadalnixAuthorUnsubmitted Not Done Inline ActionsYes, but why do you trust me on this ? deadalnix: Yes, but why do you trust me on this ? | |||||
CValidationState &state, | CValidationState &state, | ||||
const CBlockIndex *pindexPrev) { | const CBlockIndex *pindexPrev) { | ||||
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; | const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; | ||||
const Consensus::Params &consensusParams = | const Consensus::Params &consensusParams = | ||||
config.GetChainParams().GetConsensus(); | config.GetChainParams().GetConsensus(); | ||||
// Start enforcing BIP113 (Median Time Past) using versionbits logic. | // Start enforcing BIP113 (Median Time Past) using versionbits logic. | ||||
int nLockTimeFlags = 0; | int nLockTimeFlags = 0; | ||||
if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, | if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, | ||||
versionbitscache) == THRESHOLD_ACTIVE) { | versionbitscache) == THRESHOLD_ACTIVE) { | ||||
nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; | nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; | ||||
} | } | ||||
const int64_t nMedianTimePast = | const int64_t nMedianTimePast = | ||||
pindexPrev == nullptr ? 0 : pindexPrev->GetMedianTimePast(); | pindexPrev == nullptr ? 0 : pindexPrev->GetMedianTimePast(); | ||||
const int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) | const int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) | ||||
? nMedianTimePast | ? nMedianTimePast | ||||
: block.GetBlockTime(); | : block.GetBlockTime(); | ||||
const bool fIsMagneticAnomalyEnabled = | |||||
IsMagneticAnomalyEnabled(config, pindexPrev); | |||||
// Check that all transactions are finalized | // Check that all transactions are finalized | ||||
for (const auto &tx : block.vtx) { | const CTransaction *prevTx = nullptr; | ||||
if (!ContextualCheckTransaction(config, *tx, state, nHeight, | for (const auto &ptx : block.vtx) { | ||||
const CTransaction &tx = *ptx; | |||||
if (fIsMagneticAnomalyEnabled) { | |||||
if (prevTx && (tx.GetId() < prevTx->GetId())) { | |||||
return state.DoS( | |||||
100, false, REJECT_INVALID, "tx-ordering", false, | |||||
strprintf("Transaction order is invalid (%s < %s)", | |||||
tx.GetId().ToString(), | |||||
prevTx->GetId().ToString())); | |||||
} | |||||
if (prevTx || !tx.IsCoinBase()) { | |||||
schancelUnsubmitted Not Done Inline ActionsIs the prevTx check here just an optimization? schancel: Is the prevTx check here just an optimization? | |||||
deadalnixAuthorUnsubmitted Not Done Inline ActionsYes. deadalnix: Yes. | |||||
jasonbcoxUnsubmitted Not Done Inline ActionsSomething doesn't seem right with this. Lets say there are 3 txs, C (coinbase), D, E, where the TxId comparison is D < C < E and ordering is [D, C, E]. It will pass this code block when it should be an invalid ordering. Perhaps this function should have an explicit check for coinbase at index 0 before this code block, despite other parts of the code likely enforcing this? Regardless of the final solution to this, I think this case needs a unit test. jasonbcox: Something doesn't seem right with this. Lets say there are 3 txs, C (coinbase), D, E, where… | |||||
deadalnixAuthorUnsubmitted Not Done Inline Actionscoinbase must be at position zero. This is enforced and tested already. deadalnix: coinbase must be at position zero. This is enforced and tested already. | |||||
schancelUnsubmitted Not Done Inline ActionsThis is done in CheckBlock. His point is that if that is changed, this may not fail in some cases edge cases. schancel: This is done in `CheckBlock`. His point is that if that is changed, this may not fail in some… | |||||
jasonbcoxUnsubmitted Not Done Inline ActionsRight, looking at the comment // Check that all transactions are finalized and the error message "Transaction order is invalid (%s < %s)", these are hinting to me that transaction ordering is being validated here. If it's not doing full validation, that needs to be clear and indicate how/why doing partial validation is safe by design. jasonbcox: Right, looking at the comment ` // Check that all transactions are finalized` and the error… | |||||
prevTx = &tx; | |||||
} | |||||
} | |||||
if (!ContextualCheckTransaction(config, tx, state, nHeight, | |||||
nLockTimeCutoff)) { | nLockTimeCutoff)) { | ||||
// state set by ContextualCheckTransaction. | // state set by ContextualCheckTransaction. | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// Enforce rule that the coinbase starts with serialized block height | // Enforce rule that the coinbase starts with serialized block height | ||||
if (nHeight >= consensusParams.BIP34Height) { | if (nHeight >= consensusParams.BIP34Height) { | ||||
▲ Show 20 Lines • Show All 1,833 Lines • Show Last 20 Lines |
Can we get a comment here as to what "Contextual" means at least, as compared to checkblock? It's not clear to me what should be in one or the other.
Is it that this is based on the context of the block's position in the chain?