From 79788c01d4b67c72846cb65366d7a96f48b7ad9e Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 4 Jul 2024 16:51:50 +0200 Subject: [PATCH] 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. --- nimbus/config.nim | 6 +++++ nimbus/core/chain/persist_blocks.nim | 6 +++-- nimbus/evm/interpreter_dispatch.nim | 33 ++++++++++++++-------------- nimbus/nimbus_import.nim | 1 + 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/nimbus/config.nim b/nimbus/config.nim index d6e2d091c..59141989f 100644 --- a/nimbus/config.nim +++ b/nimbus/config.nim @@ -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" diff --git a/nimbus/core/chain/persist_blocks.nim b/nimbus/core/chain/persist_blocks.nim index c91e6f6b1..12233b6d3 100644 --- a/nimbus/core/chain/persist_blocks.nim +++ b/nimbus/core/chain/persist_blocks.nim @@ -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 diff --git a/nimbus/evm/interpreter_dispatch.nim b/nimbus/evm/interpreter_dispatch.nim index baa90849f..91273afad 100644 --- a/nimbus/evm/interpreter_dispatch.nim +++ b/nimbus/evm/interpreter_dispatch.nim @@ -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 diff --git a/nimbus/nimbus_import.nim b/nimbus/nimbus_import.nim index 615b0615e..dde0e75be 100644 --- a/nimbus/nimbus_import.nim +++ b/nimbus/nimbus_import.nim @@ -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)