Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 1,884 Lines • ▼ Show 20 Lines | const uint32_t flags = | ||||
GetNextBlockScriptFlags(consensusParams, pindex->pprev); | GetNextBlockScriptFlags(consensusParams, pindex->pprev); | ||||
int64_t nTime2 = GetTimeMicros(); | int64_t nTime2 = GetTimeMicros(); | ||||
nTimeForks += nTime2 - nTime1; | nTimeForks += nTime2 - nTime1; | ||||
LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", | LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", | ||||
MILLI * (nTime2 - nTime1), nTimeForks * MICRO, | MILLI * (nTime2 - nTime1), nTimeForks * MICRO, | ||||
nTimeForks * MILLI / nBlocksTotal); | nTimeForks * MILLI / nBlocksTotal); | ||||
CBlockUndo blockundo; | |||||
std::vector<int> prevheights; | std::vector<int> prevheights; | ||||
Amount nFees = Amount::zero(); | Amount nFees = Amount::zero(); | ||||
int nInputs = 0; | int nInputs = 0; | ||||
// Sigops counting. We need to do it again because of P2SH. | // Sigops counting. We need to do it again because of P2SH. | ||||
uint64_t nSigOpsCount = 0; | uint64_t nSigOpsCount = 0; | ||||
const uint64_t currentBlockSize = | const uint64_t currentBlockSize = | ||||
::GetSerializeSize(block, PROTOCOL_VERSION); | ::GetSerializeSize(block, PROTOCOL_VERSION); | ||||
const uint64_t nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize); | const uint64_t nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize); | ||||
// Limit the total executed signature operations in the block, a consensus | // Limit the total executed signature operations in the block, a consensus | ||||
// rule. Tracking during the CPU-consuming part (validation of uncached | // rule. Tracking during the CPU-consuming part (validation of uncached | ||||
// inputs) is per-input atomic and validation in each thread stops very | // inputs) is per-input atomic and validation in each thread stops very | ||||
// quickly after the limit is exceeded, so an adversary cannot cause us to | // quickly after the limit is exceeded, so an adversary cannot cause us to | ||||
// exceed the limit by much at all. | // exceed the limit by much at all. | ||||
CheckInputsLimiter nSigChecksBlockLimiter( | CheckInputsLimiter nSigChecksBlockLimiter( | ||||
GetMaxBlockSigChecksCount(options.getExcessiveBlockSize())); | GetMaxBlockSigChecksCount(options.getExcessiveBlockSize())); | ||||
blockundo.vtxundo.reserve(block.vtx.size() - 1); | CBlockUndo blockundo; | ||||
blockundo.vtxundo.resize(block.vtx.size() - 1); | |||||
jasonbcox: Any reason to not move this initialization down to where `txIndex` is initialized? It isn't… | |||||
deadalnixAuthorUnsubmitted Done Inline ActionsThis is where everything is setup. If anything we'd have to move the other loop up, but this doesn't seem like the best move for this patch. deadalnix: This is where everything is setup. If anything we'd have to move the other loop up, but this… | |||||
CCheckQueueControl<CScriptCheck> control(fScriptChecks ? &scriptcheckqueue | CCheckQueueControl<CScriptCheck> control(fScriptChecks ? &scriptcheckqueue | ||||
: nullptr); | : nullptr); | ||||
// Add all outputs | // Add all outputs | ||||
try { | try { | ||||
for (const auto &ptx : block.vtx) { | for (const auto &ptx : block.vtx) { | ||||
AddCoins(view, *ptx, pindex->nHeight); | AddCoins(view, *ptx, pindex->nHeight); | ||||
} | } | ||||
} catch (const std::logic_error &e) { | } catch (const std::logic_error &e) { | ||||
// This error will be thrown from AddCoin if we try to connect a block | // This error will be thrown from AddCoin if we try to connect a block | ||||
// containing duplicate transactions. Such a thing should normally be | // containing duplicate transactions. Such a thing should normally be | ||||
// caught early nowadays (due to ContextualCheckBlock's CTOR | // caught early nowadays (due to ContextualCheckBlock's CTOR | ||||
// enforcement) however some edge cases can escape that: | // enforcement) however some edge cases can escape that: | ||||
// - ContextualCheckBlock does not get re-run after saving the block to | // - ContextualCheckBlock does not get re-run after saving the block to | ||||
// disk, and older versions may have saved a weird block. | // disk, and older versions may have saved a weird block. | ||||
// - its checks are not applied to pre-CTOR chains, which we might visit | // - its checks are not applied to pre-CTOR chains, which we might visit | ||||
// with checkpointing off. | // with checkpointing off. | ||||
return state.DoS( | return state.DoS( | ||||
100, error("ConnectBlock(): tried to overwrite transaction"), | 100, error("ConnectBlock(): tried to overwrite transaction"), | ||||
REJECT_INVALID, "tx-duplicate"); | REJECT_INVALID, "tx-duplicate"); | ||||
} | } | ||||
size_t txIndex = 0; | |||||
for (const auto &ptx : block.vtx) { | for (const auto &ptx : block.vtx) { | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
const bool isCoinBase = tx.IsCoinBase(); | const bool isCoinBase = tx.IsCoinBase(); | ||||
nInputs += tx.vin.size(); | nInputs += tx.vin.size(); | ||||
Amount txfee = Amount::zero(); | Amount txfee = Amount::zero(); | ||||
if (!isCoinBase && !Consensus::CheckTxInputs(tx, state, view, | if (!isCoinBase && !Consensus::CheckTxInputs(tx, state, view, | ||||
pindex->nHeight, txfee)) { | pindex->nHeight, txfee)) { | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | for (const auto &ptx : block.vtx) { | ||||
false, "CheckInputs exceeded SigChecks limit"); | false, "CheckInputs exceeded SigChecks limit"); | ||||
} | } | ||||
return error("ConnectBlock(): CheckInputs on %s failed with %s", | return error("ConnectBlock(): CheckInputs on %s failed with %s", | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
control.Add(vChecks); | control.Add(vChecks); | ||||
blockundo.vtxundo.push_back(CTxUndo()); | |||||
// Note: this must execute in the same iteration as CheckTxInputs (not | // Note: this must execute in the same iteration as CheckTxInputs (not | ||||
// in a separate loop) in order to detect double spends. However, | // in a separate loop) in order to detect double spends. However, | ||||
// this does not prevent double-spending by duplicated transaction | // this does not prevent double-spending by duplicated transaction | ||||
// inputs in the same transaction (cf. CVE-2018-17144) -- that check is | // inputs in the same transaction (cf. CVE-2018-17144) -- that check is | ||||
// done in CheckBlock (CheckRegularTransaction). | // done in CheckBlock (CheckRegularTransaction). | ||||
SpendCoins(view, tx, blockundo.vtxundo.back(), pindex->nHeight); | SpendCoins(view, tx, blockundo.vtxundo.at(txIndex), pindex->nHeight); | ||||
txIndex++; | |||||
} | } | ||||
int64_t nTime3 = GetTimeMicros(); | int64_t nTime3 = GetTimeMicros(); | ||||
nTimeConnect += nTime3 - nTime2; | nTimeConnect += nTime3 - nTime2; | ||||
LogPrint(BCLog::BENCH, | LogPrint(BCLog::BENCH, | ||||
" - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) " | " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) " | ||||
"[%.2fs (%.2fms/blk)]\n", | "[%.2fs (%.2fms/blk)]\n", | ||||
(unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), | (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), | ||||
▲ Show 20 Lines • Show All 3,825 Lines • Show Last 20 Lines |
Any reason to not move this initialization down to where txIndex is initialized? It isn't used until that loop anyway, and block.vtx.size() doesn't change.