mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-16 15:25:24 +00:00
81e75622cf
The state and account MPT:s currenty share key space in the database based on that vertex id:s are assigned essentially randomly, which means that when two adjacent slot values from the same contract are accessed, they might reside at large distance from each other. Here, we prefix each vertex id by its root causing them to be sorted together thus bringing all data belonging to a particular contract closer together - the same effect also happens for the main state MPT whose nodes now end up clustered together more tightly. In the future, the prefix given to the storage keys can also be used to perform range operations such as reading all the storage at once and/or deleting an account with a batch operation. Notably, parts of the API already supported this rooting concept while parts didn't - this PR makes the API consistent by always working with a root+vid.
102 lines
3.5 KiB
Nim
102 lines
3.5 KiB
Nim
# nimbus-eth1
|
|
# Copyright (c) 2023-2024 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
# http://opensource.org/licenses/MIT)
|
|
# at your option. This file may not be copied, modified, or distributed
|
|
# except according to those terms.
|
|
|
|
## Aristo DB -- Delta filter management
|
|
## ====================================
|
|
##
|
|
|
|
import
|
|
std/tables,
|
|
eth/common,
|
|
results,
|
|
./aristo_desc,
|
|
./aristo_desc/desc_backend,
|
|
./aristo_delta/delta_siblings
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions, save to backend
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc deltaPersistentOk*(db: AristoDbRef): bool =
|
|
## Check whether the read-only filter can be merged into the backend
|
|
not db.backend.isNil and db.isCentre
|
|
|
|
|
|
proc deltaPersistent*(
|
|
db: AristoDbRef; # Database
|
|
nxtFid = 0u64; # Next filter ID (if any)
|
|
reCentreOk = false;
|
|
): Result[void,AristoError] =
|
|
## Resolve (i.e. move) the backend filter into the physical backend database.
|
|
##
|
|
## This needs write permission on the backend DB for the argument `db`
|
|
## descriptor (see the function `aristo_desc.isCentre()`.) With the argument
|
|
## flag `reCentreOk` passed `true`, write permission will be temporarily
|
|
## acquired when needed.
|
|
##
|
|
## When merging the current backend filter, its reverse will be is stored as
|
|
## back log on the filter fifos (so the current state can be retrieved.)
|
|
## Also, other non-centre descriptors are updated so there is no visible
|
|
## database change for these descriptors.
|
|
##
|
|
let be = db.backend
|
|
if be.isNil:
|
|
return err(FilBackendMissing)
|
|
|
|
# Blind or missing filter
|
|
if db.balancer.isNil:
|
|
return ok()
|
|
|
|
# Make sure that the argument `db` is at the centre so the backend is in
|
|
# read-write mode for this peer.
|
|
let parent = db.getCentre
|
|
if db != parent:
|
|
if not reCentreOk:
|
|
return err(FilBackendRoMode)
|
|
? db.reCentre()
|
|
# Always re-centre to `parent` (in case `reCentreOk` was set)
|
|
defer: discard parent.reCentre()
|
|
|
|
# Initialise peer filter balancer.
|
|
let updateSiblings = ? UpdateSiblingsRef.init db
|
|
defer: updateSiblings.rollback()
|
|
|
|
let lSst = SavedState(
|
|
key: EMPTY_ROOT_HASH, # placeholder for more
|
|
serial: nxtFid)
|
|
|
|
# Store structural single trie entries
|
|
let writeBatch = ? be.putBegFn()
|
|
for rvid, vtx in db.balancer.sTab:
|
|
be.putVtxFn(writeBatch, rvid, vtx)
|
|
for rvid, key in db.balancer.kMap:
|
|
be.putKeyFn(writeBatch, rvid, key)
|
|
be.putTuvFn(writeBatch, db.balancer.vTop)
|
|
be.putLstFn(writeBatch, lSst)
|
|
? be.putEndFn writeBatch # Finalise write batch
|
|
|
|
# Copy back updated payloads - these only change when storage is written to
|
|
# the first time or when storage is removed completely
|
|
for accPath, stoID in db.balancer.accSids:
|
|
let accKey = accPath.to(AccountKey)
|
|
if stoID.isValid:
|
|
if not db.accSids.lruUpdate(accKey, stoID):
|
|
discard db.accSids.lruAppend(accKey, stoID, accLruSize)
|
|
else:
|
|
db.accSids.del(accKey)
|
|
|
|
# Update dudes and this descriptor
|
|
? updateSiblings.update().commit()
|
|
ok()
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|