Skip to content
4 changes: 3 additions & 1 deletion execution_chain/common/common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ proc init(com : CommonRef,
initializeDb: bool,
statelessProviderEnabled: bool,
statelessWitnessValidation: bool) =

# When stateless is not enabled, disable the witness kvt which is created by default.
if not statelessProviderEnabled:
db.kvts[KvtType.Witness] = nil

config.daoCheck()

Expand Down
13 changes: 8 additions & 5 deletions execution_chain/db/core_db/backend/aristo_db.nim
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ export base_desc
# Public constructors
# ------------------------------------------------------------------------------

proc create*(dbType: CoreDbType; kvt: KvtDbRef; mpt: AristoDbRef): CoreDbRef =
proc create*(dbType: CoreDbType; mpt: AristoDbRef; kvts: array[KvtType, KvtDbRef]): CoreDbRef =
## Constructor helper
CoreDbRef(dbType: dbType, mpt: mpt, kvt: kvt)
CoreDbRef(dbType: dbType, mpt: mpt, kvts: kvts)

proc newMemoryCoreDbRef*(): CoreDbRef =
AristoDbMemory.create(
KvtDbRef.init(),
AristoDbRef.init())
var kvts: array[KvtType, KvtDbRef]
kvts[KvtType.Generic] = KvtDbRef.init()
kvts[KvtType.ContractCode] = KvtDbRef.init()
kvts[KvtType.Witness] = KvtDbRef.init()

AristoDbMemory.create(AristoDbRef.init(), kvts)

# ------------------------------------------------------------------------------
# End
Expand Down
17 changes: 9 additions & 8 deletions execution_chain/db/core_db/backend/aristo_rocksdb.nim
Original file line number Diff line number Diff line change
Expand Up @@ -183,27 +183,28 @@ proc newRocksDbCoreDbRef*(basePath: string, opts: DbOptions): CoreDbRef =
nil
dbOpts = opts.toDbOpts()
acfOpts = opts.toCfOpts(cache, true)
# The KVT is is not bulk-flushed so we have to use a skiplist memtable for
# it
# The KVT is is not bulk-flushed so we have to use a skiplist memtable for it
kcfOpts = opts.toCfOpts(cache, false)

cfDescs =
@[($AristoCFs.VtxCF, acfOpts)] & KvtCFs.items().toSeq().mapIt(($it, kcfOpts))
@[($AristoCFs.VtxCF, acfOpts)] & KvtType.items().toSeq().mapIt(($it, kcfOpts))
baseDb = RocksDbInstanceRef.open(basePath, dbOpts, cfDescs).expect(
"Open database from " & basePath
)

"Open database from " & basePath)
adb = AristoDbRef.init(opts, baseDb).valueOr:
raiseAssert "Could not initialize aristo: " & $error
kdb = KvtDbRef.init(baseDb)

var kvts: array[KvtType, KvtDbRef]
kvts[KvtType.Generic] = KvtDbRef.init(baseDb, KvtType.Generic)
kvts[KvtType.ContractCode] = KvtDbRef.init(baseDb, KvtType.ContractCode)
kvts[KvtType.Witness] = KvtDbRef.init(baseDb, KvtType.Witness)

if opts.rdbKeyCacheSize > 0:
# Make sure key cache isn't empty
adb.txRef.computeKeys(STATE_ROOT_VID).isOkOr:
fatal "Cannot compute root keys", msg = error
quit(QuitFailure)

AristoDbRocks.create(kdb, adb)
AristoDbRocks.create(adb, kvts)

# ------------------------------------------------------------------------------
# End
Expand Down
102 changes: 67 additions & 35 deletions execution_chain/db/core_db/base.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export
CoreDbPersistentTypes,
CoreDbRef,
CoreDbTxRef,
CoreDbType
CoreDbType,
KvtType

import
../aristo/[
Expand All @@ -46,13 +47,18 @@ proc baseTxFrame*(db: CoreDbRef): CoreDbTxRef =
## up in the base txframe before being persisted to the database with a
## persist call.

var kTxs: array[KvtType, KvtTxRef]
for i, kvt in db.kvts:
if not kvt.isNil():
kTxs[i] = kvt.baseTxFrame()

CoreDbTxRef(
aTx: db.mpt.baseTxFrame(),
kTx: db.kvt.baseTxFrame())
kTxs: kTxs)

proc kvtBackend*(db: CoreDbRef): TypedBackendRef =
## Get KVT backend
db.kvt.getBackendFn()
db.kvts[KvtType.Generic].getBackendFn()

# ------------------------------------------------------------------------------
# Public base descriptor methods
Expand All @@ -66,8 +72,11 @@ proc finish*(db: CoreDbRef; eradicate = false) =
## depends on the backend database. Currently, only the `AristoDbRocks` type
## backend removes the database on `true`.

db.kvt.finish(eradicate)
db.mpt.finish(eradicate)
for kvt in db.kvts:
if not kvt.isNil():
kvt.finish(eradicate)


proc `$$`*(e: CoreDbError): string =
## Pretty print error symbol
Expand All @@ -82,11 +91,19 @@ proc persist*(db: CoreDbRef, txFrame: CoreDbTxRef) =
## This function persists changes up to and including the given frame to the
## database.

let
kvtBatch = db.kvt.putBegFn()
mptBatch = db.mpt.putBegFn()
let mptBatch = db.mpt.putBegFn()

var
kvtBatches: array[KvtType, Result[init_common.PutHdlRef, KvtError]]
kvtBatchesOk = true

if kvtBatch.isOk() and mptBatch.isOk():
for i, kvt in db.kvts:
if not kvt.isNil():
kvtBatches[i] = kvt.putBegFn()
if kvtBatches[i].isErr():
kvtBatchesOk = false

if mptBatch.isOk() and kvtBatchesOk:
# TODO the `persist` api stages changes but does not actually persist - a
# separate "actually-write" api is needed so the changes from both
# kvt and ari can be staged and then written together - for this to
Expand All @@ -97,14 +114,18 @@ proc persist*(db: CoreDbRef, txFrame: CoreDbTxRef) =
# error), we have to panic instead.

let kvtTick = Moment.now()
db.kvt.persist(kvtBatch[], txFrame.kTx)
for i, kvt in db.kvts:
if not kvt.isNil():
kvt.persist(kvtBatches[i][], txFrame.kTxs[i])

let mptTick = Moment.now()
db.mpt.persist(mptBatch[], txFrame.aTx)

let endTick = Moment.now()
db.kvt.putEndFn(kvtBatch[]).isOkOr:
raiseAssert $error

for i, kvt in db.kvts:
if not kvt.isNil():
kvt.putEndFn(kvtBatches[i][]).isOkOr:
raiseAssert $error
db.mpt.putEndFn(mptBatch[]).isOkOr:
raiseAssert $error

Expand All @@ -113,8 +134,10 @@ proc persist*(db: CoreDbRef, txFrame: CoreDbTxRef) =
mptDur = endTick - mptTick,
endDur = Moment.now() - endTick
else:
discard kvtBatch.expect("should always be able to create batch")
discard mptBatch.expect("should always be able to create batch")
for i, kvt in db.kvts:
if not kvt.isNil():
discard kvtBatches[i].expect("should always be able to create batch")

proc stateBlockNumber*(db: CoreDbTxRef): BlockNumber =
## This function returns the block number stored with the latest `persist()`
Expand Down Expand Up @@ -143,40 +166,40 @@ proc verifyProof*(

# ----------- KVT ---------------

proc get*(kvt: CoreDbTxRef; key: openArray[byte]): CoreDbRc[seq[byte]] =
proc get*(kvt: CoreDbTxRef; key: openArray[byte], kvtType = KvtType.Generic): CoreDbRc[seq[byte]] =
## This function always returns a non-empty `seq[byte]` or an error code.
let rc = kvt.kTx.get(key)
let rc = kvt.kTxs[kvtType].get(key)
if rc.isOk:
ok(rc.value)
elif rc.error == GetNotFound:
err(rc.error.toError("", KvtNotFound))
else:
err(rc.error.toError(""))

proc getOrEmpty*(kvt: CoreDbTxRef; key: openArray[byte]): CoreDbRc[seq[byte]] =
proc getOrEmpty*(kvt: CoreDbTxRef; key: openArray[byte], kvtType = KvtType.Generic): CoreDbRc[seq[byte]] =
## Variant of `get()` returning an empty `seq[byte]` if the key is not found
## on the database.
##
let rc = kvt.kTx.get(key)
let rc = kvt.kTxs[kvtType].get(key)
if rc.isOk:
ok(rc.value)
elif rc.error == GetNotFound:
CoreDbRc[seq[byte]].ok(EmptyBlob)
else:
err(rc.error.toError(""))

proc len*(kvt: CoreDbTxRef; key: openArray[byte]): CoreDbRc[int] =
proc len*(kvt: CoreDbTxRef; key: openArray[byte], kvtType = KvtType.Generic): CoreDbRc[int] =
## This function returns the size of the value associated with `key`.
let rc = kvt.kTx.len(key)
let rc = kvt.kTxs[kvtType].len(key)
if rc.isOk:
ok(rc.value)
elif rc.error == GetNotFound:
err(rc.error.toError("", KvtNotFound))
else:
err(rc.error.toError(""))

proc del*(kvt: CoreDbTxRef; key: openArray[byte]): CoreDbRc[void] =
kvt.kTx.del(key).isOkOr:
proc del*(kvt: CoreDbTxRef; key: openArray[byte], kvtType = KvtType.Generic): CoreDbRc[void] =
kvt.kTxs[kvtType].del(key).isOkOr:
return err(error.toError(""))

ok()
Expand All @@ -185,30 +208,31 @@ proc put*(
kvt: CoreDbTxRef;
key: openArray[byte];
val: openArray[byte];
kvtType = KvtType.Generic;
): CoreDbRc[void] =
kvt.kTx.put(key, val).isOkOr:
kvt.kTxs[kvtType].put(key, val).isOkOr:
return err(error.toError(""))

ok()

proc hasKeyRc*(kvt: CoreDbTxRef; key: openArray[byte]): CoreDbRc[bool] =
proc hasKeyRc*(kvt: CoreDbTxRef; key: openArray[byte], kvtType = KvtType.Generic): CoreDbRc[bool] =
## For the argument `key` return `true` if `get()` returned a value on
## that argument, `false` if it returned `GetNotFound`, and an error
## otherwise.
##
let rc = kvt.kTx.hasKeyRc(key).valueOr:
let rc = kvt.kTxs[kvtType].hasKeyRc(key).valueOr:
return err(error.toError(""))

ok(rc)

proc hasKey*(kvt: CoreDbTxRef; key: openArray[byte]): bool =
proc hasKey*(kvt: CoreDbTxRef; key: openArray[byte], kvtType = KvtType.Generic): bool =
## Simplified version of `hasKeyRc` where `false` is returned instead of
## an error.
##
## This function prototype is in line with the `hasKey` function for
## `Tables`.
##
result = kvt.kTx.hasKeyRc(key).valueOr: false
result = kvt.kTxs[kvtType].hasKeyRc(key).valueOr: false

# ------------------------------------------------------------------------------
# Public methods for accounts
Expand Down Expand Up @@ -463,23 +487,29 @@ proc putSubtrie*(
proc txFrameBegin*(db: CoreDbRef): CoreDbTxRef =
## Constructor
##
let
kTx = db.kvt.txFrameBegin(nil)
aTx = db.mpt.txFrameBegin(nil, false)
let aTx = db.mpt.txFrameBegin(nil, false)

CoreDbTxRef(kTx: kTx, aTx: aTx)
var kTxs: array[KvtType, KvtTxRef]
for i, kvt in db.kvts:
if not kvt.isNil():
kTxs[i] = kvt.txFrameBegin(nil)

CoreDbTxRef(aTx: aTx, kTxs: kTxs)

proc txFrameBegin*(
parent: CoreDbTxRef,
moveParentHashKeys = false
): CoreDbTxRef =
## Constructor
##
let
kTx = parent.kTx.db.txFrameBegin(parent.kTx)
aTx = parent.aTx.db.txFrameBegin(parent.aTx, moveParentHashKeys)
let aTx = parent.aTx.db.txFrameBegin(parent.aTx, moveParentHashKeys)

var kTxs: array[KvtType, KvtTxRef]
for i, kTx in parent.kTxs:
if not kTx.isNil():
kTxs[i] = kTx.db.txFrameBegin(kTx)

CoreDbTxRef(kTx: kTx, aTx: aTx)
CoreDbTxRef(aTx: aTx, kTxs: kTxs)

proc checkpoint*(tx: CoreDbTxRef, blockNumber: BlockNumber, skipSnapshot = false) =
tx.aTx.checkpoint(blockNumber, skipSnapshot)
Expand All @@ -489,7 +519,9 @@ proc clearSnapshot*(tx: CoreDbTxRef) =

proc dispose*(tx: CoreDbTxRef) =
tx.aTx.dispose()
tx.kTx.dispose()
for kTx in tx.kTxs:
if not kTx.isNil():
kTx.dispose()
tx[].reset()

# ------------------------------------------------------------------------------
Expand Down
10 changes: 5 additions & 5 deletions execution_chain/db/core_db/base/base_desc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ type
# --------------------------------------------------
CoreDbRef* = ref object
## Database descriptor
dbType*: CoreDbType ## Type of database backend
mpt*: AristoDbRef ## `Aristo` database
kvt*: KvtDbRef ## `KVT` key-value table
dbType*: CoreDbType ## Type of database backend
mpt*: AristoDbRef ## `Aristo` database
kvts*: array[KvtType, KvtDbRef] ## `KVT` key-value tables

CoreDbTxRef* = ref object
## Transaction descriptor
aTx*: AristoTxRef ## `Aristo` transaction (if any)
kTx*: KvtTxRef ## `KVT` transaction (if any)
aTx*: AristoTxRef ## `Aristo` transaction (if any)
kTxs*: array[KvtType, KvtTxRef] ## `KVT` transactions (if any)

CoreDbError* = object
## Generic error object
Expand Down
8 changes: 4 additions & 4 deletions execution_chain/db/core_db/core_apps.nim
Original file line number Diff line number Diff line change
Expand Up @@ -631,24 +631,24 @@ proc persistUncles*(db: CoreDbTxRef, uncles: openArray[Header]): Hash32 =
return EMPTY_ROOT_HASH

proc persistWitness*(db: CoreDbTxRef, blockHash: Hash32, witness: Witness): Result[void, string] =
db.put(blockHashToWitnessKey(blockHash).toOpenArray, witness.encode()).isOkOr:
db.put(blockHash.data, witness.encode(), KvtType.Witness).isOkOr:
return err("persistWitness: " & $$error)
ok()

proc getWitness*(db: CoreDbTxRef, blockHash: Hash32): Result[Witness, string] =
let witnessBytes = db.get(blockHashToWitnessKey(blockHash).toOpenArray).valueOr:
let witnessBytes = db.get(blockHash.data, KvtType.Witness).valueOr:
return err("getWitness: " & $$error)

Witness.decode(witnessBytes)

proc getCodeByHash*(db: CoreDbTxRef, codeHash: Hash32): Result[seq[byte], string] =
let code = db.get(contractHashKey(codeHash).toOpenArray).valueOr:
let code = db.get(codeHash.data, KvtType.ContractCode).valueOr:
return err("getCodeByHash: " & $$error)

ok(code)

proc setCodeByHash*(db: CoreDbTxRef, codeHash: Hash32, code: openArray[byte]): Result[void, string] =
db.put(contractHashKey(codeHash).toOpenArray, code).isOkOr:
db.put(codeHash.data, code, KvtType.ContractCode).isOkOr:
return err("setCodeByHash: " & $$error)

ok()
Expand Down
1 change: 1 addition & 0 deletions execution_chain/db/kvt.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export
KvtDbRef,
KvtError,
KvtTxRef,
KvtType,
isValid

# End
7 changes: 2 additions & 5 deletions execution_chain/db/kvt/kvt_constants.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Copyright (c) 2023-2025 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)
Expand All @@ -8,10 +8,7 @@
# at your option. This file may not be copied, modified, or distributed
# except according to those terms.

import
../aristo/aristo_constants
import ../aristo/aristo_constants

export
EmptyBlob

# End
Loading