From f201eb611ef0197aaff54839f343869c70153557 Mon Sep 17 00:00:00 2001 From: andri lim Date: Wed, 6 Nov 2024 09:01:56 +0700 Subject: [PATCH] Simplify LedgerRef: remove unnecessary abstraction (#2826) --- nimbus/compile_info.nim | 5 +- nimbus/core/chain/persist_blocks.nim | 1 - nimbus/db/ledger.nim | 927 ++++++++++++++++++- nimbus/db/ledger/backend/accounts_ledger.nim | 916 ------------------ nimbus/db/ledger/base.nim | 329 ------- nimbus/db/ledger/base/api_tracking.nim | 148 --- nimbus/db/ledger/base/base_config.nim | 48 - nimbus/db/ledger/base/base_desc.nim | 33 - nimbus/db/ledger/base/base_helpers.nim | 43 - nimbus/db/ledger/base_iterators.nim | 71 -- nimbus/evm/state.nim | 2 +- tests/test_coredb/test_chainsync.nim | 16 +- tests/test_ledger.nim | 3 +- 13 files changed, 915 insertions(+), 1627 deletions(-) delete mode 100644 nimbus/db/ledger/backend/accounts_ledger.nim delete mode 100644 nimbus/db/ledger/base.nim delete mode 100644 nimbus/db/ledger/base/api_tracking.nim delete mode 100644 nimbus/db/ledger/base/base_config.nim delete mode 100644 nimbus/db/ledger/base/base_desc.nim delete mode 100644 nimbus/db/ledger/base/base_helpers.nim delete mode 100644 nimbus/db/ledger/base_iterators.nim diff --git a/nimbus/compile_info.nim b/nimbus/compile_info.nim index b382bbfff..8e48b5463 100644 --- a/nimbus/compile_info.nim +++ b/nimbus/compile_info.nim @@ -9,8 +9,7 @@ # according to those terms. import - ./db/core_db/base/base_config, - ./db/ledger/base/base_config + ./db/core_db/base/base_config func vmName(): string = when defined(evmc_enabled): @@ -29,8 +28,6 @@ const rc &= ", boehm/gc" when 0 < coreDbBaseConfigExtras.len: rc &= ", " & coreDbBaseConfigExtras - when 0 < ledgerBaseConfigExtras.len: - rc &= ", " & ledgerBaseConfigExtras rc &= " enabled" rc diff --git a/nimbus/core/chain/persist_blocks.nim b/nimbus/core/chain/persist_blocks.nim index c2d921491..3f09eca95 100644 --- a/nimbus/core/chain/persist_blocks.nim +++ b/nimbus/core/chain/persist_blocks.nim @@ -12,7 +12,6 @@ import results, - ../../db/ledger, ../../evm/state, ../../evm/types, ../executor, diff --git a/nimbus/db/ledger.nim b/nimbus/db/ledger.nim index cf1f140a8..05eb266e9 100644 --- a/nimbus/db/ledger.nim +++ b/nimbus/db/ledger.nim @@ -5,31 +5,926 @@ # 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. +# at your option. This file may not be copied, modified, or distributed except +# according to those terms. -## Unifies different ledger management APIs. All ledger objects are -## derived from the base objects -## :: -## LedgerSpRef => SavePoint, overloaded SavePoint etc -## {.push raises: [].} import - eth/common, - ./core_db, - ./ledger/backend/accounts_ledger, - ./ledger/base/[base_config, base_desc, base_helpers], - ./ledger/[base, base_iterators] + std/[tables, hashes, sets, typetraits], + chronicles, + eth/common/eth_types, + results, + minilru, + ../utils/mergeutils, + ../evm/code_bytes, + ../stateless/multi_keys, + "/.."/[constants, utils/utils], + ./access_list as ac_access_list, + "."/[core_db, storage_types, transient_storage], + ./aristo/aristo_blobify -export AccountsLedgerRef, base, base_config, base_iterators +export + code_bytes + +const + debugLedgerRef = false + codeLruSize = 16*1024 + # An LRU cache of 16K items gives roughly 90% hit rate anecdotally on a + # small range of test blocks - this number could be studied in more detail + # Per EIP-170, a the code of a contract can be up to `MAX_CODE_SIZE` = 24kb, + # which would cause a worst case of 386MB memory usage though in reality + # code sizes are much smaller - it would make sense to study these numbers + # in greater detail. + slotsLruSize = 16 * 1024 + +type + AccountFlag = enum + Alive + IsNew + Dirty + Touched + CodeChanged + StorageChanged + NewlyCreated # EIP-6780: self destruct only in same transaction + + AccountFlags = set[AccountFlag] + + AccountRef = ref object + statement: CoreDbAccount + accPath: Hash32 + flags: AccountFlags + code: CodeBytesRef + originalStorage: TableRef[UInt256, UInt256] + overlayStorage: Table[UInt256, UInt256] + + WitnessData* = object + storageKeys*: HashSet[UInt256] + codeTouched*: bool + + LedgerRef* = ref object + ledger: CoreDbAccRef # AccountLedger + kvt: CoreDbKvtRef + savePoint: LedgerSpRef + witnessCache: Table[Address, WitnessData] + isDirty: bool + ripemdSpecial: bool + storeSlotHash*: bool + cache: Table[Address, AccountRef] + # Second-level cache for the ledger save point, which is cleared on every + # persist + code: LruCache[Hash32, CodeBytesRef] + ## The code cache provides two main benefits: + ## + ## * duplicate code is shared in memory beween accounts + ## * the jump destination table does not have to be recomputed for every + ## execution, for commonly called called contracts + ## + ## The former feature is specially important in the 2.3-2.7M block range + ## when underpriced code opcodes are being run en masse - both advantages + ## help performance broadly as well. + + slots: LruCache[UInt256, Hash32] + ## Because the same slots often reappear, we want to avoid writing them + ## over and over again to the database to avoid the WAL and compation + ## write amplification that ensues + + ReadOnlyStateDB* = distinct LedgerRef + + TransactionState = enum + Pending + Committed + RolledBack + + LedgerSpRef* = ref object + parentSavepoint: LedgerSpRef + cache: Table[Address, AccountRef] + dirty: Table[Address, AccountRef] + selfDestruct: HashSet[Address] + logEntries: seq[Log] + accessList: ac_access_list.AccessList + transientStorage: TransientStorage + state: TransactionState + when debugLedgerRef: + depth: int + +const + emptyEthAccount = Account.init() + + resetFlags = { + Dirty, + IsNew, + Touched, + CodeChanged, + StorageChanged, + NewlyCreated + } + +when debugLedgerRef: + import + stew/byteutils + + proc inspectSavePoint(name: string, x: LedgerSpRef) = + debugEcho "*** ", name, ": ", x.depth, " ***" + var sp = x + while sp != nil: + for address, acc in sp.cache: + debugEcho address.toHex, " ", acc.flags + sp = sp.parentSavepoint + +template logTxt(info: static[string]): static[string] = + "LedgerRef " & info + +template toAccountKey(acc: AccountRef): Hash32 = + acc.accPath + +template toAccountKey(eAddr: Address): Hash32 = + eAddr.data.keccak256 + + +proc beginSavepoint*(ac: LedgerRef): LedgerSpRef {.gcsafe.} + +proc resetCoreDbAccount(ac: LedgerRef, acc: AccountRef) = + const info = "resetCoreDbAccount(): " + ac.ledger.clearStorage(acc.toAccountKey).isOkOr: + raiseAssert info & $$error + acc.statement.nonce = emptyEthAccount.nonce + acc.statement.balance = emptyEthAccount.balance + acc.statement.codeHash = emptyEthAccount.codeHash + +proc getAccount( + ac: LedgerRef; + address: Address; + shouldCreate = true; + ): AccountRef = + + # search account from layers of cache + var sp = ac.savePoint + while sp != nil: + result = sp.cache.getOrDefault(address) + if not result.isNil: + return + sp = sp.parentSavepoint + + if ac.cache.pop(address, result): + # Check second-level cache + ac.savePoint.cache[address] = result + return + + # not found in cache, look into state trie + let + accPath = address.toAccountKey + rc = ac.ledger.fetch accPath + if rc.isOk: + result = AccountRef( + statement: rc.value, + accPath: accPath, + flags: {Alive}) + elif shouldCreate: + result = AccountRef( + statement: CoreDbAccount( + nonce: emptyEthAccount.nonce, + balance: emptyEthAccount.balance, + codeHash: emptyEthAccount.codeHash), + accPath: accPath, + flags: {Alive, IsNew}) + else: + return # ignore, don't cache + + # cache the account + ac.savePoint.cache[address] = result + ac.savePoint.dirty[address] = result + +proc clone(acc: AccountRef, cloneStorage: bool): AccountRef = + result = AccountRef( + statement: acc.statement, + accPath: acc.accPath, + flags: acc.flags, + code: acc.code) + + if cloneStorage: + result.originalStorage = acc.originalStorage + # it's ok to clone a table this way + result.overlayStorage = acc.overlayStorage + +proc isEmpty(acc: AccountRef): bool = + acc.statement.nonce == 0 and + acc.statement.balance.isZero and + acc.statement.codeHash == EMPTY_CODE_HASH + +template exists(acc: AccountRef): bool = + Alive in acc.flags + +proc originalStorageValue( + acc: AccountRef; + slot: UInt256; + ac: LedgerRef; + ): UInt256 = + # share the same original storage between multiple + # versions of account + if acc.originalStorage.isNil: + acc.originalStorage = newTable[UInt256, UInt256]() + else: + acc.originalStorage[].withValue(slot, val) do: + return val[] + + # Not in the original values cache - go to the DB. + let + slotKey = ac.slots.get(slot).valueOr: + slot.toBytesBE.keccak256 + rc = ac.ledger.slotFetch(acc.toAccountKey, slotKey) + if rc.isOk: + result = rc.value + + acc.originalStorage[slot] = result + +proc storageValue( + acc: AccountRef; + slot: UInt256; + ac: LedgerRef; + ): UInt256 = + acc.overlayStorage.withValue(slot, val) do: + return val[] + do: + result = acc.originalStorageValue(slot, ac) + +proc kill(ac: LedgerRef, acc: AccountRef) = + acc.flags.excl Alive + acc.overlayStorage.clear() + acc.originalStorage = nil + ac.resetCoreDbAccount acc + acc.code.reset() + +type + PersistMode = enum + DoNothing + Update + Remove + +proc persistMode(acc: AccountRef): PersistMode = + result = DoNothing + if Alive in acc.flags: + if IsNew in acc.flags or Dirty in acc.flags: + result = Update + else: + if IsNew notin acc.flags: + result = Remove + +proc persistCode(acc: AccountRef, ac: LedgerRef) = + if acc.code.len != 0 and not acc.code.persisted: + let rc = ac.kvt.put( + contractHashKey(acc.statement.codeHash).toOpenArray, acc.code.bytes()) + if rc.isErr: + warn logTxt "persistCode()", + codeHash=acc.statement.codeHash, error=($$rc.error) + else: + # If the ledger changes rolled back entirely from the database, the ledger + # code cache must also be cleared! + acc.code.persisted = true + +proc persistStorage(acc: AccountRef, ac: LedgerRef) = + const info = "persistStorage(): " + + if acc.overlayStorage.len == 0: + # TODO: remove the storage too if we figure out + # how to create 'virtual' storage room for each account + return + + if acc.originalStorage.isNil: + acc.originalStorage = newTable[UInt256, UInt256]() + + # Make sure that there is an account entry on the database. This is needed by + # `Aristo` for updating the account's storage area reference. As a side effect, + # this action also updates the latest statement data. + ac.ledger.merge(acc.toAccountKey, acc.statement).isOkOr: + raiseAssert info & $$error + + # Save `overlayStorage[]` on database + for slot, value in acc.overlayStorage: + acc.originalStorage[].withValue(slot, v): + if v[] == value: + continue # Avoid writing A-B-A updates + + var cached = true + let slotKey = ac.slots.get(slot).valueOr: + cached = false + let hash = slot.toBytesBE.keccak256 + ac.slots.put(slot, hash) + hash + + if value > 0: + ac.ledger.slotMerge(acc.toAccountKey, slotKey, value).isOkOr: + raiseAssert info & $$error + + # move the overlayStorage to originalStorage, related to EIP2200, EIP1283 + acc.originalStorage[slot] = value + + else: + ac.ledger.slotDelete(acc.toAccountKey, slotKey).isOkOr: + if error.error != StoNotFound: + raiseAssert info & $$error + discard + acc.originalStorage.del(slot) + + if ac.storeSlotHash and not cached: + # Write only if it was not cached to avoid writing the same data over and + # over.. + let + key = slotKey.data.slotHashToSlotKey + rc = ac.kvt.put(key.toOpenArray, blobify(slot).data) + if rc.isErr: + warn logTxt "persistStorage()", slot, error=($$rc.error) + + acc.overlayStorage.clear() + +proc makeDirty(ac: LedgerRef, address: Address, cloneStorage = true): AccountRef = + ac.isDirty = true + result = ac.getAccount(address) + if address in ac.savePoint.cache: + # it's already in latest savepoint + result.flags.incl Dirty + ac.savePoint.dirty[address] = result + return + + # put a copy into latest savepoint + result = result.clone(cloneStorage) + result.flags.incl Dirty + ac.savePoint.cache[address] = result + ac.savePoint.dirty[address] = result # ------------------------------------------------------------------------------ -# Public constructor +# Public methods # ------------------------------------------------------------------------------ -proc init*(_: type LedgerRef, db: CoreDbRef, storeSlotHash: bool = false): LedgerRef = - LedgerRef(ac: AccountsLedgerRef.init(db, storeSlotHash)).bless(db) +# The LedgerRef is modeled after TrieDatabase for it's transaction style +proc init*(x: typedesc[LedgerRef], db: CoreDbRef, storeSlotHash: bool): LedgerRef = + new result + result.ledger = db.ctx.getAccounts() + result.kvt = db.ctx.getKvt() + result.witnessCache = Table[Address, WitnessData]() + result.storeSlotHash = storeSlotHash + result.code = typeof(result.code).init(codeLruSize) + result.slots = typeof(result.slots).init(slotsLruSize) + discard result.beginSavepoint + +proc init*(x: typedesc[LedgerRef], db: CoreDbRef): LedgerRef = + init(x, db, false) + +proc getStateRoot*(ac: LedgerRef): Hash32 = + const info = "state(): " + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + # make sure all cache already committed + doAssert(ac.isDirty == false) + ac.ledger.stateRoot(updateOk=true).valueOr: + raiseAssert info & $$error + +proc isTopLevelClean*(ac: LedgerRef): bool = + ## Getter, returns `true` if all pending data have been commited. + not ac.isDirty and ac.savePoint.parentSavepoint.isNil + +proc beginSavepoint*(ac: LedgerRef): LedgerSpRef = + new result + result.cache = Table[Address, AccountRef]() + result.accessList.init() + result.transientStorage.init() + result.state = Pending + result.parentSavepoint = ac.savePoint + ac.savePoint = result + + when debugLedgerRef: + if not result.parentSavePoint.isNil: + result.depth = result.parentSavePoint.depth + 1 + inspectSavePoint("snapshot", result) + +proc rollback*(ac: LedgerRef, sp: LedgerSpRef) = + # Transactions should be handled in a strictly nested fashion. + # Any child transaction must be committed or rolled-back before + # its parent transactions: + doAssert ac.savePoint == sp and sp.state == Pending + ac.savePoint = sp.parentSavepoint + sp.state = RolledBack + + when debugLedgerRef: + inspectSavePoint("rollback", ac.savePoint) + +proc commit*(ac: LedgerRef, sp: LedgerSpRef) = + # Transactions should be handled in a strictly nested fashion. + # Any child transaction must be committed or rolled-back before + # its parent transactions: + doAssert ac.savePoint == sp and sp.state == Pending + # cannot commit most inner savepoint + doAssert not sp.parentSavepoint.isNil + + ac.savePoint = sp.parentSavepoint + ac.savePoint.cache.mergeAndReset(sp.cache) + ac.savePoint.dirty.mergeAndReset(sp.dirty) + ac.savePoint.transientStorage.mergeAndReset(sp.transientStorage) + ac.savePoint.accessList.mergeAndReset(sp.accessList) + ac.savePoint.selfDestruct.mergeAndReset(sp.selfDestruct) + ac.savePoint.logEntries.mergeAndReset(sp.logEntries) + sp.state = Committed + + when debugLedgerRef: + inspectSavePoint("commit", ac.savePoint) + +proc dispose*(ac: LedgerRef, sp: LedgerSpRef) = + if sp.state == Pending: + ac.rollback(sp) + +proc safeDispose*(ac: LedgerRef, sp: LedgerSpRef) = + if (not isNil(sp)) and (sp.state == Pending): + ac.rollback(sp) + +proc getCodeHash*(ac: LedgerRef, address: Address): Hash32 = + let acc = ac.getAccount(address, false) + if acc.isNil: emptyEthAccount.codeHash + else: acc.statement.codeHash + +proc getBalance*(ac: LedgerRef, address: Address): UInt256 = + let acc = ac.getAccount(address, false) + if acc.isNil: emptyEthAccount.balance + else: acc.statement.balance + +proc getNonce*(ac: LedgerRef, address: Address): AccountNonce = + let acc = ac.getAccount(address, false) + if acc.isNil: emptyEthAccount.nonce + else: acc.statement.nonce + +proc getCode*(ac: LedgerRef, address: Address): CodeBytesRef = + # Always returns non-nil! + let acc = ac.getAccount(address, false) + if acc.isNil: + return CodeBytesRef() + + if acc.code == nil: + acc.code = + if acc.statement.codeHash != EMPTY_CODE_HASH: + ac.code.get(acc.statement.codeHash).valueOr: + var rc = ac.kvt.get(contractHashKey(acc.statement.codeHash).toOpenArray) + if rc.isErr: + warn logTxt "getCode()", codeHash=acc.statement.codeHash, error=($$rc.error) + CodeBytesRef() + else: + let newCode = CodeBytesRef.init(move(rc.value), persisted = true) + ac.code.put(acc.statement.codeHash, newCode) + newCode + else: + CodeBytesRef() + + acc.code + +proc getCodeSize*(ac: LedgerRef, address: Address): int = + let acc = ac.getAccount(address, false) + if acc.isNil: + return 0 + + if acc.code == nil: + if acc.statement.codeHash == EMPTY_CODE_HASH: + return 0 + acc.code = ac.code.get(acc.statement.codeHash).valueOr: + # On a cache miss, we don't fetch the code - instead, we fetch just the + # length - should the code itself be needed, it will typically remain + # cached and easily accessible in the database layer - this is to prevent + # EXTCODESIZE calls from messing up the code cache and thus causing + # recomputation of the jump destination table + var rc = ac.kvt.len(contractHashKey(acc.statement.codeHash).toOpenArray) + + return rc.valueOr: + warn logTxt "getCodeSize()", codeHash=acc.statement.codeHash, error=($$rc.error) + 0 + + acc.code.len() + +proc getCommittedStorage*(ac: LedgerRef, address: Address, slot: UInt256): UInt256 = + let acc = ac.getAccount(address, false) + if acc.isNil: + return + acc.originalStorageValue(slot, ac) + +proc getStorage*(ac: LedgerRef, address: Address, slot: UInt256): UInt256 = + let acc = ac.getAccount(address, false) + if acc.isNil: + return + acc.storageValue(slot, ac) + +proc contractCollision*(ac: LedgerRef, address: Address): bool = + let acc = ac.getAccount(address, false) + if acc.isNil: + return + acc.statement.nonce != 0 or + acc.statement.codeHash != EMPTY_CODE_HASH or + not ac.ledger.slotStateEmptyOrVoid(acc.toAccountKey) + +proc accountExists*(ac: LedgerRef, address: Address): bool = + let acc = ac.getAccount(address, false) + if acc.isNil: + return + acc.exists() + +proc isEmptyAccount*(ac: LedgerRef, address: Address): bool = + let acc = ac.getAccount(address, false) + doAssert not acc.isNil + doAssert acc.exists() + acc.isEmpty() + +proc isDeadAccount*(ac: LedgerRef, address: Address): bool = + let acc = ac.getAccount(address, false) + if acc.isNil: + return true + if not acc.exists(): + return true + acc.isEmpty() + +proc setBalance*(ac: LedgerRef, address: Address, balance: UInt256) = + let acc = ac.getAccount(address) + acc.flags.incl {Alive} + if acc.statement.balance != balance: + ac.makeDirty(address).statement.balance = balance + +proc addBalance*(ac: LedgerRef, address: Address, delta: UInt256) = + # EIP161: We must check emptiness for the objects such that the account + # clearing (0,0,0 objects) can take effect. + if delta.isZero: + let acc = ac.getAccount(address) + if acc.isEmpty: + ac.makeDirty(address).flags.incl Touched + return + ac.setBalance(address, ac.getBalance(address) + delta) + +proc subBalance*(ac: LedgerRef, address: Address, delta: UInt256) = + if delta.isZero: + # This zero delta early exit is important as shown in EIP-4788. + # If the account is created, it will change the state. + # But early exit will prevent the account creation. + # In this case, the SYSTEM_ADDRESS + return + ac.setBalance(address, ac.getBalance(address) - delta) + +proc setNonce*(ac: LedgerRef, address: Address, nonce: AccountNonce) = + let acc = ac.getAccount(address) + acc.flags.incl {Alive} + if acc.statement.nonce != nonce: + ac.makeDirty(address).statement.nonce = nonce + +proc incNonce*(ac: LedgerRef, address: Address) = + ac.setNonce(address, ac.getNonce(address) + 1) + +proc setCode*(ac: LedgerRef, address: Address, code: seq[byte]) = + let acc = ac.getAccount(address) + acc.flags.incl {Alive} + let codeHash = keccak256(code) + if acc.statement.codeHash != codeHash: + var acc = ac.makeDirty(address) + acc.statement.codeHash = codeHash + # Try to reuse cache entry if it exists, but don't save the code - it's not + # a given that it will be executed within LRU range + acc.code = ac.code.get(codeHash).valueOr(CodeBytesRef.init(code)) + acc.flags.incl CodeChanged + +proc setStorage*(ac: LedgerRef, address: Address, slot, value: UInt256) = + let acc = ac.getAccount(address) + acc.flags.incl {Alive} + let oldValue = acc.storageValue(slot, ac) + if oldValue != value: + var acc = ac.makeDirty(address) + acc.overlayStorage[slot] = value + acc.flags.incl StorageChanged + +proc clearStorage*(ac: LedgerRef, address: Address) = + const info = "clearStorage(): " + + # a.k.a createStateObject. If there is an existing account with + # the given address, it is overwritten. + + let acc = ac.getAccount(address) + acc.flags.incl {Alive, NewlyCreated} + + let empty = ac.ledger.slotStateEmpty(acc.toAccountKey).valueOr: return + if not empty: + # need to clear the storage from the database first + let acc = ac.makeDirty(address, cloneStorage = false) + ac.ledger.clearStorage(acc.toAccountKey).isOkOr: + raiseAssert info & $$error + # update caches + if acc.originalStorage.isNil.not: + # also clear originalStorage cache, otherwise + # both getStorage and getCommittedStorage will + # return wrong value + acc.originalStorage.clear() + +proc deleteAccount*(ac: LedgerRef, address: Address) = + # make sure all savepoints already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + let acc = ac.getAccount(address) + ac.savePoint.dirty[address] = acc + ac.kill acc + +proc selfDestruct*(ac: LedgerRef, address: Address) = + ac.setBalance(address, 0.u256) + ac.savePoint.selfDestruct.incl address + +proc selfDestruct6780*(ac: LedgerRef, address: Address) = + let acc = ac.getAccount(address, false) + if acc.isNil: + return + + if NewlyCreated in acc.flags: + ac.selfDestruct(address) + +proc selfDestructLen*(ac: LedgerRef): int = + ac.savePoint.selfDestruct.len + +proc addLogEntry*(ac: LedgerRef, log: Log) = + ac.savePoint.logEntries.add log + +proc getAndClearLogEntries*(ac: LedgerRef): seq[Log] = + swap(result, ac.savePoint.logEntries) + +proc ripemdSpecial*(ac: LedgerRef) = + ac.ripemdSpecial = true + +proc deleteEmptyAccount(ac: LedgerRef, address: Address) = + let acc = ac.getAccount(address, false) + if acc.isNil: + return + if not acc.isEmpty: + return + if not acc.exists: + return + + ac.savePoint.dirty[address] = acc + ac.kill acc + +proc clearEmptyAccounts(ac: LedgerRef) = + # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md + for acc in ac.savePoint.dirty.values(): + if Touched in acc.flags and + acc.isEmpty and acc.exists: + ac.kill acc + + # https://github.com/ethereum/EIPs/issues/716 + if ac.ripemdSpecial: + ac.deleteEmptyAccount(RIPEMD_ADDR) + ac.ripemdSpecial = false + +proc persist*(ac: LedgerRef, + clearEmptyAccount: bool = false, + clearCache = false) = + const info = "persist(): " + + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + + if clearEmptyAccount: + ac.clearEmptyAccounts() + + for address in ac.savePoint.selfDestruct: + ac.deleteAccount(address) + + for (eAddr,acc) in ac.savePoint.dirty.pairs(): # This is a hotspot in block processing + case acc.persistMode() + of Update: + if CodeChanged in acc.flags: + acc.persistCode(ac) + if StorageChanged in acc.flags: + acc.persistStorage(ac) + else: + # This one is only necessary unless `persistStorage()` is run which needs + # to `merge()` the latest statement as well. + ac.ledger.merge(acc.toAccountKey, acc.statement).isOkOr: + raiseAssert info & $$error + of Remove: + ac.ledger.delete(acc.toAccountKey).isOkOr: + if error.error != AccNotFound: + raiseAssert info & $$error + ac.savePoint.cache.del eAddr + of DoNothing: + # dead man tell no tales + # remove touched dead account from cache + if Alive notin acc.flags: + ac.savePoint.cache.del eAddr + + acc.flags = acc.flags - resetFlags + ac.savePoint.dirty.clear() + + if clearCache: + # This overwrites the cache from the previous persist, providing a crude LRU + # scheme with little overhead + # TODO https://github.com/nim-lang/Nim/issues/23759 + swap(ac.cache, ac.savePoint.cache) + ac.savePoint.cache.reset() + + ac.savePoint.selfDestruct.clear() + + # EIP2929 + ac.savePoint.accessList.clear() + + ac.isDirty = false + +iterator addresses*(ac: LedgerRef): Address = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + for address, _ in ac.savePoint.cache: + yield address + +iterator accounts*(ac: LedgerRef): Account = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + for _, acc in ac.savePoint.cache: + yield ac.ledger.recast( + acc.toAccountKey, acc.statement, updateOk=true).value + +iterator pairs*(ac: LedgerRef): (Address, Account) = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + for address, acc in ac.savePoint.cache: + yield (address, ac.ledger.recast( + acc.toAccountKey, acc.statement, updateOk=true).value) + +iterator storage*( + ac: LedgerRef; + eAddr: Address; + ): (UInt256, UInt256) = + # beware that if the account not persisted, + # the storage root will not be updated + for (slotHash, value) in ac.ledger.slotPairs eAddr.toAccountKey: + let rc = ac.kvt.get(slotHashToSlotKey(slotHash).toOpenArray) + if rc.isErr: + warn logTxt "storage()", slotHash, error=($$rc.error) + continue + let r = deblobify(rc.value, UInt256) + if r.isErr: + warn logTxt "storage.deblobify", slotHash, msg=r.error + continue + yield (r.value, value) + +iterator cachedStorage*(ac: LedgerRef, address: Address): (UInt256, UInt256) = + let acc = ac.getAccount(address, false) + if not acc.isNil: + if not acc.originalStorage.isNil: + for k, v in acc.originalStorage: + yield (k, v) + +proc getStorageRoot*(ac: LedgerRef, address: Address): Hash32 = + # beware that if the account not persisted, + # the storage root will not be updated + let acc = ac.getAccount(address, false) + if acc.isNil: EMPTY_ROOT_HASH + else: ac.ledger.slotState(acc.toAccountKey).valueOr: EMPTY_ROOT_HASH + +proc update(wd: var WitnessData, acc: AccountRef) = + # once the code is touched make sure it doesn't get reset back to false in another update + if not wd.codeTouched: + wd.codeTouched = CodeChanged in acc.flags or acc.code != nil + + if not acc.originalStorage.isNil: + for k, v in acc.originalStorage: + if v.isZero: continue + wd.storageKeys.incl k + + for k, v in acc.overlayStorage: + wd.storageKeys.incl k + +proc witnessData(acc: AccountRef): WitnessData = + result.storageKeys = HashSet[UInt256]() + update(result, acc) + +proc collectWitnessData*(ac: LedgerRef) = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + # usually witness data is collected before we call persist() + for address, acc in ac.savePoint.cache: + ac.witnessCache.withValue(address, val) do: + update(val[], acc) + do: + ac.witnessCache[address] = witnessData(acc) + +func multiKeys(slots: HashSet[UInt256]): MultiKeysRef = + if slots.len == 0: return + new result + for x in slots: + result.add x.toBytesBE + result.sort() + +proc makeMultiKeys*(ac: LedgerRef): MultiKeysRef = + # this proc is called after we done executing a block + new result + for k, v in ac.witnessCache: + result.add(k, v.codeTouched, multiKeys(v.storageKeys)) + result.sort() + +proc accessList*(ac: LedgerRef, address: Address) = + ac.savePoint.accessList.add(address) + +proc accessList*(ac: LedgerRef, address: Address, slot: UInt256) = + ac.savePoint.accessList.add(address, slot) + +func inAccessList*(ac: LedgerRef, address: Address): bool = + var sp = ac.savePoint + while sp != nil: + result = sp.accessList.contains(address) + if result: + return + sp = sp.parentSavepoint + +func inAccessList*(ac: LedgerRef, address: Address, slot: UInt256): bool = + var sp = ac.savePoint + while sp != nil: + result = sp.accessList.contains(address, slot) + if result: + return + sp = sp.parentSavepoint + +func getTransientStorage*(ac: LedgerRef, + address: Address, slot: UInt256): UInt256 = + var sp = ac.savePoint + while sp != nil: + let (ok, res) = sp.transientStorage.getStorage(address, slot) + if ok: + return res + sp = sp.parentSavepoint + +proc setTransientStorage*(ac: LedgerRef, + address: Address, slot, val: UInt256) = + ac.savePoint.transientStorage.setStorage(address, slot, val) + +proc clearTransientStorage*(ac: LedgerRef) = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + ac.savePoint.transientStorage.clear() + +func getAccessList*(ac: LedgerRef): common.AccessList = + # make sure all savepoint already committed + doAssert(ac.savePoint.parentSavepoint.isNil) + ac.savePoint.accessList.getAccessList() + +proc getEthAccount*(ac: LedgerRef, address: Address): Account = + let acc = ac.getAccount(address, false) + if acc.isNil: + return emptyEthAccount + + ## Convert to legacy object, will throw an assert if that fails + let rc = ac.ledger.recast(acc.toAccountKey, acc.statement) + if rc.isErr: + raiseAssert "getAccount(): cannot convert account: " & $$rc.error + rc.value + +proc getAccountProof*(ac: LedgerRef, address: Address): seq[seq[byte]] = + let accProof = ac.ledger.proof(address.toAccountKey).valueOr: + raiseAssert "Failed to get account proof: " & $$error + + accProof[0] + +proc getStorageProof*(ac: LedgerRef, address: Address, slots: openArray[UInt256]): seq[seq[seq[byte]]] = + var storageProof = newSeqOfCap[seq[seq[byte]]](slots.len) + + let + addressHash = address.toAccountKey + accountExists = ac.ledger.hasPath(addressHash).valueOr: + raiseAssert "Call to hasPath failed: " & $$error + + for slot in slots: + if not accountExists: + storageProof.add(@[]) + continue + + let + slotKey = ac.slots.get(slot).valueOr: + slot.toBytesBE.keccak256 + slotProof = ac.ledger.slotProof(addressHash, slotKey).valueOr: + if error.aErr == FetchPathNotFound: + storageProof.add(@[]) + continue + else: + raiseAssert "Failed to get slot proof: " & $$error + storageProof.add(slotProof[0]) + + storageProof + +# ------------------------------------------------------------------------------ +# Public virtual read-only methods +# ------------------------------------------------------------------------------ + +proc getStateRoot*(db: ReadOnlyStateDB): Hash32 {.borrow.} +proc getCodeHash*(db: ReadOnlyStateDB, address: Address): Hash32 = getCodeHash(distinctBase db, address) +proc getStorageRoot*(db: ReadOnlyStateDB, address: Address): Hash32 = getStorageRoot(distinctBase db, address) +proc getBalance*(db: ReadOnlyStateDB, address: Address): UInt256 = getBalance(distinctBase db, address) +proc getStorage*(db: ReadOnlyStateDB, address: Address, slot: UInt256): UInt256 = getStorage(distinctBase db, address, slot) +proc getNonce*(db: ReadOnlyStateDB, address: Address): AccountNonce = getNonce(distinctBase db, address) +proc getCode*(db: ReadOnlyStateDB, address: Address): CodeBytesRef = getCode(distinctBase db, address) +proc getCodeSize*(db: ReadOnlyStateDB, address: Address): int = getCodeSize(distinctBase db, address) +proc contractCollision*(db: ReadOnlyStateDB, address: Address): bool = contractCollision(distinctBase db, address) +proc accountExists*(db: ReadOnlyStateDB, address: Address): bool = accountExists(distinctBase db, address) +proc isDeadAccount*(db: ReadOnlyStateDB, address: Address): bool = isDeadAccount(distinctBase db, address) +proc isEmptyAccount*(db: ReadOnlyStateDB, address: Address): bool = isEmptyAccount(distinctBase db, address) +proc getCommittedStorage*(db: ReadOnlyStateDB, address: Address, slot: UInt256): UInt256 = getCommittedStorage(distinctBase db, address, slot) +proc inAccessList*(db: ReadOnlyStateDB, address: Address): bool = inAccessList(distinctBase db, address) +proc inAccessList*(db: ReadOnlyStateDB, address: Address, slot: UInt256): bool = inAccessList(distinctBase db, address) +proc getTransientStorage*(db: ReadOnlyStateDB, + address: Address, slot: UInt256): UInt256 = getTransientStorage(distinctBase db, address, slot) +proc getAccountProof*(db: ReadOnlyStateDB, address: Address): seq[seq[byte]] = getAccountProof(distinctBase db, address) +proc getStorageProof*(db: ReadOnlyStateDB, address: Address, slots: openArray[UInt256]): seq[seq[seq[byte]]] = getStorageProof(distinctBase db, address, slots) # ------------------------------------------------------------------------------ # End diff --git a/nimbus/db/ledger/backend/accounts_ledger.nim b/nimbus/db/ledger/backend/accounts_ledger.nim deleted file mode 100644 index 2b23b4252..000000000 --- a/nimbus/db/ledger/backend/accounts_ledger.nim +++ /dev/null @@ -1,916 +0,0 @@ -# Nimbus -# 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. - -{.push raises: [].} - -import - std/[tables, hashes, sets, typetraits], - chronicles, - eth/common/eth_types, - results, - minilru, - ../../../utils/mergeutils, - ../../../evm/code_bytes, - ../../../stateless/multi_keys, - "../../.."/[constants, utils/utils], - ../../access_list as ac_access_list, - "../.."/[core_db, storage_types, transient_storage], - ../../aristo/aristo_blobify - -const - debugAccountsLedgerRef = false - codeLruSize = 16*1024 - # An LRU cache of 16K items gives roughly 90% hit rate anecdotally on a - # small range of test blocks - this number could be studied in more detail - # Per EIP-170, a the code of a contract can be up to `MAX_CODE_SIZE` = 24kb, - # which would cause a worst case of 386MB memory usage though in reality - # code sizes are much smaller - it would make sense to study these numbers - # in greater detail. - slotsLruSize = 16 * 1024 - -type - AccountFlag = enum - Alive - IsNew - Dirty - Touched - CodeChanged - StorageChanged - NewlyCreated # EIP-6780: self destruct only in same transaction - - AccountFlags = set[AccountFlag] - - AccountRef = ref object - statement: CoreDbAccount - accPath: Hash32 - flags: AccountFlags - code: CodeBytesRef - originalStorage: TableRef[UInt256, UInt256] - overlayStorage: Table[UInt256, UInt256] - - WitnessData* = object - storageKeys*: HashSet[UInt256] - codeTouched*: bool - - AccountsLedgerRef* = ref object - ledger: CoreDbAccRef # AccountLedger - kvt: CoreDbKvtRef - savePoint: LedgerSavePoint - witnessCache: Table[Address, WitnessData] - isDirty: bool - ripemdSpecial: bool - storeSlotHash*: bool - cache: Table[Address, AccountRef] - # Second-level cache for the ledger save point, which is cleared on every - # persist - code: LruCache[Hash32, CodeBytesRef] - ## The code cache provides two main benefits: - ## - ## * duplicate code is shared in memory beween accounts - ## * the jump destination table does not have to be recomputed for every - ## execution, for commonly called called contracts - ## - ## The former feature is specially important in the 2.3-2.7M block range - ## when underpriced code opcodes are being run en masse - both advantages - ## help performance broadly as well. - - slots: LruCache[UInt256, Hash32] - ## Because the same slots often reappear, we want to avoid writing them - ## over and over again to the database to avoid the WAL and compation - ## write amplification that ensues - - ReadOnlyStateDB* = distinct AccountsLedgerRef - - TransactionState = enum - Pending - Committed - RolledBack - - LedgerSavePoint* = ref object - parentSavepoint: LedgerSavePoint - cache: Table[Address, AccountRef] - dirty: Table[Address, AccountRef] - selfDestruct: HashSet[Address] - logEntries: seq[Log] - accessList: ac_access_list.AccessList - transientStorage: TransientStorage - state: TransactionState - when debugAccountsLedgerRef: - depth: int - -const - emptyEthAccount = Account.init() - - resetFlags = { - Dirty, - IsNew, - Touched, - CodeChanged, - StorageChanged, - NewlyCreated - } - -when debugAccountsLedgerRef: - import - stew/byteutils - - proc inspectSavePoint(name: string, x: LedgerSavePoint) = - debugEcho "*** ", name, ": ", x.depth, " ***" - var sp = x - while sp != nil: - for address, acc in sp.cache: - debugEcho address.toHex, " ", acc.flags - sp = sp.parentSavepoint - -template logTxt(info: static[string]): static[string] = - "AccountsLedgerRef " & info - -template toAccountKey(acc: AccountRef): Hash32 = - acc.accPath - -template toAccountKey(eAddr: Address): Hash32 = - eAddr.data.keccak256 - - -proc beginSavepoint*(ac: AccountsLedgerRef): LedgerSavePoint {.gcsafe.} - -proc resetCoreDbAccount(ac: AccountsLedgerRef, acc: AccountRef) = - const info = "resetCoreDbAccount(): " - ac.ledger.clearStorage(acc.toAccountKey).isOkOr: - raiseAssert info & $$error - acc.statement.nonce = emptyEthAccount.nonce - acc.statement.balance = emptyEthAccount.balance - acc.statement.codeHash = emptyEthAccount.codeHash - -# The AccountsLedgerRef is modeled after TrieDatabase for it's transaction style -proc init*(x: typedesc[AccountsLedgerRef], db: CoreDbRef, storeSlotHash: bool): AccountsLedgerRef = - new result - result.ledger = db.ctx.getAccounts() - result.kvt = db.ctx.getKvt() - result.witnessCache = Table[Address, WitnessData]() - result.storeSlotHash = storeSlotHash - result.code = typeof(result.code).init(codeLruSize) - result.slots = typeof(result.slots).init(slotsLruSize) - discard result.beginSavepoint - -proc init*(x: typedesc[AccountsLedgerRef], db: CoreDbRef): AccountsLedgerRef = - init(x, db, EMPTY_ROOT_HASH) - -proc getStateRoot*(ac: AccountsLedgerRef): Hash32 = - const info = "state(): " - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - # make sure all cache already committed - doAssert(ac.isDirty == false) - ac.ledger.stateRoot(updateOk=true).valueOr: - raiseAssert info & $$error - -proc isTopLevelClean*(ac: AccountsLedgerRef): bool = - ## Getter, returns `true` if all pending data have been commited. - not ac.isDirty and ac.savePoint.parentSavepoint.isNil - -proc beginSavepoint*(ac: AccountsLedgerRef): LedgerSavePoint = - new result - result.cache = Table[Address, AccountRef]() - result.accessList.init() - result.transientStorage.init() - result.state = Pending - result.parentSavepoint = ac.savePoint - ac.savePoint = result - - when debugAccountsLedgerRef: - if not result.parentSavePoint.isNil: - result.depth = result.parentSavePoint.depth + 1 - inspectSavePoint("snapshot", result) - -proc rollback*(ac: AccountsLedgerRef, sp: LedgerSavePoint) = - # Transactions should be handled in a strictly nested fashion. - # Any child transaction must be committed or rolled-back before - # its parent transactions: - doAssert ac.savePoint == sp and sp.state == Pending - ac.savePoint = sp.parentSavepoint - sp.state = RolledBack - - when debugAccountsLedgerRef: - inspectSavePoint("rollback", ac.savePoint) - -proc commit*(ac: AccountsLedgerRef, sp: LedgerSavePoint) = - # Transactions should be handled in a strictly nested fashion. - # Any child transaction must be committed or rolled-back before - # its parent transactions: - doAssert ac.savePoint == sp and sp.state == Pending - # cannot commit most inner savepoint - doAssert not sp.parentSavepoint.isNil - - ac.savePoint = sp.parentSavepoint - ac.savePoint.cache.mergeAndReset(sp.cache) - ac.savePoint.dirty.mergeAndReset(sp.dirty) - ac.savePoint.transientStorage.mergeAndReset(sp.transientStorage) - ac.savePoint.accessList.mergeAndReset(sp.accessList) - ac.savePoint.selfDestruct.mergeAndReset(sp.selfDestruct) - ac.savePoint.logEntries.mergeAndReset(sp.logEntries) - sp.state = Committed - - when debugAccountsLedgerRef: - inspectSavePoint("commit", ac.savePoint) - -proc dispose*(ac: AccountsLedgerRef, sp: LedgerSavePoint) = - if sp.state == Pending: - ac.rollback(sp) - -proc safeDispose*(ac: AccountsLedgerRef, sp: LedgerSavePoint) = - if (not isNil(sp)) and (sp.state == Pending): - ac.rollback(sp) - -proc getAccount( - ac: AccountsLedgerRef; - address: Address; - shouldCreate = true; - ): AccountRef = - - # search account from layers of cache - var sp = ac.savePoint - while sp != nil: - result = sp.cache.getOrDefault(address) - if not result.isNil: - return - sp = sp.parentSavepoint - - if ac.cache.pop(address, result): - # Check second-level cache - ac.savePoint.cache[address] = result - return - - # not found in cache, look into state trie - let - accPath = address.toAccountKey - rc = ac.ledger.fetch accPath - if rc.isOk: - result = AccountRef( - statement: rc.value, - accPath: accPath, - flags: {Alive}) - elif shouldCreate: - result = AccountRef( - statement: CoreDbAccount( - nonce: emptyEthAccount.nonce, - balance: emptyEthAccount.balance, - codeHash: emptyEthAccount.codeHash), - accPath: accPath, - flags: {Alive, IsNew}) - else: - return # ignore, don't cache - - # cache the account - ac.savePoint.cache[address] = result - ac.savePoint.dirty[address] = result - -proc clone(acc: AccountRef, cloneStorage: bool): AccountRef = - result = AccountRef( - statement: acc.statement, - accPath: acc.accPath, - flags: acc.flags, - code: acc.code) - - if cloneStorage: - result.originalStorage = acc.originalStorage - # it's ok to clone a table this way - result.overlayStorage = acc.overlayStorage - -proc isEmpty(acc: AccountRef): bool = - acc.statement.nonce == 0 and - acc.statement.balance.isZero and - acc.statement.codeHash == EMPTY_CODE_HASH - -template exists(acc: AccountRef): bool = - Alive in acc.flags - -proc originalStorageValue( - acc: AccountRef; - slot: UInt256; - ac: AccountsLedgerRef; - ): UInt256 = - # share the same original storage between multiple - # versions of account - if acc.originalStorage.isNil: - acc.originalStorage = newTable[UInt256, UInt256]() - else: - acc.originalStorage[].withValue(slot, val) do: - return val[] - - # Not in the original values cache - go to the DB. - let - slotKey = ac.slots.get(slot).valueOr: - slot.toBytesBE.keccak256 - rc = ac.ledger.slotFetch(acc.toAccountKey, slotKey) - if rc.isOk: - result = rc.value - - acc.originalStorage[slot] = result - -proc storageValue( - acc: AccountRef; - slot: UInt256; - ac: AccountsLedgerRef; - ): UInt256 = - acc.overlayStorage.withValue(slot, val) do: - return val[] - do: - result = acc.originalStorageValue(slot, ac) - -proc kill(ac: AccountsLedgerRef, acc: AccountRef) = - acc.flags.excl Alive - acc.overlayStorage.clear() - acc.originalStorage = nil - ac.resetCoreDbAccount acc - acc.code.reset() - -type - PersistMode = enum - DoNothing - Update - Remove - -proc persistMode(acc: AccountRef): PersistMode = - result = DoNothing - if Alive in acc.flags: - if IsNew in acc.flags or Dirty in acc.flags: - result = Update - else: - if IsNew notin acc.flags: - result = Remove - -proc persistCode(acc: AccountRef, ac: AccountsLedgerRef) = - if acc.code.len != 0 and not acc.code.persisted: - let rc = ac.kvt.put( - contractHashKey(acc.statement.codeHash).toOpenArray, acc.code.bytes()) - if rc.isErr: - warn logTxt "persistCode()", - codeHash=acc.statement.codeHash, error=($$rc.error) - else: - # If the ledger changes rolled back entirely from the database, the ledger - # code cache must also be cleared! - acc.code.persisted = true - -proc persistStorage(acc: AccountRef, ac: AccountsLedgerRef) = - const info = "persistStorage(): " - - if acc.overlayStorage.len == 0: - # TODO: remove the storage too if we figure out - # how to create 'virtual' storage room for each account - return - - if acc.originalStorage.isNil: - acc.originalStorage = newTable[UInt256, UInt256]() - - # Make sure that there is an account entry on the database. This is needed by - # `Aristo` for updating the account's storage area reference. As a side effect, - # this action also updates the latest statement data. - ac.ledger.merge(acc.toAccountKey, acc.statement).isOkOr: - raiseAssert info & $$error - - # Save `overlayStorage[]` on database - for slot, value in acc.overlayStorage: - acc.originalStorage[].withValue(slot, v): - if v[] == value: - continue # Avoid writing A-B-A updates - - var cached = true - let slotKey = ac.slots.get(slot).valueOr: - cached = false - let hash = slot.toBytesBE.keccak256 - ac.slots.put(slot, hash) - hash - - if value > 0: - ac.ledger.slotMerge(acc.toAccountKey, slotKey, value).isOkOr: - raiseAssert info & $$error - - # move the overlayStorage to originalStorage, related to EIP2200, EIP1283 - acc.originalStorage[slot] = value - - else: - ac.ledger.slotDelete(acc.toAccountKey, slotKey).isOkOr: - if error.error != StoNotFound: - raiseAssert info & $$error - discard - acc.originalStorage.del(slot) - - if ac.storeSlotHash and not cached: - # Write only if it was not cached to avoid writing the same data over and - # over.. - let - key = slotKey.data.slotHashToSlotKey - rc = ac.kvt.put(key.toOpenArray, blobify(slot).data) - if rc.isErr: - warn logTxt "persistStorage()", slot, error=($$rc.error) - - acc.overlayStorage.clear() - -proc makeDirty(ac: AccountsLedgerRef, address: Address, cloneStorage = true): AccountRef = - ac.isDirty = true - result = ac.getAccount(address) - if address in ac.savePoint.cache: - # it's already in latest savepoint - result.flags.incl Dirty - ac.savePoint.dirty[address] = result - return - - # put a copy into latest savepoint - result = result.clone(cloneStorage) - result.flags.incl Dirty - ac.savePoint.cache[address] = result - ac.savePoint.dirty[address] = result - -proc getCodeHash*(ac: AccountsLedgerRef, address: Address): Hash32 = - let acc = ac.getAccount(address, false) - if acc.isNil: emptyEthAccount.codeHash - else: acc.statement.codeHash - -proc getBalance*(ac: AccountsLedgerRef, address: Address): UInt256 = - let acc = ac.getAccount(address, false) - if acc.isNil: emptyEthAccount.balance - else: acc.statement.balance - -proc getNonce*(ac: AccountsLedgerRef, address: Address): AccountNonce = - let acc = ac.getAccount(address, false) - if acc.isNil: emptyEthAccount.nonce - else: acc.statement.nonce - -proc getCode*(ac: AccountsLedgerRef, address: Address): CodeBytesRef = - # Always returns non-nil! - let acc = ac.getAccount(address, false) - if acc.isNil: - return CodeBytesRef() - - if acc.code == nil: - acc.code = - if acc.statement.codeHash != EMPTY_CODE_HASH: - ac.code.get(acc.statement.codeHash).valueOr: - var rc = ac.kvt.get(contractHashKey(acc.statement.codeHash).toOpenArray) - if rc.isErr: - warn logTxt "getCode()", codeHash=acc.statement.codeHash, error=($$rc.error) - CodeBytesRef() - else: - let newCode = CodeBytesRef.init(move(rc.value), persisted = true) - ac.code.put(acc.statement.codeHash, newCode) - newCode - else: - CodeBytesRef() - - acc.code - -proc getCodeSize*(ac: AccountsLedgerRef, address: Address): int = - let acc = ac.getAccount(address, false) - if acc.isNil: - return 0 - - if acc.code == nil: - if acc.statement.codeHash == EMPTY_CODE_HASH: - return 0 - acc.code = ac.code.get(acc.statement.codeHash).valueOr: - # On a cache miss, we don't fetch the code - instead, we fetch just the - # length - should the code itself be needed, it will typically remain - # cached and easily accessible in the database layer - this is to prevent - # EXTCODESIZE calls from messing up the code cache and thus causing - # recomputation of the jump destination table - var rc = ac.kvt.len(contractHashKey(acc.statement.codeHash).toOpenArray) - - return rc.valueOr: - warn logTxt "getCodeSize()", codeHash=acc.statement.codeHash, error=($$rc.error) - 0 - - acc.code.len() - -proc getCommittedStorage*(ac: AccountsLedgerRef, address: Address, slot: UInt256): UInt256 = - let acc = ac.getAccount(address, false) - if acc.isNil: - return - acc.originalStorageValue(slot, ac) - -proc getStorage*(ac: AccountsLedgerRef, address: Address, slot: UInt256): UInt256 = - let acc = ac.getAccount(address, false) - if acc.isNil: - return - acc.storageValue(slot, ac) - -proc contractCollision*(ac: AccountsLedgerRef, address: Address): bool = - let acc = ac.getAccount(address, false) - if acc.isNil: - return - acc.statement.nonce != 0 or - acc.statement.codeHash != EMPTY_CODE_HASH or - not ac.ledger.slotStateEmptyOrVoid(acc.toAccountKey) - -proc accountExists*(ac: AccountsLedgerRef, address: Address): bool = - let acc = ac.getAccount(address, false) - if acc.isNil: - return - acc.exists() - -proc isEmptyAccount*(ac: AccountsLedgerRef, address: Address): bool = - let acc = ac.getAccount(address, false) - doAssert not acc.isNil - doAssert acc.exists() - acc.isEmpty() - -proc isDeadAccount*(ac: AccountsLedgerRef, address: Address): bool = - let acc = ac.getAccount(address, false) - if acc.isNil: - return true - if not acc.exists(): - return true - acc.isEmpty() - -proc setBalance*(ac: AccountsLedgerRef, address: Address, balance: UInt256) = - let acc = ac.getAccount(address) - acc.flags.incl {Alive} - if acc.statement.balance != balance: - ac.makeDirty(address).statement.balance = balance - -proc addBalance*(ac: AccountsLedgerRef, address: Address, delta: UInt256) = - # EIP161: We must check emptiness for the objects such that the account - # clearing (0,0,0 objects) can take effect. - if delta.isZero: - let acc = ac.getAccount(address) - if acc.isEmpty: - ac.makeDirty(address).flags.incl Touched - return - ac.setBalance(address, ac.getBalance(address) + delta) - -proc subBalance*(ac: AccountsLedgerRef, address: Address, delta: UInt256) = - if delta.isZero: - # This zero delta early exit is important as shown in EIP-4788. - # If the account is created, it will change the state. - # But early exit will prevent the account creation. - # In this case, the SYSTEM_ADDRESS - return - ac.setBalance(address, ac.getBalance(address) - delta) - -proc setNonce*(ac: AccountsLedgerRef, address: Address, nonce: AccountNonce) = - let acc = ac.getAccount(address) - acc.flags.incl {Alive} - if acc.statement.nonce != nonce: - ac.makeDirty(address).statement.nonce = nonce - -proc incNonce*(ac: AccountsLedgerRef, address: Address) = - ac.setNonce(address, ac.getNonce(address) + 1) - -proc setCode*(ac: AccountsLedgerRef, address: Address, code: seq[byte]) = - let acc = ac.getAccount(address) - acc.flags.incl {Alive} - let codeHash = keccak256(code) - if acc.statement.codeHash != codeHash: - var acc = ac.makeDirty(address) - acc.statement.codeHash = codeHash - # Try to reuse cache entry if it exists, but don't save the code - it's not - # a given that it will be executed within LRU range - acc.code = ac.code.get(codeHash).valueOr(CodeBytesRef.init(code)) - acc.flags.incl CodeChanged - -proc setStorage*(ac: AccountsLedgerRef, address: Address, slot, value: UInt256) = - let acc = ac.getAccount(address) - acc.flags.incl {Alive} - let oldValue = acc.storageValue(slot, ac) - if oldValue != value: - var acc = ac.makeDirty(address) - acc.overlayStorage[slot] = value - acc.flags.incl StorageChanged - -proc clearStorage*(ac: AccountsLedgerRef, address: Address) = - const info = "clearStorage(): " - - # a.k.a createStateObject. If there is an existing account with - # the given address, it is overwritten. - - let acc = ac.getAccount(address) - acc.flags.incl {Alive, NewlyCreated} - - let empty = ac.ledger.slotStateEmpty(acc.toAccountKey).valueOr: return - if not empty: - # need to clear the storage from the database first - let acc = ac.makeDirty(address, cloneStorage = false) - ac.ledger.clearStorage(acc.toAccountKey).isOkOr: - raiseAssert info & $$error - # update caches - if acc.originalStorage.isNil.not: - # also clear originalStorage cache, otherwise - # both getStorage and getCommittedStorage will - # return wrong value - acc.originalStorage.clear() - -proc deleteAccount*(ac: AccountsLedgerRef, address: Address) = - # make sure all savepoints already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - let acc = ac.getAccount(address) - ac.savePoint.dirty[address] = acc - ac.kill acc - -proc selfDestruct*(ac: AccountsLedgerRef, address: Address) = - ac.setBalance(address, 0.u256) - ac.savePoint.selfDestruct.incl address - -proc selfDestruct6780*(ac: AccountsLedgerRef, address: Address) = - let acc = ac.getAccount(address, false) - if acc.isNil: - return - - if NewlyCreated in acc.flags: - ac.selfDestruct(address) - -proc selfDestructLen*(ac: AccountsLedgerRef): int = - ac.savePoint.selfDestruct.len - -proc addLogEntry*(ac: AccountsLedgerRef, log: Log) = - ac.savePoint.logEntries.add log - -proc getAndClearLogEntries*(ac: AccountsLedgerRef): seq[Log] = - swap(result, ac.savePoint.logEntries) - -proc ripemdSpecial*(ac: AccountsLedgerRef) = - ac.ripemdSpecial = true - -proc deleteEmptyAccount(ac: AccountsLedgerRef, address: Address) = - let acc = ac.getAccount(address, false) - if acc.isNil: - return - if not acc.isEmpty: - return - if not acc.exists: - return - - ac.savePoint.dirty[address] = acc - ac.kill acc - -proc clearEmptyAccounts(ac: AccountsLedgerRef) = - # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md - for acc in ac.savePoint.dirty.values(): - if Touched in acc.flags and - acc.isEmpty and acc.exists: - ac.kill acc - - # https://github.com/ethereum/EIPs/issues/716 - if ac.ripemdSpecial: - ac.deleteEmptyAccount(RIPEMD_ADDR) - ac.ripemdSpecial = false - -proc persist*(ac: AccountsLedgerRef, - clearEmptyAccount: bool = false, - clearCache = false) = - const info = "persist(): " - - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - - if clearEmptyAccount: - ac.clearEmptyAccounts() - - for address in ac.savePoint.selfDestruct: - ac.deleteAccount(address) - - for (eAddr,acc) in ac.savePoint.dirty.pairs(): # This is a hotspot in block processing - case acc.persistMode() - of Update: - if CodeChanged in acc.flags: - acc.persistCode(ac) - if StorageChanged in acc.flags: - acc.persistStorage(ac) - else: - # This one is only necessary unless `persistStorage()` is run which needs - # to `merge()` the latest statement as well. - ac.ledger.merge(acc.toAccountKey, acc.statement).isOkOr: - raiseAssert info & $$error - of Remove: - ac.ledger.delete(acc.toAccountKey).isOkOr: - if error.error != AccNotFound: - raiseAssert info & $$error - ac.savePoint.cache.del eAddr - of DoNothing: - # dead man tell no tales - # remove touched dead account from cache - if Alive notin acc.flags: - ac.savePoint.cache.del eAddr - - acc.flags = acc.flags - resetFlags - ac.savePoint.dirty.clear() - - if clearCache: - # This overwrites the cache from the previous persist, providing a crude LRU - # scheme with little overhead - # TODO https://github.com/nim-lang/Nim/issues/23759 - swap(ac.cache, ac.savePoint.cache) - ac.savePoint.cache.reset() - - ac.savePoint.selfDestruct.clear() - - # EIP2929 - ac.savePoint.accessList.clear() - - ac.isDirty = false - -iterator addresses*(ac: AccountsLedgerRef): Address = - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - for address, _ in ac.savePoint.cache: - yield address - -iterator accounts*(ac: AccountsLedgerRef): Account = - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - for _, acc in ac.savePoint.cache: - yield ac.ledger.recast( - acc.toAccountKey, acc.statement, updateOk=true).value - -iterator pairs*(ac: AccountsLedgerRef): (Address, Account) = - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - for address, acc in ac.savePoint.cache: - yield (address, ac.ledger.recast( - acc.toAccountKey, acc.statement, updateOk=true).value) - -iterator storage*( - ac: AccountsLedgerRef; - eAddr: Address; - ): (UInt256, UInt256) = - # beware that if the account not persisted, - # the storage root will not be updated - for (slotHash, value) in ac.ledger.slotPairs eAddr.toAccountKey: - let rc = ac.kvt.get(slotHashToSlotKey(slotHash).toOpenArray) - if rc.isErr: - warn logTxt "storage()", slotHash, error=($$rc.error) - continue - let r = deblobify(rc.value, UInt256) - if r.isErr: - warn logTxt "storage.deblobify", slotHash, msg=r.error - continue - yield (r.value, value) - -iterator cachedStorage*(ac: AccountsLedgerRef, address: Address): (UInt256, UInt256) = - let acc = ac.getAccount(address, false) - if not acc.isNil: - if not acc.originalStorage.isNil: - for k, v in acc.originalStorage: - yield (k, v) - -proc getStorageRoot*(ac: AccountsLedgerRef, address: Address): Hash32 = - # beware that if the account not persisted, - # the storage root will not be updated - let acc = ac.getAccount(address, false) - if acc.isNil: EMPTY_ROOT_HASH - else: ac.ledger.slotState(acc.toAccountKey).valueOr: EMPTY_ROOT_HASH - -proc update(wd: var WitnessData, acc: AccountRef) = - # once the code is touched make sure it doesn't get reset back to false in another update - if not wd.codeTouched: - wd.codeTouched = CodeChanged in acc.flags or acc.code != nil - - if not acc.originalStorage.isNil: - for k, v in acc.originalStorage: - if v.isZero: continue - wd.storageKeys.incl k - - for k, v in acc.overlayStorage: - wd.storageKeys.incl k - -proc witnessData(acc: AccountRef): WitnessData = - result.storageKeys = HashSet[UInt256]() - update(result, acc) - -proc collectWitnessData*(ac: AccountsLedgerRef) = - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - # usually witness data is collected before we call persist() - for address, acc in ac.savePoint.cache: - ac.witnessCache.withValue(address, val) do: - update(val[], acc) - do: - ac.witnessCache[address] = witnessData(acc) - -func multiKeys(slots: HashSet[UInt256]): MultiKeysRef = - if slots.len == 0: return - new result - for x in slots: - result.add x.toBytesBE - result.sort() - -proc makeMultiKeys*(ac: AccountsLedgerRef): MultiKeysRef = - # this proc is called after we done executing a block - new result - for k, v in ac.witnessCache: - result.add(k, v.codeTouched, multiKeys(v.storageKeys)) - result.sort() - -proc accessList*(ac: AccountsLedgerRef, address: Address) = - ac.savePoint.accessList.add(address) - -proc accessList*(ac: AccountsLedgerRef, address: Address, slot: UInt256) = - ac.savePoint.accessList.add(address, slot) - -func inAccessList*(ac: AccountsLedgerRef, address: Address): bool = - var sp = ac.savePoint - while sp != nil: - result = sp.accessList.contains(address) - if result: - return - sp = sp.parentSavepoint - -func inAccessList*(ac: AccountsLedgerRef, address: Address, slot: UInt256): bool = - var sp = ac.savePoint - while sp != nil: - result = sp.accessList.contains(address, slot) - if result: - return - sp = sp.parentSavepoint - -func getTransientStorage*(ac: AccountsLedgerRef, - address: Address, slot: UInt256): UInt256 = - var sp = ac.savePoint - while sp != nil: - let (ok, res) = sp.transientStorage.getStorage(address, slot) - if ok: - return res - sp = sp.parentSavepoint - -proc setTransientStorage*(ac: AccountsLedgerRef, - address: Address, slot, val: UInt256) = - ac.savePoint.transientStorage.setStorage(address, slot, val) - -proc clearTransientStorage*(ac: AccountsLedgerRef) = - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - ac.savePoint.transientStorage.clear() - -func getAccessList*(ac: AccountsLedgerRef): common.AccessList = - # make sure all savepoint already committed - doAssert(ac.savePoint.parentSavepoint.isNil) - ac.savePoint.accessList.getAccessList() - -proc getEthAccount*(ac: AccountsLedgerRef, address: Address): Account = - let acc = ac.getAccount(address, false) - if acc.isNil: - return emptyEthAccount - - ## Convert to legacy object, will throw an assert if that fails - let rc = ac.ledger.recast(acc.toAccountKey, acc.statement) - if rc.isErr: - raiseAssert "getAccount(): cannot convert account: " & $$rc.error - rc.value - -proc getAccountProof*(ac: AccountsLedgerRef, address: Address): seq[seq[byte]] = - let accProof = ac.ledger.proof(address.toAccountKey).valueOr: - raiseAssert "Failed to get account proof: " & $$error - - accProof[0] - -proc getStorageProof*(ac: AccountsLedgerRef, address: Address, slots: openArray[UInt256]): seq[seq[seq[byte]]] = - var storageProof = newSeqOfCap[seq[seq[byte]]](slots.len) - - let - addressHash = address.toAccountKey - accountExists = ac.ledger.hasPath(addressHash).valueOr: - raiseAssert "Call to hasPath failed: " & $$error - - for slot in slots: - if not accountExists: - storageProof.add(@[]) - continue - - let - slotKey = ac.slots.get(slot).valueOr: - slot.toBytesBE.keccak256 - slotProof = ac.ledger.slotProof(addressHash, slotKey).valueOr: - if error.aErr == FetchPathNotFound: - storageProof.add(@[]) - continue - else: - raiseAssert "Failed to get slot proof: " & $$error - storageProof.add(slotProof[0]) - - storageProof - -proc getStateRoot*(db: ReadOnlyStateDB): Hash32 {.borrow.} -proc getCodeHash*(db: ReadOnlyStateDB, address: Address): Hash32 = getCodeHash(distinctBase db, address) -proc getStorageRoot*(db: ReadOnlyStateDB, address: Address): Hash32 = getStorageRoot(distinctBase db, address) -proc getBalance*(db: ReadOnlyStateDB, address: Address): UInt256 = getBalance(distinctBase db, address) -proc getStorage*(db: ReadOnlyStateDB, address: Address, slot: UInt256): UInt256 = getStorage(distinctBase db, address, slot) -proc getNonce*(db: ReadOnlyStateDB, address: Address): AccountNonce = getNonce(distinctBase db, address) -proc getCode*(db: ReadOnlyStateDB, address: Address): CodeBytesRef = getCode(distinctBase db, address) -proc getCodeSize*(db: ReadOnlyStateDB, address: Address): int = getCodeSize(distinctBase db, address) -proc contractCollision*(db: ReadOnlyStateDB, address: Address): bool = contractCollision(distinctBase db, address) -proc accountExists*(db: ReadOnlyStateDB, address: Address): bool = accountExists(distinctBase db, address) -proc isDeadAccount*(db: ReadOnlyStateDB, address: Address): bool = isDeadAccount(distinctBase db, address) -proc isEmptyAccount*(db: ReadOnlyStateDB, address: Address): bool = isEmptyAccount(distinctBase db, address) -proc getCommittedStorage*(db: ReadOnlyStateDB, address: Address, slot: UInt256): UInt256 = getCommittedStorage(distinctBase db, address, slot) -proc inAccessList*(db: ReadOnlyStateDB, address: Address): bool = inAccessList(distinctBase db, address) -proc inAccessList*(db: ReadOnlyStateDB, address: Address, slot: UInt256): bool = inAccessList(distinctBase db, address) -proc getTransientStorage*(db: ReadOnlyStateDB, - address: Address, slot: UInt256): UInt256 = getTransientStorage(distinctBase db, address, slot) -proc getAccountProof*(db: ReadOnlyStateDB, address: Address): seq[seq[byte]] = getAccountProof(distinctBase db, address) -proc getStorageProof*(db: ReadOnlyStateDB, address: Address, slots: openArray[UInt256]): seq[seq[seq[byte]]] = getStorageProof(distinctBase db, address, slots) diff --git a/nimbus/db/ledger/base.nim b/nimbus/db/ledger/base.nim deleted file mode 100644 index d8fc3ff12..000000000 --- a/nimbus/db/ledger/base.nim +++ /dev/null @@ -1,329 +0,0 @@ -# Nimbus -# 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. - -## Ledger management APIs. - -{.push raises: [].} - -import - std/typetraits, - eth/common/[addresses, hashes], - ../../evm/code_bytes, - ../../stateless/multi_keys, - ../core_db, - ./backend/accounts_ledger, - ./base/[api_tracking, base_config, base_desc] - -type - ReadOnlyStateDB* = distinct LedgerRef - -export - code_bytes, - LedgerRef, - LedgerSpRef - -# ------------------------------------------------------------------------------ -# Logging/tracking helpers (some public) -# ------------------------------------------------------------------------------ - -when LedgerEnableApiTracking: - import - std/times, - chronicles - logScope: - topics = "ledger" - const - apiTxt = "API" - -when LedgerEnableApiProfiling: - export - LedgerFnInx, - LedgerProfListRef - -# ------------------------------------------------------------------------------ -# Public methods -# ------------------------------------------------------------------------------ - -proc accessList*(ldg: LedgerRef, eAddr: Address) = - ldg.beginTrackApi LdgAccessListFn - ldg.ac.accessList(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr) - -proc accessList*(ldg: LedgerRef, eAddr: Address, slot: UInt256) = - ldg.beginTrackApi LdgAccessListFn - ldg.ac.accessList(eAddr, slot) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), slot - -proc accountExists*(ldg: LedgerRef, eAddr: Address): bool = - ldg.beginTrackApi LdgAccountExistsFn - result = ldg.ac.accountExists(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc addBalance*(ldg: LedgerRef, eAddr: Address, delta: UInt256) = - ldg.beginTrackApi LdgAddBalanceFn - ldg.ac.addBalance(eAddr, delta) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), delta - -proc addLogEntry*(ldg: LedgerRef, log: Log) = - ldg.beginTrackApi LdgAddLogEntryFn - ldg.ac.addLogEntry(log) - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc beginSavepoint*(ldg: LedgerRef): LedgerSpRef = - ldg.beginTrackApi LdgBeginSavepointFn - result = ldg.ac.beginSavepoint() - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc clearStorage*(ldg: LedgerRef, eAddr: Address) = - ldg.beginTrackApi LdgClearStorageFn - ldg.ac.clearStorage(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr) - -proc clearTransientStorage*(ldg: LedgerRef) = - ldg.beginTrackApi LdgClearTransientStorageFn - ldg.ac.clearTransientStorage() - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc collectWitnessData*(ldg: LedgerRef) = - ldg.beginTrackApi LdgCollectWitnessDataFn - ldg.ac.collectWitnessData() - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc commit*(ldg: LedgerRef, sp: LedgerSpRef) = - ldg.beginTrackApi LdgCommitFn - ldg.ac.commit(sp) - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc deleteAccount*(ldg: LedgerRef, eAddr: Address) = - ldg.beginTrackApi LdgDeleteAccountFn - ldg.ac.deleteAccount(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr) - -proc dispose*(ldg: LedgerRef, sp: LedgerSpRef) = - ldg.beginTrackApi LdgDisposeFn - ldg.ac.dispose(sp) - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc getAndClearLogEntries*(ldg: LedgerRef): seq[Log] = - ldg.beginTrackApi LdgGetAndClearLogEntriesFn - result = ldg.ac.getAndClearLogEntries() - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc getBalance*(ldg: LedgerRef, eAddr: Address): UInt256 = - ldg.beginTrackApi LdgGetBalanceFn - result = ldg.ac.getBalance(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc getCode*(ldg: LedgerRef, eAddr: Address): CodeBytesRef = - ldg.beginTrackApi LdgGetCodeFn - result = ldg.ac.getCode(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc getCodeHash*(ldg: LedgerRef, eAddr: Address): Hash32 = - ldg.beginTrackApi LdgGetCodeHashFn - result = ldg.ac.getCodeHash(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result=($$result) - -proc getCodeSize*(ldg: LedgerRef, eAddr: Address): int = - ldg.beginTrackApi LdgGetCodeSizeFn - result = ldg.ac.getCodeSize(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc getCommittedStorage*( - ldg: LedgerRef; - eAddr: Address; - slot: UInt256; - ): UInt256 = - ldg.beginTrackApi LdgGetCommittedStorageFn - result = ldg.ac.getCommittedStorage(eAddr, slot) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), slot, result - -proc getNonce*(ldg: LedgerRef, eAddr: Address): AccountNonce = - ldg.beginTrackApi LdgGetNonceFn - result = ldg.ac.getNonce(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc getStorage*(ldg: LedgerRef, eAddr: Address, slot: UInt256): UInt256 = - ldg.beginTrackApi LdgGetStorageFn - result = ldg.ac.getStorage(eAddr, slot) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), slot, result - -proc getStorageRoot*(ldg: LedgerRef, eAddr: Address): Hash32 = - ldg.beginTrackApi LdgGetStorageRootFn - result = ldg.ac.getStorageRoot(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result=($$result) - -proc getTransientStorage*( - ldg: LedgerRef; - eAddr: Address; - slot: UInt256; - ): UInt256 = - ldg.beginTrackApi LdgGetTransientStorageFn - result = ldg.ac.getTransientStorage(eAddr, slot) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), slot, result - -proc contractCollision*(ldg: LedgerRef, eAddr: Address): bool = - ldg.beginTrackApi LdgContractCollisionFn - result = ldg.ac.contractCollision(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc inAccessList*(ldg: LedgerRef, eAddr: Address): bool = - ldg.beginTrackApi LdgInAccessListFn - result = ldg.ac.inAccessList(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc inAccessList*(ldg: LedgerRef, eAddr: Address, slot: UInt256): bool = - ldg.beginTrackApi LdgInAccessListFn - result = ldg.ac.inAccessList(eAddr, slot) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), slot, result - -proc incNonce*(ldg: LedgerRef, eAddr: Address) = - ldg.beginTrackApi LdgIncNonceFn - ldg.ac.incNonce(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr) - -proc isDeadAccount*(ldg: LedgerRef, eAddr: Address): bool = - ldg.beginTrackApi LdgIsDeadAccountFn - result = ldg.ac.isDeadAccount(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc isEmptyAccount*(ldg: LedgerRef, eAddr: Address): bool = - ldg.beginTrackApi LdgIsEmptyAccountFn - result = ldg.ac.isEmptyAccount(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), result - -proc isTopLevelClean*(ldg: LedgerRef): bool = - ldg.beginTrackApi LdgIsTopLevelCleanFn - result = ldg.ac.isTopLevelClean() - ldg.ifTrackApi: debug apiTxt, api, elapsed, result - -proc makeMultiKeys*(ldg: LedgerRef): MultiKeysRef = - ldg.beginTrackApi LdgMakeMultiKeysFn - result = ldg.ac.makeMultiKeys() - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc persist*(ldg: LedgerRef, clearEmptyAccount = false, clearCache = false) = - ldg.beginTrackApi LdgPersistFn - ldg.ac.persist(clearEmptyAccount, clearCache) - ldg.ifTrackApi: debug apiTxt, api, elapsed, clearEmptyAccount, clearCache - -proc ripemdSpecial*(ldg: LedgerRef) = - ldg.beginTrackApi LdgRipemdSpecialFn - ldg.ac.ripemdSpecial() - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc rollback*(ldg: LedgerRef, sp: LedgerSpRef) = - ldg.beginTrackApi LdgRollbackFn - ldg.ac.rollback(sp) - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc safeDispose*(ldg: LedgerRef, sp: LedgerSpRef) = - ldg.beginTrackApi LdgSafeDisposeFn - ldg.ac.safeDispose(sp) - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc selfDestruct*(ldg: LedgerRef, eAddr: Address) = - ldg.beginTrackApi LdgSelfDestructFn - ldg.ac.selfDestruct(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc selfDestruct6780*(ldg: LedgerRef, eAddr: Address) = - ldg.beginTrackApi LdgSelfDestruct6780Fn - ldg.ac.selfDestruct6780(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc selfDestructLen*(ldg: LedgerRef): int = - ldg.beginTrackApi LdgSelfDestructLenFn - result = ldg.ac.selfDestructLen() - ldg.ifTrackApi: debug apiTxt, api, elapsed, result - -proc setBalance*(ldg: LedgerRef, eAddr: Address, balance: UInt256) = - ldg.beginTrackApi LdgSetBalanceFn - ldg.ac.setBalance(eAddr, balance) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), balance - -proc setCode*(ldg: LedgerRef, eAddr: Address, code: seq[byte]) = - ldg.beginTrackApi LdgSetCodeFn - ldg.ac.setCode(eAddr, code) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), code - -proc setNonce*(ldg: LedgerRef, eAddr: Address, nonce: AccountNonce) = - ldg.beginTrackApi LdgSetNonceFn - ldg.ac.setNonce(eAddr, nonce) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), nonce - -proc setStorage*(ldg: LedgerRef, eAddr: Address, slot, val: UInt256) = - ldg.beginTrackApi LdgSetStorageFn - ldg.ac.setStorage(eAddr, slot, val) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), slot, val - -proc setTransientStorage*( - ldg: LedgerRef; - eAddr: Address; - slot: UInt256; - val: UInt256; - ) = - ldg.beginTrackApi LdgSetTransientStorageFn - ldg.ac.setTransientStorage(eAddr, slot, val) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), slot, val - -proc getStateRoot*(ldg: LedgerRef): Hash32 = - ldg.beginTrackApi LdgStateFn - result = ldg.ac.getStateRoot() - ldg.ifTrackApi: debug apiTxt, api, elapsed, result - -proc subBalance*(ldg: LedgerRef, eAddr: Address, delta: UInt256) = - ldg.beginTrackApi LdgSubBalanceFn - ldg.ac.subBalance(eAddr, delta) - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr), delta - -proc getAccessList*(ldg: LedgerRef): AccessList = - ldg.beginTrackApi LdgGetAccessListFn - result = ldg.ac.getAccessList() - ldg.ifTrackApi: debug apiTxt, api, elapsed - -proc getEthAccount*(ldg: LedgerRef, eAddr: Address): Account = - ldg.beginTrackApi LdgGetAthAccountFn - result = ldg.ac.getEthAccount(eAddr) - ldg.ifTrackApi: debug apiTxt, api, elapsed, result - -proc getAccountProof*(ldg: LedgerRef, eAddr: Address): seq[seq[byte]] = - result = ldg.ac.getAccountProof(eAddr) - -proc getStorageProof*(ldg: LedgerRef, eAddr: Address, slots: openArray[UInt256]): seq[seq[seq[byte]]] = - result = ldg.ac.getStorageProof(eAddr, slots) - -# ------------------------------------------------------------------------------ -# Public virtual read-only methods -# ------------------------------------------------------------------------------ - -proc getStateRoot*(db: ReadOnlyStateDB): Hash32 {.borrow.} -proc getCodeHash*(db: ReadOnlyStateDB, address: Address): Hash32 = getCodeHash(distinctBase db, address) -proc getStorageRoot*(db: ReadOnlyStateDB, address: Address): Hash32 = getStorageRoot(distinctBase db, address) -proc getBalance*(db: ReadOnlyStateDB, address: Address): UInt256 = getBalance(distinctBase db, address) -proc getStorage*(db: ReadOnlyStateDB, address: Address, slot: UInt256): UInt256 = getStorage(distinctBase db, address, slot) -proc getNonce*(db: ReadOnlyStateDB, address: Address): AccountNonce = getNonce(distinctBase db, address) -proc getCode*(db: ReadOnlyStateDB, address: Address): CodeBytesRef = getCode(distinctBase db, address) -proc getCodeSize*(db: ReadOnlyStateDB, address: Address): int = getCodeSize(distinctBase db, address) -proc contractCollision*(db: ReadOnlyStateDB, address: Address): bool = contractCollision(distinctBase db, address) -proc accountExists*(db: ReadOnlyStateDB, address: Address): bool = accountExists(distinctBase db, address) -proc isDeadAccount*(db: ReadOnlyStateDB, address: Address): bool = isDeadAccount(distinctBase db, address) -proc isEmptyAccount*(db: ReadOnlyStateDB, address: Address): bool = isEmptyAccount(distinctBase db, address) -proc getCommittedStorage*(db: ReadOnlyStateDB, address: Address, slot: UInt256): UInt256 = getCommittedStorage(distinctBase db, address, slot) -proc inAccessList*(db: ReadOnlyStateDB, address: Address): bool = inAccessList(distinctBase db, address) -proc inAccessList*(db: ReadOnlyStateDB, address: Address, slot: UInt256): bool = inAccessList(distinctBase db, address) -proc getTransientStorage*(db: ReadOnlyStateDB, - address: Address, slot: UInt256): UInt256 = getTransientStorage(distinctBase db, address, slot) -proc getAccountProof*(db: ReadOnlyStateDB, address: Address): seq[seq[byte]] = getAccountProof(distinctBase db, address) -proc getStorageProof*(db: ReadOnlyStateDB, address: Address, slots: openArray[UInt256]): seq[seq[seq[byte]]] = getStorageProof(distinctBase db, address, slots) - -# ------------------------------------------------------------------------------ -# End -# ------------------------------------------------------------------------------ diff --git a/nimbus/db/ledger/base/api_tracking.nim b/nimbus/db/ledger/base/api_tracking.nim deleted file mode 100644 index 17b150724..000000000 --- a/nimbus/db/ledger/base/api_tracking.nim +++ /dev/null @@ -1,148 +0,0 @@ -# Nimbus -# 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. - -{.push raises: [].} - -import - std/[strutils, times], - eth/common, - stew/byteutils, - ../../../evm/code_bytes, - ../../aristo/aristo_profile, - ../../core_db, - "."/[base_config, base_desc] - -type - Elapsed* = distinct Duration - ## Needed for local `$` as it would be ambiguous for `Duration` - - LedgerFnInx* = enum - ## Profiling table index - SummaryItem = "total" - - LdgAccessListFn = "accessList" - LdgAccountExistsFn = "accountExists" - LdgAddBalanceFn = "addBalance" - LdgAddLogEntryFn = "addLogEntry" - LdgBeginSavepointFn = "beginSavepoint" - LdgClearStorageFn = "clearStorage" - LdgClearTransientStorageFn = "clearTransientStorage" - LdgCollectWitnessDataFn = "collectWitnessData" - LdgCommitFn = "commit" - LdgContractCollisionFn = "contractCollision" - LdgDeleteAccountFn = "deleteAccount" - LdgDisposeFn = "dispose" - LdgGetAccessListFn = "getAcessList" - LdgGetAccountFn = "getAccount" - LdgGetAndClearLogEntriesFn = "getAndClearLogEntries" - LdgGetBalanceFn = "getBalance" - LdgGetCodeFn = "getCode" - LdgGetCodeHashFn = "getCodeHash" - LdgGetCodeSizeFn = "getCodeSize" - LdgGetCommittedStorageFn = "getCommittedStorage" - LdgGetNonceFn = "getNonce" - LdgGetStorageFn = "getStorage" - LdgGetStorageRootFn = "getStorageRoot" - LdgGetTransientStorageFn = "getTransientStorage" - LdgGetAthAccountFn = "getEthAccount" - LdgInAccessListFn = "inAccessList" - LdgIncNonceFn = "incNonce" - LdgIsDeadAccountFn = "isDeadAccount" - LdgIsEmptyAccountFn = "isEmptyAccount" - LdgIsTopLevelCleanFn = "isTopLevelClean" - LdgMakeMultiKeysFn = "makeMultiKeys" - LdgPersistFn = "persist" - LdgRipemdSpecialFn = "ripemdSpecial" - LdgRollbackFn = "rollback" - LdgSafeDisposeFn = "safeDispose" - LdgSelfDestruct6780Fn = "selfDestruct6780" - LdgSelfDestructFn = "selfDestruct" - LdgSelfDestructLenFn = "selfDestructLen" - LdgSetBalanceFn = "setBalance" - LdgSetCodeFn = "setCode" - LdgSetNonceFn = "setNonce" - LdgSetStorageFn = "setStorage" - LdgSetTransientStorageFn = "setTransientStorage" - LdgStateFn = "state" - LdgSubBalanceFn = "subBalance" - - LdgAccountsIt = "accounts" - LdgAdressesIt = "addresses" - LdgCachedStorageIt = "cachedStorage" - LdgPairsIt = "pairs" - LdgStorageIt = "storage" - -# ------------------------------------------------------------------------------ -# Private helpers -# ------------------------------------------------------------------------------ - -func oaToStr(w: openArray[byte]): string = - w.toHex.toLowerAscii - -func toStr(w: Address): string = - w.toHex - -func toStr(w: Hash32): string = - w.toHex - -func toStr(w: CodeBytesRef): string = - if w.isNil: "nil" - else: "[" & $w.bytes.len & "]" - -func toStr(w: seq[byte]): string = - if 0 < w.len and w.len < 5: "<" & w.oaToStr & ">" - else: "seq[byte][" & $w.len & "]" - -func toStr(w: seq[Log]): string = - "Logs[" & $w.len & "]" - -func toStr(ela: Duration): string = - aristo_profile.toStr(ela) - -# ------------------------------------------------------------------------------ -# Public API logging helpers -# ------------------------------------------------------------------------------ - -func `$`*(w: CodeBytesRef): string {.used.} = w.toStr -func `$`*(e: Elapsed): string = e.Duration.toStr -func `$`*(l: seq[Log]): string = l.toStr -func `$`*(b: seq[byte]): string = b.toStr -func `$$`*(a: Address): string = a.toStr # otherwise collision w/existing `$` -func `$$`*(h: Hash32): string = h.toStr # otherwise collision w/existing `$` - -# ------------------------------------------------------------------------------ -# Public API logging framework -# ------------------------------------------------------------------------------ - -template beginTrackApi*(ldg: LedgerRef; s: LedgerFnInx) = - when LedgerEnableApiTracking: - const api {.inject,used.} = s # Generally available - let baStart {.inject.} = getTime() # Local use only - -template ifTrackApi*(ldg: LedgerRef; code: untyped) = - when LedgerEnableApiTracking: - when LedgerEnableApiProfiling: - let elapsed {.inject,used.} = (getTime() - baStart).Elapsed - aristo_profile.update(ldg.profTab, api.ord, elapsed.Duration) - if ldg.trackApi: - when not LedgerEnableApiProfiling: # otherwise use variable above - let elapsed {.inject,used.} = (getTime() - baStart).Elapsed - code - -# ------------------------------------------------------------------------------ -# Public helpers -# ------------------------------------------------------------------------------ - -func init*(T: type LedgerProfListRef): T = - T(list: newSeq[LedgerProfData](1 + high(LedgerFnInx).ord)) - -# ------------------------------------------------------------------------------ -# End -# ------------------------------------------------------------------------------ diff --git a/nimbus/db/ledger/base/base_config.nim b/nimbus/db/ledger/base/base_config.nim deleted file mode 100644 index 07ba08d0d..000000000 --- a/nimbus/db/ledger/base/base_config.nim +++ /dev/null @@ -1,48 +0,0 @@ -# Nimbus -# 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. - -{.push raises: [].} - -import - ../../core_db/base/base_config - -# Configuration section -const - EnableApiTracking = false - ## When enabled, API functions are logged. Tracking is enabled by setting - ## the `trackApi` flag to `true`. This setting is typically inherited from - ## the `CoreDb` descriptor flag `trackLedgerApi` (which is only available - ## if the flag `CoreDbEnableApiTracking` is set `true`. - - EnableApiProfiling = false - ## Enable API functions profiling. This setting is only effective if the - ## flag `CoreDbEnableApiJumpTable` is set `true`. - -# Exportable constants (leave alone this section) -const - LedgerEnableApiTracking* = EnableApiTracking and CoreDbEnableApiTracking - LedgerEnableApiProfiling* = EnableApiProfiling and CoreDbEnableApiJumpTable - - -# Support warning about extra compile time options. For production, non of -# the above features should be enabled. -import strutils -const ledgerBaseConfigExtras* = block: - var s: seq[string] - when LedgerEnableApiTracking: - s.add "logging" - when LedgerEnableApiProfiling: - s.add "profiling" - if s.len == 0: - "" - else: - "Ledger(" & s.join(", ") & ")" - -# End diff --git a/nimbus/db/ledger/base/base_desc.nim b/nimbus/db/ledger/base/base_desc.nim deleted file mode 100644 index 450f912e3..000000000 --- a/nimbus/db/ledger/base/base_desc.nim +++ /dev/null @@ -1,33 +0,0 @@ -# Nimbus -# 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. - -{.push raises: [].} - -import - ../../aristo/aristo_profile, - ../backend/accounts_ledger - -type - LedgerProfListRef* = AristoDbProfListRef - ## Borrowed from `aristo_profile`, only used in profiling mode - - LedgerProfData* = AristoDbProfData - ## Borrowed from `aristo_profile`, only used in profiling mode - - LedgerSpRef* = LedgerSavePoint - ## Object for check point or save point - - LedgerRef* = ref object of RootRef - ## Root object with closures - trackApi*: bool ## For debugging - profTab*: LedgerProfListRef ## Profiling data (if any) - ac*: AccountsLedgerRef - -# End diff --git a/nimbus/db/ledger/base/base_helpers.nim b/nimbus/db/ledger/base/base_helpers.nim deleted file mode 100644 index 7ae7d09d0..000000000 --- a/nimbus/db/ledger/base/base_helpers.nim +++ /dev/null @@ -1,43 +0,0 @@ -# Nimbus -# Copyright (c) 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. - -import - ../../core_db, - "."/[base_config, base_desc] - -# ------------------------------------------------------------------------------ -# Public constructor helper -# ------------------------------------------------------------------------------ - -when LedgerEnableApiProfiling: - import api_tracking - - proc ldgProfData*(db: CoreDbRef): LedgerProfListRef = - ## Return profiling data table (only available in profiling mode). If - ## available (i.e. non-nil), result data can be organised by the functions - ## available with `aristo_profile`. - ## - ## Note that profiling these data have accumulated over several ledger - ## sessions running on the same `CoreDb` instance. - ## - if db.ledgerHook.isNil: - db.ledgerHook = LedgerProfListRef.init() - cast[LedgerProfListRef](db.ledgerHook) - -proc bless*(ldg: LedgerRef; db: CoreDbRef): LedgerRef = - when LedgerEnableApiTracking: - ldg.trackApi = db.trackLedgerApi - when LedgerEnableApiProfiling: - ldg.profTab = db.ldgProfData() - ldg - -# ------------------------------------------------------------------------------ -# End -# ------------------------------------------------------------------------------ diff --git a/nimbus/db/ledger/base_iterators.nim b/nimbus/db/ledger/base_iterators.nim deleted file mode 100644 index 25a317357..000000000 --- a/nimbus/db/ledger/base_iterators.nim +++ /dev/null @@ -1,71 +0,0 @@ -# Nimbus -# 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. - -{.push raises: [].} - -import - eth/common, - ../core_db, - ./backend/accounts_ledger, - ./base/[api_tracking, base_config, base_desc] - -when LedgerEnableApiTracking: - import - std/times, - chronicles - logScope: - topics = "ledger" - const - apiTxt = "API" - -# ------------------------------------------------------------------------------ -# Public iterators -# ------------------------------------------------------------------------------ - -iterator accounts*(ldg: LedgerRef): Account = - ldg.beginTrackApi LdgAccountsIt - for w in ldg.ac.accounts(): - yield w - ldg.ifTrackApi: debug apiTxt, api, elapsed - - -iterator addresses*(ldg: LedgerRef): Address = - ldg.beginTrackApi LdgAdressesIt - for w in ldg.ac.addresses(): - yield w - ldg.ifTrackApi: debug apiTxt, api, elapsed - - -iterator cachedStorage*(ldg: LedgerRef, eAddr: Address): (UInt256,UInt256) = - ldg.beginTrackApi LdgCachedStorageIt - for w in ldg.ac.cachedStorage(eAddr): - yield w - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr) - - -iterator pairs*(ldg: LedgerRef): (Address,Account) = - ldg.beginTrackApi LdgPairsIt - for w in ldg.ac.pairs(): - yield w - ldg.ifTrackApi: debug apiTxt, api, elapsed - - -iterator storage*( - ldg: LedgerRef; - eAddr: Address; - ): (UInt256,UInt256) = - ldg.beginTrackApi LdgStorageIt - for w in ldg.ac.storage(eAddr): - yield w - ldg.ifTrackApi: debug apiTxt, api, elapsed, eAddr=($$eAddr) - -# ------------------------------------------------------------------------------ -# End -# ------------------------------------------------------------------------------ diff --git a/nimbus/evm/state.nim b/nimbus/evm/state.nim index 192e8b3f4..1d4d23522 100644 --- a/nimbus/evm/state.nim +++ b/nimbus/evm/state.nim @@ -110,7 +110,7 @@ proc reinit*(self: BaseVMState; ## Object descriptor com = self.com db = com.db ac = if linear or self.stateDB.getStateRoot() == parent.stateRoot: self.stateDB - else: LedgerRef.init(db, self.stateDB.ac.storeSlotHash) + else: LedgerRef.init(db, self.stateDB.storeSlotHash) flags = self.flags self[].reset self.init( diff --git a/tests/test_coredb/test_chainsync.nim b/tests/test_coredb/test_chainsync.nim index 02d112403..9225c5882 100644 --- a/tests/test_coredb/test_chainsync.nim +++ b/tests/test_coredb/test_chainsync.nim @@ -19,8 +19,7 @@ import ../replay/[pp, undump_blocks, undump_blocks_era1, xcheck], ./test_helpers -when CoreDbEnableProfiling or - LedgerEnableApiProfiling: +when CoreDbEnableProfiling: import std/sequtils @@ -33,12 +32,6 @@ when CoreDbEnableProfiling: kvtProfData: KvtDbProfListRef cdbProfData: CoreDbProfListRef -when LedgerEnableApiProfiling: - import - ../../nimbus/db/ledger/base/base_helpers - var - ldgProfData: LedgerProfListRef - const EnableExtraLoggingControl = true var @@ -125,11 +118,6 @@ proc test_chainSyncProfilingPrint*( else: "" discard info var blurb: seq[string] - when LedgerEnableApiProfiling: - blurb.add ldgProfData.profilingPrinter( - names = LedgerFnInx.toSeq.mapIt($it), - header = "Ledger profiling results" & info, - indent) when CoreDbEnableProfiling: blurb.add cdbProfData.profilingPrinter( names = CoreDbFnInx.toSeq.mapIt($it), @@ -192,8 +180,6 @@ proc test_chainSync*( aristoProfData = com.db.ariApi.AristoApiProfRef.data kvtProfData = com.db.kvtApi.KvtApiProfRef.data cdbProfData = com.db.profTab - when LedgerEnableApiProfiling: - ldgProfData = com.db.ldgProfData() # This will enable printing the `era1` covered block ranges (if any) undump_blocks_era1.noisy = noisy diff --git a/tests/test_ledger.nim b/tests/test_ledger.nim index 2edea1be0..8a0b7d60e 100644 --- a/tests/test_ledger.nim +++ b/tests/test_ledger.nim @@ -14,7 +14,6 @@ import stew/byteutils, stew/endians2, ../nimbus/config, - ../nimbus/db/ledger, ../nimbus/db/storage_types, ../nimbus/common/common, ../nimbus/core/chain, @@ -22,7 +21,7 @@ import ../nimbus/core/casper, ../nimbus/transaction, ../nimbus/constants, - ../nimbus/db/ledger/backend/accounts_ledger {.all.}, # import all private symbols + ../nimbus/db/ledger {.all.}, # import all private symbols unittest2 const