Add debug mode for disabling per-chunk state root validation (#2453)

This significantly speeds up block import at the cost of less protection
against invalid data, potentially resulting in an invalid database
getting stored.

The risk is small given that import is used only for validated data -
evaluating the right level of of validation vs performance is left for a
future PR.

A side effect of this approach is that there is no cached stated root in
the database - computing it currently requires a lot of memory since the
intermediate roots get cached in memory in full while the computation is
ongoing - a future PR will need to address this deficiency, for example
by streaming the already-computed hashes directly to the database.
This commit is contained in:
Jacek Sieka 2024-07-04 16:51:50 +02:00 committed by GitHub
parent f04f30c72b
commit 79788c01d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 27 additions and 19 deletions

View File

@ -524,6 +524,12 @@ type
defaultValue: false
name: "debug-full-validation".}: bool
noValidation* {.
hidden
desc: "Disble per-chunk validation"
defaultValue: true
name: "debug-no-validation".}: bool
storeBodies* {.
hidden
desc: "Store block blodies in database"

View File

@ -30,6 +30,7 @@ export results
type
PersistBlockFlag* = enum
NoValidation # Validate the batch instead of validating each block in it
NoFullValidation # Validate the batch instead of validating each block in it
NoPersistHeader
NoPersistTransactions
@ -115,7 +116,8 @@ proc persistBlocksImpl(
# can the state root of the last block still be correct? Dubious, but
# what would be the consequences? We would roll back the full set of
# blocks which is fairly low-cost.
let skipValidation = NoFullValidation in flags and header.number != toBlock
let skipValidation =
NoFullValidation in flags and header.number != toBlock or NoValidation in flags
c.com.hardForkTransition(header)
@ -174,7 +176,7 @@ proc persistBlocksImpl(
if NoPersistWithdrawals notin flags and blk.withdrawals.isSome:
c.db.persistWithdrawals(
header.withdrawalsRoot.expect("WithdrawalsRoot should be verified before"),
blk.withdrawals.get
blk.withdrawals.get,
)
# update currentBlock *after* we persist it

View File

@ -273,28 +273,23 @@ proc executeOpcodes*(c: Computation, shouldPrepareTracer: bool = true) =
when vm_use_recursion:
# Recursion with tiny stack frame per level.
proc execCallOrCreate*(c: Computation) =
defer: c.dispose()
if c.beforeExec():
return
c.executeOpcodes()
while not c.continuation.isNil:
# If there's a continuation, then it's because there's either
# a child (i.e. call or create)
when evmc_enabled:
c.res = c.host.call(c.child[])
else:
execCallOrCreate(c.child)
c.child = nil
if not c.beforeExec():
c.executeOpcodes()
c.afterExec()
while not c.continuation.isNil:
# If there's a continuation, then it's because there's either
# a child (i.e. call or create)
when evmc_enabled:
c.res = c.host.call(c.child[])
else:
execCallOrCreate(c.child)
c.child = nil
c.executeOpcodes()
c.afterExec()
c.dispose()
else:
proc execCallOrCreate*(cParam: Computation) =
var (c, before, shouldPrepareTracer) = (cParam, true, true)
defer:
while not c.isNil:
c.dispose()
c = c.parent
# No actual recursion, but simulate recursion including before/after/dispose.
while true:
@ -311,6 +306,10 @@ else:
c.dispose()
(before, shouldPrepareTracer, c.parent, c) = (false, true, nil.Computation, c.parent)
while not c.isNil:
c.dispose()
c = c.parent
# ------------------------------------------------------------------------------
# End

View File

@ -100,6 +100,7 @@ proc importBlocks*(conf: NimbusConf, com: CommonRef) =
else:
File(nil)
flags =
boolFlag({PersistBlockFlag.NoValidation}, conf.noValidation) +
boolFlag({PersistBlockFlag.NoFullValidation}, not conf.fullValidation) +
boolFlag(NoPersistBodies, not conf.storeBodies) +
boolFlag({PersistBlockFlag.NoPersistReceipts}, not conf.storeReceipts)