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 =
|
levelFn: proc(): int =
|
||||||
aBase.getLevel,
|
aBase.getLevel,
|
||||||
|
|
||||||
|
colStateEmptyFn: proc(col: CoreDbColRef): CoreDbRc[bool] =
|
||||||
|
aBase.rootHashEmpty(col, "rootHashFn()"),
|
||||||
|
|
||||||
colStateFn: proc(col: CoreDbColRef): CoreDbRc[Hash256] =
|
colStateFn: proc(col: CoreDbColRef): CoreDbRc[Hash256] =
|
||||||
aBase.rootHash(col, "rootHashFn()"),
|
aBase.rootHash(col, "rootHashFn()"),
|
||||||
|
|
||||||
|
|
|
@ -645,6 +645,20 @@ proc colPrint*(
|
||||||
result &= "$?"
|
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*(
|
proc rootHash*(
|
||||||
base: AristoBaseRef;
|
base: AristoBaseRef;
|
||||||
col: CoreDbColRef;
|
col: CoreDbColRef;
|
||||||
|
|
|
@ -445,6 +445,23 @@ proc `$$`*(col: CoreDbColRef): string =
|
||||||
result = col.prettyText()
|
result = col.prettyText()
|
||||||
#col.ifTrackNewApi: debug newApiTxt, api, elapsed, result
|
#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] =
|
proc state*(col: CoreDbColRef): CoreDbRc[Hash256] =
|
||||||
## Getter (well, sort of). It retrieves the column state hash for the
|
## Getter (well, sort of). It retrieves the column state hash for the
|
||||||
## argument `col` descriptor. The function might fail unless the current
|
## argument `col` descriptor. The function might fail unless the current
|
||||||
|
|
|
@ -41,6 +41,7 @@ type
|
||||||
AnyBackendFn = "any/backend"
|
AnyBackendFn = "any/backend"
|
||||||
|
|
||||||
BaseColPrintFn = "$$"
|
BaseColPrintFn = "$$"
|
||||||
|
BaseColStateEmptyFn = "stateEmpty"
|
||||||
BaseColStateFn = "state"
|
BaseColStateFn = "state"
|
||||||
BaseDbTypeFn = "dbType"
|
BaseDbTypeFn = "dbType"
|
||||||
BaseFinishFn = "finish"
|
BaseFinishFn = "finish"
|
||||||
|
|
|
@ -92,6 +92,8 @@ type
|
||||||
CoreDbBaseDestroyFn* = proc(eradicate = true) {.noRaise.}
|
CoreDbBaseDestroyFn* = proc(eradicate = true) {.noRaise.}
|
||||||
CoreDbBaseColStateFn* = proc(
|
CoreDbBaseColStateFn* = proc(
|
||||||
col: CoreDbColRef): CoreDbRc[Hash256] {.noRaise.}
|
col: CoreDbColRef): CoreDbRc[Hash256] {.noRaise.}
|
||||||
|
CoreDbBaseColStateEmptyFn* = proc(
|
||||||
|
col: CoreDbColRef): CoreDbRc[bool] {.noRaise.}
|
||||||
CoreDbBaseColPrintFn* = proc(vid: CoreDbColRef): string {.noRaise.}
|
CoreDbBaseColPrintFn* = proc(vid: CoreDbColRef): string {.noRaise.}
|
||||||
CoreDbBaseErrorPrintFn* = proc(e: CoreDbErrorRef): string {.noRaise.}
|
CoreDbBaseErrorPrintFn* = proc(e: CoreDbErrorRef): string {.noRaise.}
|
||||||
CoreDbBaseLevelFn* = proc(): int {.noRaise.}
|
CoreDbBaseLevelFn* = proc(): int {.noRaise.}
|
||||||
|
@ -110,6 +112,7 @@ type
|
||||||
CoreDbBaseFns* = object
|
CoreDbBaseFns* = object
|
||||||
destroyFn*: CoreDbBaseDestroyFn
|
destroyFn*: CoreDbBaseDestroyFn
|
||||||
colStateFn*: CoreDbBaseColStateFn
|
colStateFn*: CoreDbBaseColStateFn
|
||||||
|
colStateEmptyFn*: CoreDbBaseColStateEmptyFn
|
||||||
colPrintFn*: CoreDbBaseColPrintFn
|
colPrintFn*: CoreDbBaseColPrintFn
|
||||||
errorPrintFn*: CoreDbBaseErrorPrintFn
|
errorPrintFn*: CoreDbBaseErrorPrintFn
|
||||||
levelFn*: CoreDbBaseLevelFn
|
levelFn*: CoreDbBaseLevelFn
|
||||||
|
|
|
@ -376,9 +376,9 @@ proc persistStorage(acc: AccountRef, ac: AccountsLedgerRef) =
|
||||||
acc.statement.storage = storageLedger.getColumn()
|
acc.statement.storage = storageLedger.getColumn()
|
||||||
|
|
||||||
# No need to hold descriptors for longer than needed
|
# 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
|
raiseAssert "Storage column state error: " & $$error
|
||||||
if state == EMPTY_ROOT_HASH:
|
if stateEmpty:
|
||||||
acc.statement.storage = CoreDbColRef(nil)
|
acc.statement.storage = CoreDbColRef(nil)
|
||||||
|
|
||||||
|
|
||||||
|
@ -540,8 +540,8 @@ proc clearStorage*(ac: AccountsLedgerRef, address: EthAddress) =
|
||||||
let acc = ac.getAccount(address)
|
let acc = ac.getAccount(address)
|
||||||
acc.flags.incl {Alive, NewlyCreated}
|
acc.flags.incl {Alive, NewlyCreated}
|
||||||
|
|
||||||
let accHash = acc.statement.storage.state.valueOr: return
|
let empty = acc.statement.storage.stateEmpty.valueOr: return
|
||||||
if accHash != EMPTY_ROOT_HASH:
|
if not empty:
|
||||||
# need to clear the storage from the database first
|
# need to clear the storage from the database first
|
||||||
let acc = ac.makeDirty(address, cloneStorage = false)
|
let acc = ac.makeDirty(address, cloneStorage = false)
|
||||||
ac.ledger.freeStorage address
|
ac.ledger.freeStorage address
|
||||||
|
@ -613,7 +613,7 @@ proc clearEmptyAccounts(ac: AccountsLedgerRef) =
|
||||||
ac.ripemdSpecial = false
|
ac.ripemdSpecial = false
|
||||||
|
|
||||||
proc persist*(ac: AccountsLedgerRef,
|
proc persist*(ac: AccountsLedgerRef,
|
||||||
clearEmptyAccount: bool = false) =
|
clearEmptyAccount: bool = false) {.deprecated.} =
|
||||||
# make sure all savepoint already committed
|
# make sure all savepoint already committed
|
||||||
doAssert(ac.savePoint.parentSavepoint.isNil)
|
doAssert(ac.savePoint.parentSavepoint.isNil)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue