nimbus-eth1/nimbus/db/incomplete_db.nim
Jordan Hrycaj 6d132811ba
Core db update providing additional results code interface (#1776)
* Split `core_db/base.nim` into several sources

* Rename `core_db/legacy.nim` => `core_db/legacy_db.nim`

* Update `CoreDb` API, dual methods returning `Result[]` or plain value

detail:
  Plain value methods implemet the legacy API, they defect on error results

* Redesign `CoreDB` direct backend access

why:
  Made the `backend` directive integral part of the API

* Discontinue providing unused or otherwise available functions

details:
+ setTransactionID() removed, not used and not easily replicable in Aristo
+ maybeGet() removed, available via direct backend access
+ newPhk() removed, never used & was experimental anyway

* Update/reorg backend API

why:
+ Added error print function `$$()`
+ General descriptor completion (and optional validation) via `bless()`

* Update `Aristo`/`Kvt` exception handling

why:
  Avoid `CatchableError` exceptions, rather pass them as error code where
  appropriate.

* More `CoreDB` compliant `Aristo` and `Kvt` methods

details:
+ Providing functions like `contains()`, `getVtxRc()` (returns `Result[]`).
+ Additional error code: `NotImplemented`

* Rewrite/reorg of Aristo DB constructor

why:
  Previously used global object `DefaultQidLayoutRef` as default
  initialiser. This object was created at compile time which lead to
  non-gc safe functions.

* Update nimbus/db/core_db/legacy_db.nim

Co-authored-by: Kim De Mey <kim.demey@gmail.com>

* Update nimbus/db/aristo/aristo_transcode.nim

Co-authored-by: Kim De Mey <kim.demey@gmail.com>

* Update nimbus/db/core_db/legacy_db.nim

Co-authored-by: Kim De Mey <kim.demey@gmail.com>

---------

Co-authored-by: Kim De Mey <kim.demey@gmail.com>
2023-09-26 10:21:13 +01:00

98 lines
4.0 KiB
Nim

#[
FIXME-Adam: I feel like this and distinct_tries should either be combined or more clearly separated.
The points of these two files are:
- Have distinct types for the two kinds of tries, because we really don't want to mix them up.
- Have an interface with functions like getAccountBytes rather than just get. (But still just a super-thin wrapper.)
- Have maybeGetWhatever instead of just getWhatever. (Also assertions.)
- Notice that this makes sense at both the bytes level and the Account/UInt256 level.
]#
import
chronicles,
eth/[common, trie/db],
"."/[core_db, distinct_tries, storage_types, values_from_bytes]
# Useful for debugging.
const shouldDoAssertionsForMissingNodes* = false
proc ifNodesExistGetAccountBytes*(trie: AccountsTrie, address: EthAddress): Option[seq[byte]] =
trie.maybeGetAccountBytes(address)
proc ifNodesExistGetStorageBytesWithinAccount*(storageTrie: StorageTrie, slotAsKey: openArray[byte]): Option[seq[byte]] =
storageTrie.maybeGetSlotBytes(slotAsKey)
proc populateDbWithNodes*(db: CoreDbRef, nodes: seq[seq[byte]]) =
error("GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG AARDVARK: populateDbWithNodes received nodes, about to populate", nodes) # AARDVARK not an error, I just want it to stand out
for nodeBytes in nodes:
let nodeHash = keccakHash(nodeBytes)
info("AARDVARK: populateDbWithNodes about to add node", nodeHash, nodeBytes)
db.kvt.put(nodeHash.data, nodeBytes)
# AARDVARK: just make the callers call populateDbWithNodes directly?
proc populateDbWithBranch*(db: CoreDbRef, branch: seq[seq[byte]]) =
for nodeBytes in branch:
let nodeHash = keccakHash(nodeBytes)
db.kvt.put(nodeHash.data, nodeBytes)
# Returns a none if there are missing nodes; if the account itself simply
# doesn't exist yet, that's fine and it returns some(newAccount()).
proc ifNodesExistGetAccount*(trie: AccountsTrie, address: EthAddress): Option[Account] =
ifNodesExistGetAccountBytes(trie, address).map(accountFromBytes)
proc maybeGetCode*(db: CoreDbRef, codeHash: Hash256): Option[seq[byte]] =
when defined(geth):
if db.isLegacy:
db.kvt.backend.toLegacy.maybeGet(codeHash.data)
else:
db.kvt.get(codeHash.data)
else:
if db.isLegacy:
db.kvt.backend.toLegacy.maybeGet(contractHashKey(codeHash).toOpenArray)
else:
some(db.kvt.get(contractHashKey(codeHash).toOpenArray))
proc maybeGetCode*(trie: AccountsTrie, address: EthAddress): Option[seq[byte]] =
let maybeAcc = trie.ifNodesExistGetAccount(address)
if maybeAcc.isNone:
none[seq[byte]]()
else:
maybeGetCode(trie.db, maybeAcc.get.codeHash)
proc checkingForMissingNodes_getCode*(trie: AccountsTrie, address: EthAddress): seq[byte] =
let m = maybeGetCode(trie, address)
doAssert(m.isSome, "missing code for account at " & $(address))
m.get
proc assertFetchedCode*(trie: AccountsTrie, address: EthAddress) =
if shouldDoAssertionsForMissingNodes:
let m = maybeGetCode(trie, address)
doAssert(m.isSome, "missing code for account at " & $(address))
proc ifNodesExistGetStorageWithinAccount*(storageTrie: StorageTrie, slot: UInt256): Option[UInt256] =
ifNodesExistGetStorageBytesWithinAccount(storageTrie, createTrieKeyFromSlot(slot)).map(slotValueFromBytes)
proc ifNodesExistGetStorage*(trie: AccountsTrie, address: EthAddress, slot: UInt256): Option[UInt256] =
let maybeAcc = ifNodesExistGetAccount(trie, address)
if maybeAcc.isNone:
none[UInt256]()
else:
ifNodesExistGetStorageWithinAccount(storageTrieForAccount(trie, maybeAcc.get), slot)
proc hasAllNodesForAccount*(trie: AccountsTrie, address: EthAddress): bool =
ifNodesExistGetAccountBytes(trie, address).isSome
proc hasAllNodesForCode*(trie: AccountsTrie, address: EthAddress): bool =
maybeGetCode(trie, address).isSome
proc hasAllNodesForStorageSlot*(trie: AccountsTrie, address: EthAddress, slot: UInt256): bool =
ifNodesExistGetStorage(trie, address, slot).isSome
proc assertFetchedStorage*(trie: AccountsTrie, address: EthAddress, slot: UInt256) =
doAssert(hasAllNodesForStorageSlot(trie, address, slot))