avoid computing state root just to know if storage is empty (#2380)
The state root computation here is one of the major hotspots in block processing - in the cases the code only needs to know if it's empty or not, it can be done a lot faster. Adding a separate function for this looks fragile and should probably be revisited.
This commit is contained in:
parent
9cf7e6aea3
commit
9c6fd46a51
|
@ -150,6 +150,9 @@ proc baseMethods(db: AristoCoreDbRef): CoreDbBaseFns =
|
|||
levelFn: proc(): int =
|
||||
aBase.getLevel,
|
||||
|
||||
colStateEmptyFn: proc(col: CoreDbColRef): CoreDbRc[bool] =
|
||||
aBase.rootHashEmpty(col, "rootHashFn()"),
|
||||
|
||||
colStateFn: proc(col: CoreDbColRef): CoreDbRc[Hash256] =
|
||||
aBase.rootHash(col, "rootHashFn()"),
|
||||
|
||||
|
|
|
@ -645,6 +645,20 @@ proc colPrint*(
|
|||
result &= "$?"
|
||||
|
||||
|
||||
proc rootHashEmpty*(
|
||||
base: AristoBaseRef;
|
||||
col: CoreDbColRef;
|
||||
info: static[string];
|
||||
): CoreDbRc[bool] =
|
||||
let col = AristoColRef(col)
|
||||
if not col.isValid:
|
||||
return err(TrieInvalid.toError(base, info, HashNotAvailable))
|
||||
|
||||
let root = col.to(VertexID)
|
||||
if not root.isValid:
|
||||
return ok(true)
|
||||
return ok(false)
|
||||
|
||||
proc rootHash*(
|
||||
base: AristoBaseRef;
|
||||
col: CoreDbColRef;
|
||||
|
|
|
@ -445,6 +445,23 @@ proc `$$`*(col: CoreDbColRef): string =
|
|||
result = col.prettyText()
|
||||
#col.ifTrackNewApi: debug newApiTxt, api, elapsed, result
|
||||
|
||||
proc stateEmpty*(col: CoreDbColRef): CoreDbRc[bool] =
|
||||
## Getter (well, sort of). It retrieves the column state hash for the
|
||||
## argument `col` descriptor. The function might fail unless the current
|
||||
## state is available (e.g. on `Aristo`.)
|
||||
##
|
||||
## The value `EMPTY_ROOT_HASH` is returned on the void `col` descriptor
|
||||
## argument `CoreDbColRef(nil)`.
|
||||
##
|
||||
col.setTrackNewApi BaseColStateEmptyFn
|
||||
result = block:
|
||||
if not col.isNil and col.ready:
|
||||
col.parent.methods.colStateEmptyFn col
|
||||
else:
|
||||
ok true
|
||||
# Note: tracker will be silent if `vid` is NIL
|
||||
col.ifTrackNewApi: debug newApiTxt, api, elapsed, col, result
|
||||
|
||||
proc state*(col: CoreDbColRef): CoreDbRc[Hash256] =
|
||||
## Getter (well, sort of). It retrieves the column state hash for the
|
||||
## argument `col` descriptor. The function might fail unless the current
|
||||
|
|
|
@ -41,6 +41,7 @@ type
|
|||
AnyBackendFn = "any/backend"
|
||||
|
||||
BaseColPrintFn = "$$"
|
||||
BaseColStateEmptyFn = "stateEmpty"
|
||||
BaseColStateFn = "state"
|
||||
BaseDbTypeFn = "dbType"
|
||||
BaseFinishFn = "finish"
|
||||
|
|
|
@ -92,6 +92,8 @@ type
|
|||
CoreDbBaseDestroyFn* = proc(eradicate = true) {.noRaise.}
|
||||
CoreDbBaseColStateFn* = proc(
|
||||
col: CoreDbColRef): CoreDbRc[Hash256] {.noRaise.}
|
||||
CoreDbBaseColStateEmptyFn* = proc(
|
||||
col: CoreDbColRef): CoreDbRc[bool] {.noRaise.}
|
||||
CoreDbBaseColPrintFn* = proc(vid: CoreDbColRef): string {.noRaise.}
|
||||
CoreDbBaseErrorPrintFn* = proc(e: CoreDbErrorRef): string {.noRaise.}
|
||||
CoreDbBaseLevelFn* = proc(): int {.noRaise.}
|
||||
|
@ -110,6 +112,7 @@ type
|
|||
CoreDbBaseFns* = object
|
||||
destroyFn*: CoreDbBaseDestroyFn
|
||||
colStateFn*: CoreDbBaseColStateFn
|
||||
colStateEmptyFn*: CoreDbBaseColStateEmptyFn
|
||||
colPrintFn*: CoreDbBaseColPrintFn
|
||||
errorPrintFn*: CoreDbBaseErrorPrintFn
|
||||
levelFn*: CoreDbBaseLevelFn
|
||||
|
|
|
@ -376,9 +376,9 @@ proc persistStorage(acc: AccountRef, ac: AccountsLedgerRef) =
|
|||
acc.statement.storage = storageLedger.getColumn()
|
||||
|
||||
# No need to hold descriptors for longer than needed
|
||||
let state = acc.statement.storage.state.valueOr:
|
||||
let stateEmpty = acc.statement.storage.stateEmpty.valueOr:
|
||||
raiseAssert "Storage column state error: " & $$error
|
||||
if state == EMPTY_ROOT_HASH:
|
||||
if stateEmpty:
|
||||
acc.statement.storage = CoreDbColRef(nil)
|
||||
|
||||
|
||||
|
@ -540,8 +540,8 @@ proc clearStorage*(ac: AccountsLedgerRef, address: EthAddress) =
|
|||
let acc = ac.getAccount(address)
|
||||
acc.flags.incl {Alive, NewlyCreated}
|
||||
|
||||
let accHash = acc.statement.storage.state.valueOr: return
|
||||
if accHash != EMPTY_ROOT_HASH:
|
||||
let empty = acc.statement.storage.stateEmpty.valueOr: return
|
||||
if not empty:
|
||||
# need to clear the storage from the database first
|
||||
let acc = ac.makeDirty(address, cloneStorage = false)
|
||||
ac.ledger.freeStorage address
|
||||
|
@ -613,7 +613,7 @@ proc clearEmptyAccounts(ac: AccountsLedgerRef) =
|
|||
ac.ripemdSpecial = false
|
||||
|
||||
proc persist*(ac: AccountsLedgerRef,
|
||||
clearEmptyAccount: bool = false) =
|
||||
clearEmptyAccount: bool = false) {.deprecated.} =
|
||||
# make sure all savepoint already committed
|
||||
doAssert(ac.savePoint.parentSavepoint.isNil)
|
||||
|
||||
|
|
Loading…
Reference in New Issue