Compare commits

...

3 Commits

Author SHA1 Message Date
tersec e1bb65fdfa
rm PoW hash function and validation support (#2372) 2024-06-16 10:22:06 +07:00
andri lim 69044dda60
Remove AccountStateDB (#2368)
* Remove AccountStateDB

AccountStateDB should no longer be used.
It's usage have been reduce to read only operations.
Replace it with LedgerRef to reduce maintenance burden.

* remove extra spaces

Co-authored-by: tersec <tersec@users.noreply.github.com>

---------

Co-authored-by: tersec <tersec@users.noreply.github.com>
2024-06-16 10:21:02 +07:00
andri lim a36aa95fab
Bump nim-bearssl for gcc-14 compatibility (#2366) 2024-06-16 10:20:42 +07:00
25 changed files with 69 additions and 957 deletions

5
.gitmodules vendored
View File

@ -113,11 +113,6 @@
url = https://github.com/status-im/nimbus-build-system.git url = https://github.com/status-im/nimbus-build-system.git
ignore = dirty ignore = dirty
branch = master branch = master
[submodule "vendor/ethash"]
path = vendor/ethash
url = https://github.com/status-im/nim-ethash
ignore = dirty
branch = master
[submodule "vendor/nim-evmc"] [submodule "vendor/nim-evmc"]
path = vendor/nim-evmc path = vendor/nim-evmc
url = https://github.com/status-im/nim-evmc url = https://github.com/status-im/nim-evmc

View File

@ -12,7 +12,7 @@
import import
chronicles, chronicles,
eth/trie/trie_defs, eth/trie/trie_defs,
../core/[pow, casper], ../core/casper,
../db/[core_db, ledger, storage_types], ../db/[core_db, ledger, storage_types],
../utils/[utils, ec_recover], ../utils/[utils, ec_recover],
".."/[constants, errors], ".."/[constants, errors],
@ -81,9 +81,6 @@ type
## installing a snapshot pivot. The default value for this field is ## installing a snapshot pivot. The default value for this field is
## `GENESIS_PARENT_HASH` to start at the very beginning. ## `GENESIS_PARENT_HASH` to start at the very beginning.
pow: PowRef
## Wrapper around `hashimotoLight()` and lookup cache
pos: CasperRef pos: CasperRef
## Proof Of Stake descriptor ## Proof Of Stake descriptor
@ -141,9 +138,6 @@ proc init(com : CommonRef,
com.networkId = networkId com.networkId = networkId
com.syncProgress= SyncProgress() com.syncProgress= SyncProgress()
com.pruneHistory= pruneHistory com.pruneHistory= pruneHistory
# Always initialise the PoW epoch cache even though it migh no be used
com.pow = PowRef.new
com.pos = CasperRef.new com.pos = CasperRef.new
# com.currentFork and com.consensusType # com.currentFork and com.consensusType
@ -253,7 +247,6 @@ func clone*(com: CommonRef, db: CoreDbRef): CommonRef =
networkId : com.networkId, networkId : com.networkId,
currentFork : com.currentFork, currentFork : com.currentFork,
consensusType: com.consensusType, consensusType: com.consensusType,
pow : com.pow,
pos : com.pos, pos : com.pos,
pruneHistory : com.pruneHistory) pruneHistory : com.pruneHistory)
@ -396,10 +389,6 @@ func startOfHistory*(com: CommonRef): Hash256 =
## Getter ## Getter
com.startOfHistory com.startOfHistory
func pow*(com: CommonRef): PowRef =
## Getter
com.pow
func pos*(com: CommonRef): CasperRef = func pos*(com: CommonRef): CasperRef =
## Getter ## Getter
com.pos com.pos

View File

@ -13,8 +13,7 @@
import import
../../common/common, ../../common/common,
../../utils/utils, ../../utils/utils,
../../vm_types, ../../vm_types
../pow
export export
common common
@ -41,7 +40,7 @@ type
# Public constructors # Public constructors
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc newChain*(com: CommonRef, func newChain*(com: CommonRef,
extraValidation: bool, extraValidation: bool,
vmState = BaseVMState(nil)): ChainRef = vmState = BaseVMState(nil)): ChainRef =
## Constructor for the `Chain` descriptor object. ## Constructor for the `Chain` descriptor object.
@ -65,27 +64,23 @@ func newChain*(com: CommonRef): ChainRef =
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public `Chain` getters # Public `Chain` getters
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc vmState*(c: ChainRef): BaseVMState = func vmState*(c: ChainRef): BaseVMState =
## Getter ## Getter
c.vmState c.vmState
proc pow*(c: ChainRef): PowRef = func db*(c: ChainRef): CoreDbRef =
## Getter
c.com.pow
proc db*(c: ChainRef): CoreDbRef =
## Getter ## Getter
c.com.db c.com.db
proc com*(c: ChainRef): CommonRef = func com*(c: ChainRef): CommonRef =
## Getter ## Getter
c.com c.com
proc extraValidation*(c: ChainRef): bool = func extraValidation*(c: ChainRef): bool =
## Getter ## Getter
c.extraValidation c.extraValidation
proc verifyFrom*(c: ChainRef): BlockNumber = func verifyFrom*(c: ChainRef): BlockNumber =
## Getter ## Getter
c.verifyFrom c.verifyFrom
@ -100,12 +95,12 @@ proc currentBlock*(c: ChainRef): BlockHeader
# Public `Chain` setters # Public `Chain` setters
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc `extraValidation=`*(c: ChainRef; extraValidation: bool) = func `extraValidation=`*(c: ChainRef; extraValidation: bool) =
## Setter. If set `true`, the assignment value `extraValidation` enables ## Setter. If set `true`, the assignment value `extraValidation` enables
## extra block chain validation. ## extra block chain validation.
c.extraValidation = extraValidation c.extraValidation = extraValidation
proc `verifyFrom=`*(c: ChainRef; verifyFrom: BlockNumber) = func `verifyFrom=`*(c: ChainRef; verifyFrom: BlockNumber) =
## Setter. The assignment value `verifyFrom` defines the first block where ## Setter. The assignment value `verifyFrom` defines the first block where
## validation should start if the `Clique` field `extraValidation` was set ## validation should start if the `Clique` field `extraValidation` was set
## `true`. ## `true`.

View File

@ -1,211 +0,0 @@
# Nimbus
# Copyright (c) 2018-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.
## Block PoW Support (Verifying & Mining)
## ======================================
##
{.push raises: [].}
import
std/[options, strutils],
../utils/utils,
./pow/pow_cache,
eth/[common, keys, p2p, rlp],
stew/endians2,
ethash,
stint
type
PowDigest = tuple ##\
## Return value from the `hashimotoLight()` function
mixDigest: Hash256
value : Hash256
PowSpecs* = object ##\
## Relevant block header parts for PoW mining & verifying. This object
## might be more useful for testing and debugging than for production.
number* : BlockNumber
miningHash*: Hash256
nonce : BlockNonce
mixHash* : Hash256
difficulty : DifficultyInt
PowHeader = object ##\
## Stolen from `p2p/validate.MiningHeader`
parentHash : Hash256
ommersHash : Hash256
coinbase : EthAddress
stateRoot : Hash256
txRoot : Hash256
receiptsRoot: Hash256
logsBloom : common.BloomFilter
difficulty : DifficultyInt
number : BlockNumber
gasLimit : GasInt
gasUsed : GasInt
timestamp : EthTime
extraData : Blob
PowRef* = ref object of RootObj ##\
## PoW context descriptor
lightByEpoch: PowCacheRef ## PoW cache indexed by epoch
# You should only create one instance of the RNG per application / library
# Ref is used so that it can be shared between components
rng: ref HmacDrbgContext
# ------------------------------------------------------------------------------
# Private functions: RLP support
# ------------------------------------------------------------------------------
func append(w: var RlpWriter; specs: PowSpecs) =
## RLP support
w.startList(5)
w.append(HashOrNum(isHash: false, number: specs.number))
w.append(HashOrNum(isHash: true, hash: specs.miningHash))
w.append(specs.nonce.toUint)
w.append(HashOrNum(isHash: true, hash: specs.mixHash))
w.append(specs.difficulty)
func read(rlp: var Rlp; Q: type PowSpecs): Q
{.raises: [RlpError].} =
## RLP support
rlp.tryEnterList()
result.number = rlp.read(HashOrNum).number
result.miningHash = rlp.read(HashOrNum).hash
result.nonce = rlp.read(uint64).toBlockNonce
result.mixHash = rlp.read(HashOrNum).hash
result.difficulty = rlp.read(DifficultyInt)
func rlpTextEncode(specs: PowSpecs): string =
"specs #" & $specs.number & " " & rlp.encode(specs).toHex
func decodeRlpText(data: string): PowSpecs
{.raises: [CatchableError].} =
if 180 < data.len and data[0 .. 6] == "specs #":
let hexData = data.split
if hexData.len == 3:
var rlpData = hexData[2].rlpFromHex
result = rlpData.read(PowSpecs)
# ------------------------------------------------------------------------------
# Private functions
# ------------------------------------------------------------------------------
func miningHash(header: BlockHeader): Hash256 =
## Calculate hash from mining relevant fields of the argument `header`
let miningHeader = PowHeader(
parentHash: header.parentHash,
ommersHash: header.ommersHash,
coinbase: header.coinbase,
stateRoot: header.stateRoot,
txRoot: header.txRoot,
receiptsRoot:header.receiptsRoot,
logsBloom: header.logsBloom,
difficulty: header.difficulty,
number: header.number,
gasLimit: header.gasLimit,
gasUsed: header.gasUsed,
timestamp: header.timestamp,
extraData: header.extraData)
rlpHash(miningHeader)
# ---------------
proc init(tm: PowRef; light: Option[PowCacheRef]) =
## Constructor
tm.rng = newRng()
if light.isSome:
tm.lightByEpoch = light.get
else:
tm.lightByEpoch = PowCacheRef.new
# ------------------------------------------------------------------------------
# Public functions, Constructor
# ------------------------------------------------------------------------------
proc new*(T: type PowRef; cache: PowCacheRef): T =
## Constructor
new result
result.init(some(cache))
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
func getPowSpecs*(header: BlockHeader): PowSpecs =
## Extracts relevant parts from the `header` argument that are needed
## for mining or pow verification. This function might be more useful for
## testing and debugging than for production.
PowSpecs(
number: header.number,
miningHash: header.miningHash,
nonce: header.nonce,
mixHash: header.mixHash,
difficulty: header.difficulty)
func getPowCacheLookup*(tm: PowRef;
blockNumber: BlockNumber): (uint64, Hash256)
{.gcsafe, raises: [KeyError].} =
## Returns the pair `(size,digest)` derived from the lookup cache for the
## `hashimotoLight()` function for the given block number. The `size` is the
## full size of the dataset (the cache represents) as passed on to the
## `hashimotoLight()` function. The `digest` is a hash derived from the
## cache that would be passed on to `hashimotoLight()`.
##
## This function is intended for error reporting and might also be useful
## for testing and debugging.
let ds = tm.lightByEpoch.get(blockNumber)
if ds == nil:
raise newException(KeyError, "block not found")
result[0] = ds.size
result[1] = withKeccakHash:
for a in ds.data:
h.update(a.data)
# ------------------------
func getPowDigest(tm: PowRef; blockNumber: BlockNumber;
powHeaderDigest: Hash256; nonce: BlockNonce): PowDigest =
## Calculate the expected value of `header.mixHash` using the
## `hashimotoLight()` library method.
let
ds = tm.lightByEpoch.get(blockNumber)
u64Nonce = uint64.fromBytesBE(nonce)
hashimotoLight(ds.size, ds.data, powHeaderDigest, u64Nonce)
func getPowDigest*(tm: PowRef; header: BlockHeader): PowDigest =
## Variant of `getPowDigest()`
tm.getPowDigest(header.number, header.miningHash, header.nonce)
func getPowDigest*(tm: PowRef; specs: PowSpecs): PowDigest =
## Variant of `getPowDigest()`
tm.getPowDigest(specs.number, specs.miningHash, specs.nonce)
# ------------------------------------------------------------------------------
# Public functions, debugging & testing
# ------------------------------------------------------------------------------
func dumpPowSpecs*(specs: PowSpecs): string =
## Text representation of `PowSpecs` argument object
specs.rlpTextEncode
func undumpPowSpecs*(data: string): PowSpecs
{.raises: [CatchableError].} =
## Recover `PowSpecs` object from text representation
data.decodeRlpText
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -1,116 +0,0 @@
# Nimbus
# Copyright (c) 2018-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.
## LRU Cache for Epoch Indexed Hashimoto Cache
## ============================================
##
## This module uses the eth-block number (mapped to epoch) to hold and re-use
## the cache needed for running the `hasimotoLight()` proof-of-work function.
import
eth/common,
ethash,
stew/keyed_queue
{.push raises: [].}
type
PowCacheItemRef* = ref object
size*: uint64
data*: seq[MDigest[512]]
PowCacheStats* = tuple
maxItems: int
size: int
PowCache* = object
cacheMax: int
cache: KeyedQueue[uint64,PowCacheItemRef]
PowCacheRef* = ref PowCache
const
nItemsMax = 10
nItemsInit = 2
# ------------------------------------------------------------------------------
# Private helpers
# ------------------------------------------------------------------------------
proc toKey(bn: BlockNumber): uint64 =
bn div EPOCH_LENGTH
# ------------------------------------------------------------------------------
# Public functions, constructor
# ------------------------------------------------------------------------------
proc init*(pc: var PowCache; maxItems = nItemsMax) =
## Constructor for PoW cache
pc.cacheMax = maxItems
pc.cache.init(nItemsInit)
proc init*(T: type PowCache; maxItems = nItemsMax): T =
## Constructor variant
result.init(maxItems)
proc new*(T: type PowCacheRef; maxItems = nItemsMax): T =
## Constructor variant
new result
result[].init(maxItems)
# ------------------------------------------------------------------------------
# Public functions, constructor
# ------------------------------------------------------------------------------
proc get*(pc: var PowCache; bn: BlockNumber): PowCacheItemRef =
## Return a cache derived from argument `blockNumber` ready to be used
## for the `hashimotoLight()` method.
let
key = bn.toKey
rc = pc.cache.lruFetch(key)
if rc.isOk:
return rc.value
let
# note that `getDataSize()` and `getCacheSize()` depend on
# `key * EPOCH_LENGTH` rather than the original block number.
top = key * EPOCH_LENGTH
pair = PowCacheItemRef(
size: top.getDataSize,
data: top.getCacheSize.mkcache(top.getSeedhash))
pc.cache.lruAppend(key, pair, pc.cacheMax)
proc get*(pcr: PowCacheRef; bn: BlockNumber): PowCacheItemRef =
## Variant of `getCache()`
pcr[].get(bn)
proc hasItem*(pc: var PowCache; bn: BlockNumber): bool =
## Returns true if there is a cache entry for argument `bn`.
pc.cache.hasKey(bn.toKey)
proc hasItem*(pcr: PowCacheRef; bn: BlockNumber): bool =
## Variant of `hasItem()`
pcr[].hasItem(bn)
# -------------------------
proc stats*(pc: var PowCache): PowCacheStats =
## Return current cache sizes
result = (maxItems: pc.cacheMax, size: pc.cache.len)
proc stats*(pcr: PowCacheRef): PowCacheStats =
## Variant of `stats()`
pcr[].stats
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -18,7 +18,6 @@ import
../utils/utils, ../utils/utils,
"."/[dao, eip4844, gaslimit, withdrawals], "."/[dao, eip4844, gaslimit, withdrawals],
./pow/[difficulty, header], ./pow/[difficulty, header],
./pow,
nimcrypto/utils as cryptoutils, nimcrypto/utils as cryptoutils,
stew/objects, stew/objects,
results results
@ -34,35 +33,9 @@ const
byteutils.hexToByteArray[13](DAOForkBlockExtra).toSeq byteutils.hexToByteArray[13](DAOForkBlockExtra).toSeq
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Pivate validator functions # Private validator functions
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc validateSeal(pow: PowRef; header: BlockHeader): Result[void,string] =
try:
let (expmixHash, miningValue) = pow.getPowDigest(header)
if expmixHash != header.mixHash:
let
miningHash = header.getPowSpecs.miningHash
(size, cachedHash) = try: pow.getPowCacheLookup(header.number)
except KeyError: return err("Unknown block")
except CatchableError as e: return err(e.msg)
return err("mixHash mismatch. actual=$1, expected=$2," &
" blockNumber=$3, miningHash=$4, nonce=$5, difficulty=$6," &
" size=$7, cachedHash=$8" % [
$header.mixHash, $expmixHash, $header.number,
$miningHash, header.nonce.toHex, $header.difficulty,
$size, $cachedHash])
let value = UInt256.fromBytesBE(miningValue.data)
if value > UInt256.high div header.difficulty:
return err("mining difficulty error")
except CatchableError as err:
return err(err.msg)
ok()
proc validateHeader( proc validateHeader(
com: CommonRef; com: CommonRef;
blk: EthBlock; blk: EthBlock;
@ -118,9 +91,6 @@ proc validateHeader(
if header.difficulty < calcDiffc: if header.difficulty < calcDiffc:
return err("provided header difficulty is too low") return err("provided header difficulty is too low")
if checkSealOK:
return com.pow.validateSeal(header)
? com.validateWithdrawals(header, blk.withdrawals) ? com.validateWithdrawals(header, blk.withdrawals)
? com.validateEip4844Header(header, parentHeader, blk.transactions) ? com.validateEip4844Header(header, parentHeader, blk.transactions)
? com.validateGasLimitOrBaseFee(header, parentHeader) ? com.validateGasLimitOrBaseFee(header, parentHeader)
@ -195,10 +165,6 @@ proc validateUncles(com: CommonRef; header: BlockHeader;
if uncle.timestamp <= parent.timestamp: if uncle.timestamp <= parent.timestamp:
return err("Uncle's parent must me older") return err("Uncle's parent must me older")
# Now perform VM level validation of the uncle
if checkSealOK:
? com.pow.validateSeal(uncle)
let uncleParent = try: let uncleParent = try:
chainDB.getBlockHeader(uncle.parentHash) chainDB.getBlockHeader(uncle.parentHash)
except BlockNotFound: except BlockNotFound:

View File

@ -988,7 +988,7 @@ proc finalizedHeaderHash*(db: CoreDbRef, headerHash: Hash256) =
proc safeHeader*( proc safeHeader*(
db: CoreDbRef; db: CoreDbRef;
): BlockHeader ): BlockHeader
{.gcsafe, raises: [RlpError,BlockNotFound].} = {.gcsafe, raises: [BlockNotFound].} =
db.getBlockHeader(db.safeHeaderHash) db.getBlockHeader(db.safeHeaderHash)
proc finalizedHeader*( proc finalizedHeader*(

View File

@ -152,8 +152,8 @@ proc init*(x: typedesc[AccountsLedgerRef], db: CoreDbRef,
result.witnessCache = Table[EthAddress, WitnessData]() result.witnessCache = Table[EthAddress, WitnessData]()
discard result.beginSavepoint discard result.beginSavepoint
proc init*(x: typedesc[AccountsLedgerRef], db: CoreDbRef, pruneTrie = true): AccountsLedgerRef = proc init*(x: typedesc[AccountsLedgerRef], db: CoreDbRef): AccountsLedgerRef =
init(x, db, EMPTY_ROOT_HASH, pruneTrie) init(x, db, EMPTY_ROOT_HASH)
# Renamed `rootHash()` => `state()` # Renamed `rootHash()` => `state()`
proc state*(ac: AccountsLedgerRef): KeccakHash = proc state*(ac: AccountsLedgerRef): KeccakHash =
@ -784,6 +784,17 @@ func getAccessList*(ac: AccountsLedgerRef): common.AccessList =
doAssert(ac.savePoint.parentSavepoint.isNil) doAssert(ac.savePoint.parentSavepoint.isNil)
ac.savePoint.accessList.getAccessList() ac.savePoint.accessList.getAccessList()
proc getEthAccount*(ac: AccountsLedgerRef, address: EthAddress): 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 = acc.statement.recast()
if rc.isErr:
raiseAssert "getAccount(): cannot convert account: " & $$rc.error
rc.value
proc state*(db: ReadOnlyStateDB): KeccakHash {.borrow.} proc state*(db: ReadOnlyStateDB): KeccakHash {.borrow.}
proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.} proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
proc getStorageRoot*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.} proc getStorageRoot*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}

View File

@ -356,6 +356,11 @@ proc getMpt*(ldg: LedgerRef): CoreDxMptRef =
result = ldg.ac.rawTrie.CoreDxAccRef.getMpt result = ldg.ac.rawTrie.CoreDxAccRef.getMpt
ldg.ifTrackApi: debug apiTxt, api, elapsed, result ldg.ifTrackApi: debug apiTxt, api, elapsed, result
proc getEthAccount*(ldg: LedgerRef, eAddr: EthAddress): Account =
ldg.beginTrackApi LdgGetAthAccountFn
result = ldg.ac.getEthAccount(eAddr)
ldg.ifTrackApi: debug apiTxt, api, elapsed, result
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public virtual read-only methods # Public virtual read-only methods
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -50,6 +50,7 @@ type
LdgGetStorageFn = "getStorage" LdgGetStorageFn = "getStorage"
LdgGetStorageRootFn = "getStorageRoot" LdgGetStorageRootFn = "getStorageRoot"
LdgGetTransientStorageFn = "getTransientStorage" LdgGetTransientStorageFn = "getTransientStorage"
LdgGetAthAccountFn = "getEthAccount"
LdgInAccessListFn = "inAccessList" LdgInAccessListFn = "inAccessList"
LdgIncNonceFn = "incNonce" LdgIncNonceFn = "incNonce"
LdgIsDeadAccountFn = "isDeadAccount" LdgIsDeadAccountFn = "isDeadAccount"

View File

@ -1,35 +0,0 @@
# Nimbus
# Copyright (c) 2018-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.
## Read only source, import `state_db/read_write` for full functionality.
##
## Note that the writable mode is only partially supported by the `Aristo`
## backend of `CoreDb` (read-only mode is fully supported.)
import
state_db/[base, read_only]
export
AccountStateDB,
ReadOnlyStateDB,
accountExists,
contractCollision,
db,
getAccount,
getBalance,
getCode,
getCodeHash,
getNonce,
getStorage,
getStorageRoot,
isDeadAccount,
isEmptyAccount,
newAccountStateDB,
rootHash,
to
# End

View File

@ -1,314 +0,0 @@
# Nimbus
# Copyright (c) 2018-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
std/[sets, strformat, typetraits],
chronicles,
eth/[common, rlp, trie/trie_defs],
results,
../../constants,
../../utils/utils,
".."/[core_db, ledger, storage_types]
logScope:
topics = "state_db"
# aleth/geth/parity compatibility mode:
#
# affected test cases both in GST and BCT:
# - stSStoreTest\InitCollision.json
# - stRevertTest\RevertInCreateInInit.json
# - stCreate2\RevertInCreateInInitCreate2.json
#
# pyEVM sided with original Nimbus EVM
#
# implementation difference:
# Aleth/geth/parity using accounts cache.
# When contract creation happened on an existing
# but 'empty' account with non empty storage will
# get new empty storage root.
# Aleth cs. only clear the storage cache while both pyEVM
# and Nimbus will modify the state trie.
# During the next SSTORE call, aleth cs. calculate
# gas used based on this cached 'original storage value'.
# In other hand pyEVM and Nimbus will fetch
# 'original storage value' from state trie.
#
# Both Yellow Paper and EIP2200 are not clear about this
# situation but since aleth/geth/and parity implement this
# behaviour, we perhaps also need to implement it.
#
# TODO: should this compatibility mode enabled via
# compile time switch, runtime switch, or just hard coded
# it?
const
aleth_compat = true
type
AccountStateDB* = ref object
trie: AccountLedger
originalRoot: KeccakHash # will be updated for every transaction
when aleth_compat:
cleared: HashSet[EthAddress]
#MptNodeRlpBytes* = seq[byte]
#AccountProof* = seq[MptNodeRlpBytes]
#SlotProof* = seq[MptNodeRlpBytes]
proc db*(db: AccountStateDB): CoreDbRef =
db.trie.db
proc rootHash*(db: AccountStateDB): KeccakHash =
db.trie.state
proc `rootHash=`*(db: AccountStateDB, root: KeccakHash) =
db.trie = AccountLedger.init(db.trie.db, root)
func newCoreDbAccount(
eAddr: EthAddress;
nonce = AccountNonce(0);
balance = 0.u256;
): CoreDbAccount =
CoreDbAccount(
address: eAddr,
nonce: nonce,
balance: balance,
codeHash: EMPTY_CODE_HASH)
proc newAccountStateDB*(backingStore: CoreDbRef,
root: KeccakHash): AccountStateDB =
result.new()
result.trie = AccountLedger.init(backingStore, root)
result.originalRoot = root
when aleth_compat:
result.cleared = HashSet[EthAddress]()
#proc getTrie*(db: AccountStateDB): CoreDxMptRef =
# db.trie.mpt
#proc getSecureTrie*(db: AccountStateDB): CoreDbPhkRef =
# db.trie.phk
proc to*(acc: CoreDbAccount; T: type Account): T =
## Convert to legacy object, will throw an aseert if that fails
let rc = acc.recast()
if rc.isErr:
raiseAssert "getAccount(): cannot convert account: " & $$rc.error
rc.value
proc getAccount*(db: AccountStateDB, eAddr: EthAddress): CoreDbAccount =
db.trie.fetch(eAddr).valueOr:
return newCoreDbAccount(eAddr)
proc setAccount*(db: AccountStateDB, acc: CoreDbAccount) =
db.trie.merge(acc)
proc deleteAccount*(db: AccountStateDB, acc: CoreDbAccount) =
db.trie.delete(acc.address)
proc deleteAccount*(db: AccountStateDB, eAddr: EthAddress) =
db.trie.delete(eAddr)
proc getCodeHash*(db: AccountStateDB, eAddr: EthAddress): Hash256 =
db.getAccount(eAddr).codeHash
proc getBalance*(db: AccountStateDB, eAddr: EthAddress): UInt256 =
db.getAccount(eAddr).balance
proc setBalance*(db: AccountStateDB, eAddr: EthAddress, balance: UInt256) =
var acc = db.getAccount(eAddr)
if acc.balance != balance:
acc.balance = balance
db.setAccount(acc)
proc addBalance*(db: AccountStateDB, eAddr: EthAddress, delta: UInt256) =
db.setBalance(eAddr, db.getBalance(eAddr) + delta)
#template getStorageTrie(db: AccountStateDB, account: Account): auto =
# storageTrieForAccount(db.trie, account)
proc subBalance*(db: AccountStateDB, eAddr: EthAddress, delta: UInt256) =
db.setBalance(eAddr, db.getBalance(eAddr) - delta)
#template createTrieKeyFromSlot(slot: UInt256): auto =
# # Converts a number to hex big-endian representation including
# # prefix and leading zeros:
# slot.toBytesBE
# # Original py-evm code:
# # pad32(int_to_big_endian(slot))
# # morally equivalent to toByteRange_Unnecessary but with different types
proc clearStorage*(db: AccountStateDB, eAddr: EthAddress) =
# Flush associated storage trie (will update account record on disk)
db.trie.distinctBase.stoDelete(eAddr).isOkOr:
raiseAssert "clearStorage(): stoDelete() failed, " & $$error
# Reset storage info locally so that `Aristo` would not complain when
# updating the account record on disk
var account = db.getAccount(eAddr)
account.storage = CoreDbColRef(nil)
when aleth_compat:
db.cleared.incl eAddr
proc getStorageRoot*(db: AccountStateDB, eAddr: EthAddress): Hash256 =
db.getAccount(eAddr).storage.state.valueOr:
EMPTY_ROOT_HASH
proc setStorage*(
db: AccountStateDB;
eAddr: EthAddress;
slot: UInt256;
value: UInt256;
) =
var
acc = db.getAccount(eAddr)
sto = StorageLedger.init(db.trie, acc)
if value > 0:
sto.merge(slot, rlp.encode(value))
else:
sto.delete(slot)
# map slot hash back to slot value
# see iterator storage below
var
# slotHash can be obtained from storage.merge()?
slotHash = keccakHash(slot.toBytesBE)
db.db.newKvt().put(
slotHashToSlotKey(slotHash.data).toOpenArray, rlp.encode(slot)).isOkOr:
raiseAssert "setStorage(): put(slotHash) failed: " & $$error
# Changing the storage trie might also change the `storage` descriptor when
# the trie changes from empty to existing or v.v.
acc.storage = sto.getColumn()
# No need to hold descriptors for longer than needed
let state = acc.storage.state.valueOr:
raiseAssert "Storage column state error: " & $$error
if state == EMPTY_ROOT_HASH:
acc.storage = CoreDbColRef(nil)
iterator storage*(db: AccountStateDB, eAddr: EthAddress): (UInt256, UInt256) =
let kvt = db.db.newKvt()
for key, value in db.trie.storage db.getAccount(eAddr):
if key.len != 0:
var keyData = kvt.get(slotHashToSlotKey(key).toOpenArray).valueOr:
raiseAssert "storage(): get() failed: " & $$error
yield (rlp.decode(keyData, UInt256), rlp.decode(value, UInt256))
proc getStorage*(
db: AccountStateDB;
eAddr: EthAddress;
slot: UInt256;
): Result[UInt256,void] =
let
acc = db.getAccount(eAddr)
data = ? StorageLedger.init(db.trie, acc).fetch(slot)
ok rlp.decode(data, UInt256)
proc setNonce*(db: AccountStateDB, eAddr: EthAddress; nonce: AccountNonce) =
var acc = db.getAccount(eAddr)
if nonce != acc.nonce:
acc.nonce = nonce
db.setAccount(acc)
proc getNonce*(db: AccountStateDB, eAddr: EthAddress): AccountNonce =
db.getAccount(eAddr).nonce
proc incNonce*(db: AccountStateDB, eAddr: EthAddress) {.inline.} =
db.setNonce(eAddr, db.getNonce(eAddr) + 1)
proc setCode*(db: AccountStateDB, eAddr: EthAddress, code: openArray[byte]) =
var acc = db.getAccount(eAddr)
let codeHash = keccakHash(code)
if acc.codeHash != codeHash:
if code.len != 0:
db.db.newKvt().put(contractHashKey(codeHash).toOpenArray, code).isOkOr:
raiseAssert "setCode(): put() failed: " & $$error
acc.codeHash = codeHash
db.setAccount(acc)
proc getCode*(db: AccountStateDB, eAddr: EthAddress): seq[byte] =
let codeHash = db.getCodeHash(eAddr)
db.db.newKvt().get(contractHashKey(codeHash).toOpenArray).valueOr:
EmptyBlob
proc contractCollision*(db: AccountStateDB, eAddr: EthAddress): bool =
db.getNonce(eAddr) != 0 or
db.getCodeHash(eAddr) != EMPTY_CODE_HASH or
db.getStorageRoot(eAddr) != EMPTY_ROOT_HASH
proc dumpAccount*(db: AccountStateDB, eAddr: string): string =
let pAddr = eAddr.parseAddress
return fmt"{eAddr}: Storage: {db.getStorage(pAddr, 0.u256)}; getAccount: {db.getAccount pAddr}"
proc accountExists*(db: AccountStateDB, eAddr: EthAddress): bool =
db.trie.fetch(eAddr).isOk
proc isEmptyAccount*(db: AccountStateDB, eAddr: EthAddress): bool =
let acc = db.trie.fetch(eAddr).valueOr:
return false
acc.nonce == 0 and
acc.balance.isZero and
acc.codeHash == EMPTY_CODE_HASH
proc isDeadAccount*(db: AccountStateDB, eAddr: EthAddress): bool =
let acc = db.trie.fetch(eAddr).valueOr:
return true
acc.nonce == 0 and
acc.balance.isZero and
acc.codeHash == EMPTY_CODE_HASH
#proc removeEmptyRlpNode(branch: var seq[MptNodeRlpBytes]) =
# if branch.len() == 1 and branch[0] == emptyRlp:
# branch.del(0)
#proc getAccountProof*(db: AccountStateDB, eAddr: EthAddress): AccountProof =
# var branch = db.trie.phk().getBranch(eAddr)
# removeEmptyRlpNode(branch)
# branch
#proc getStorageProof*(db: AccountStateDB, eAddr: EthAddress, slots: seq[UInt256]): seq[SlotProof] =
# var acc = db.getAccount(eAddr)
# var storageTrie = StorageLedger.init(db.trie, acc)
#
# var slotProofs = newSeqOfCap[SlotProof](slots.len())
# for slot in slots:
# var branch = storageTrie.phk().getBranch(createTrieKeyFromSlot(slot))
# removeEmptyRlpNode(branch)
# slotProofs.add(branch)
#
# slotProofs
# Note: `state_db.getCommittedStorage()` is nowhere used.
#
#proc getCommittedStorage*(db: AccountStateDB, eAddr: EthAddress, slot: UInt256): UInt256 =
# let tmpHash = db.rootHash
# db.rootHash = db.originalRoot
# db.transactionID.shortTimeReadOnly():
# when aleth_compat:
# if eAddr in db.cleared:
# debug "Forced contract creation on existing account detected", eAddr
# result = 0.u256
# else:
# result = db.getStorage(eAddr, slot)[0]
# else:
# result = db.getStorage(eAddr, slot)[0]
# db.rootHash = tmpHash
# Note: `state_db.updateOriginalRoot()` is nowhere used.
#
#proc updateOriginalRoot*(db: AccountStateDB) =
# ## this proc will be called for every transaction
# db.originalRoot = db.rootHash
# # no need to rollback or dispose
# # transactionID, it will be handled elsewhere
# db.transactionID = db.db.getTransactionID()
#
# when aleth_compat:
# db.cleared.clear()
# End

View File

@ -1,37 +0,0 @@
# Nimbus
# Copyright (c) 2018-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
results,
../core_db,
./base
type
ReadOnlyStateDB* = distinct AccountStateDB
#proc getTrie*(db: ReadOnlyStateDB): CoreDbMptRef {.borrow.}
proc db*(db: ReadOnlyStateDB): CoreDbRef {.borrow.}
proc rootHash*(db: ReadOnlyStateDB): KeccakHash {.borrow.}
proc getAccount*(db: ReadOnlyStateDB, address: EthAddress): CoreDbAccount {.borrow.}
proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
proc getBalance*(db: ReadOnlyStateDB, address: EthAddress): UInt256 {.borrow.}
proc getStorageRoot*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
proc getStorage*(db: ReadOnlyStateDB, address: EthAddress, slot: UInt256): Result[UInt256,void] {.borrow.}
proc getNonce*(db: ReadOnlyStateDB, address: EthAddress): AccountNonce {.borrow.}
proc getCode*(db: ReadOnlyStateDB, address: EthAddress): seq[byte] {.borrow.}
proc contractCollision*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
proc accountExists*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
proc isDeadAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
proc isEmptyAccount*(db: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}
#proc getAccountProof*(db: ReadOnlyStateDB, address: EthAddress): AccountProof {.borrow.}
#proc getStorageProof*(db: ReadOnlyStateDB, address: EthAddress, slots: seq[UInt256]): seq[SlotProof] {.borrow.}
#proc getCommittedStorage*(db: ReadOnlyStateDB, address: EthAddress, slot: UInt256): UInt256 {.borrow.}
# End

View File

@ -1,17 +0,0 @@
# Nimbus
# Copyright (c) 2018-2023 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
"."/[base, read_only]
export
base, read_only
# End

View File

@ -15,7 +15,7 @@ import
graphql, graphql/graphql as context, graphql, graphql/graphql as context,
graphql/common/types, graphql/httpserver, graphql/common/types, graphql/httpserver,
graphql/instruments/query_complexity, graphql/instruments/query_complexity,
../db/[state_db], ../db/[ledger],
../rpc/rpc_types, ../rpc/rpc_types,
../rpc/rpc_utils, ../rpc/rpc_utils,
".."/[transaction, vm_state, config, constants], ".."/[transaction, vm_state, config, constants],
@ -47,7 +47,7 @@ type
AccountNode = ref object of Node AccountNode = ref object of Node
address: EthAddress address: EthAddress
account: Account account: Account
db: ReadOnlyStateDB db: LedgerRef
TxNode = ref object of Node TxNode = ref object of Node
tx: Transaction tx: Transaction
@ -99,7 +99,7 @@ proc headerNode(ctx: GraphqlContextRef, header: common.BlockHeader): Node =
header: header header: header
) )
proc accountNode(ctx: GraphqlContextRef, acc: Account, address: EthAddress, db: ReadOnlyStateDB): Node = proc accountNode(ctx: GraphqlContextRef, acc: Account, address: EthAddress, db: LedgerRef): Node =
AccountNode( AccountNode(
kind: nkMap, kind: nkMap,
typeName: ctx.ids[ethAccount], typeName: ctx.ids[ethAccount],
@ -146,11 +146,10 @@ proc wdNode(ctx: GraphqlContextRef, wd: Withdrawal): Node =
wd: wd wd: wd
) )
proc getStateDB(com: CommonRef, header: common.BlockHeader): ReadOnlyStateDB = proc getStateDB(com: CommonRef, header: common.BlockHeader): LedgerRef =
## Retrieves the account db from canonical head ## Retrieves the account db from canonical head
## we don't use accounst_cache here because it's read only operations ## we don't use accounst_cache here because it's read only operations
let ac = newAccountStateDB(com.db, header.stateRoot) LedgerRef.init(com.db, header.stateRoot)
ReadOnlyStateDB(ac)
proc getBlockByNumber(ctx: GraphqlContextRef, number: Node): RespResult = proc getBlockByNumber(ctx: GraphqlContextRef, number: Node): RespResult =
try: try:
@ -353,8 +352,8 @@ proc accountNode(ctx: GraphqlContextRef, header: common.BlockHeader, address: Et
# but hive test case demand something # but hive test case demand something
if not db.accountExists(address): if not db.accountExists(address):
return ok(respNull()) return ok(respNull())
let acc = db.getAccount(address) let acc = db.getEthAccount(address)
ok(accountNode(ctx, acc.to(Account), address, db)) ok(accountNode(ctx, acc, address, db))
except RlpError as ex: except RlpError as ex:
err(ex.msg) err(ex.msg)
@ -552,7 +551,7 @@ proc accountStorage(ud: RootRef, params: Args, parent: Node): RespResult {.apiPr
let acc = AccountNode(parent) let acc = AccountNode(parent)
try: try:
let slot = parse(params[0].val.stringVal, UInt256, radix = 16) let slot = parse(params[0].val.stringVal, UInt256, radix = 16)
let val = acc.db.getStorage(acc.address, slot).valueOr: 0.u256 let val = acc.db.getStorage(acc.address, slot)
byte32Node(val) byte32Node(val)
except RlpError as ex: except RlpError as ex:
err(ex.msg) err(ex.msg)

View File

@ -14,7 +14,6 @@ import
json_rpc/rpcserver, stint, web3/conversions, json_rpc/rpcserver, stint, web3/conversions,
eth/p2p, eth/p2p,
../[transaction, vm_state, constants, vm_types], ../[transaction, vm_state, constants, vm_types],
../db/state_db,
rpc_types, rpc_utils, rpc_types, rpc_utils,
../common/common, ../common/common,
../utils/utils, ../utils/utils,
@ -27,13 +26,12 @@ import
type type
BlockHeader = eth_types.BlockHeader BlockHeader = eth_types.BlockHeader
ReadOnlyStateDB = state_db.ReadOnlyStateDB
proc getMultiKeys*( proc getMultiKeys*(
com: CommonRef, com: CommonRef,
blockHeader: BlockHeader, blockHeader: BlockHeader,
statePostExecution: bool): MultiKeysRef statePostExecution: bool): MultiKeysRef
{.raises: [RlpError, BlockNotFound, ValueError, CatchableError].} = {.raises: [RlpError, BlockNotFound, ValueError].} =
let let
chainDB = com.db chainDB = com.db
@ -60,8 +58,8 @@ proc getMultiKeys*(
mkeys mkeys
proc getBlockProofs*( proc getBlockProofs*(
accDB: ReadOnlyStateDB, accDB: LedgerRef,
mkeys: MultiKeysRef): seq[ProofResponse] {.raises: [RlpError].} = mkeys: MultiKeysRef): seq[ProofResponse] =
var blockProofs = newSeq[ProofResponse]() var blockProofs = newSeq[ProofResponse]()
@ -81,11 +79,10 @@ proc setupExpRpc*(com: CommonRef, server: RpcServer) =
let chainDB = com.db let chainDB = com.db
proc getStateDB(header: BlockHeader): ReadOnlyStateDB = proc getStateDB(header: BlockHeader): LedgerRef =
## Retrieves the account db from canonical head ## Retrieves the account db from canonical head
# we don't use accounst_cache here because it's only read operations # we don't use accounst_cache here because it's only read operations
let ac = newAccountStateDB(chainDB, header.stateRoot) LedgerRef.init(chainDB, header.stateRoot)
result = ReadOnlyStateDB(ac)
server.rpc("exp_getProofsByBlockNumber") do(quantityTag: BlockTag, statePostExecution: bool) -> seq[ProofResponse]: server.rpc("exp_getProofsByBlockNumber") do(quantityTag: BlockTag, statePostExecution: bool) -> seq[ProofResponse]:
## Returns the block proofs for a block by block number or tag. ## Returns the block proofs for a block by block number or tag.

View File

@ -16,7 +16,7 @@ import
eth/common/eth_types_json_serialization, eth/common/eth_types_json_serialization,
eth/[keys, rlp, p2p], eth/[keys, rlp, p2p],
".."/[transaction, vm_state, constants], ".."/[transaction, vm_state, constants],
../db/state_db, ../db/ledger,
./rpc_types, ./rpc_utils, ./oracle, ./rpc_types, ./rpc_utils, ./oracle,
../transaction/call_evm, ../transaction/call_evm,
../core/tx_pool, ../core/tx_pool,
@ -42,23 +42,23 @@ when not AccountAndStorageProofAvailableAndWorking:
AccountProof = seq[MptNodeRlpBytes] AccountProof = seq[MptNodeRlpBytes]
SlotProof = seq[MptNodeRlpBytes] SlotProof = seq[MptNodeRlpBytes]
func getAccountProof( func getAccountProof(
db: ReadOnlyStateDB; db: LedgerRef;
eAddr: EthAddress; eAddr: EthAddress;
): AccountProof = ): AccountProof =
discard discard
func getStorageProof( func getStorageProof(
db: ReadOnlyStateDB; db: LedgerRef;
eAddr: EthAddress; eAddr: EthAddress;
slot: seq[UInt256]; slot: seq[UInt256];
): seq[SlotProof] = ): seq[SlotProof] =
discard discard
proc getProof*( proc getProof*(
accDB: ReadOnlyStateDB, accDB: LedgerRef,
address: EthAddress, address: EthAddress,
slots: seq[UInt256]): ProofResponse {.raises: [RlpError].} = slots: seq[UInt256]): ProofResponse =
let let
acc = accDB.getAccount(address) acc = accDB.getEthAccount(address)
accExists = accDB.accountExists(address) accExists = accDB.accountExists(address)
accountProof = accDB.getAccountProof(address) accountProof = accDB.getAccountProof(address)
slotProofs = accDB.getStorageProof(address, slots) slotProofs = accDB.getStorageProof(address, slots)
@ -66,7 +66,7 @@ proc getProof*(
var storage = newSeqOfCap[StorageProof](slots.len) var storage = newSeqOfCap[StorageProof](slots.len)
for i, slotKey in slots: for i, slotKey in slots:
let slotValue = accDB.getStorage(address, slotKey).valueOr: 0.u256 let slotValue = accDB.getStorage(address, slotKey)
storage.add(StorageProof( storage.add(StorageProof(
key: slotKey, key: slotKey,
value: slotValue, value: slotValue,
@ -79,7 +79,7 @@ proc getProof*(
balance: acc.balance, balance: acc.balance,
nonce: w3Qty(acc.nonce), nonce: w3Qty(acc.nonce),
codeHash: w3Hash(acc.codeHash), codeHash: w3Hash(acc.codeHash),
storageHash: w3Hash(acc.to(Account).storageRoot), storageHash: w3Hash(acc.storageRoot),
storageProof: storage) storageProof: storage)
else: else:
ProofResponse( ProofResponse(
@ -92,13 +92,12 @@ proc setupEthRpc*(
txPool: TxPoolRef, oracle: Oracle, server: RpcServer) = txPool: TxPoolRef, oracle: Oracle, server: RpcServer) =
let chainDB = com.db let chainDB = com.db
proc getStateDB(header: BlockHeader): ReadOnlyStateDB = proc getStateDB(header: BlockHeader): LedgerRef =
## Retrieves the account db from canonical head ## Retrieves the account db from canonical head
# we don't use accounst_cache here because it's only read operations # we don't use accounst_cache here because it's only read operations
let ac = newAccountStateDB(chainDB, header.stateRoot) LedgerRef.init(chainDB, header.stateRoot)
result = ReadOnlyStateDB(ac)
proc stateDBFromTag(quantityTag: BlockTag, readOnly = true): ReadOnlyStateDB proc stateDBFromTag(quantityTag: BlockTag, readOnly = true): LedgerRef
{.gcsafe, raises: [CatchableError].} = {.gcsafe, raises: [CatchableError].} =
result = getStateDB(chainDB.headerFromTag(quantityTag)) result = getStateDB(chainDB.headerFromTag(quantityTag))
@ -182,7 +181,7 @@ proc setupEthRpc*(
let let
accDB = stateDBFromTag(quantityTag) accDB = stateDBFromTag(quantityTag)
address = data.ethAddr address = data.ethAddr
data = accDB.getStorage(address, slot).valueOr: 0.u256 data = accDB.getStorage(address, slot)
result = data.w3FixedBytes result = data.w3FixedBytes
server.rpc("eth_getTransactionCount") do(data: Web3Address, quantityTag: BlockTag) -> Web3Quantity: server.rpc("eth_getTransactionCount") do(data: Web3Address, quantityTag: BlockTag) -> Web3Quantity:

View File

@ -39,7 +39,6 @@ cliBuilder:
./test_multi_keys, ./test_multi_keys,
./test_misc, ./test_misc,
#./test_graphql, -- fails #./test_graphql, -- fails
./test_pow,
./test_configuration, ./test_configuration,
#./test_txpool, -- fails #./test_txpool, -- fails
./test_txpool2, ./test_txpool2,

Binary file not shown.

View File

@ -16,7 +16,7 @@ import
./test_helpers, ./test_allowed_to_fail, ./test_helpers, ./test_allowed_to_fail,
../premix/parser, test_config, ../premix/parser, test_config,
../nimbus/[vm_state, vm_types, errors, constants], ../nimbus/[vm_state, vm_types, errors, constants],
../nimbus/db/[ledger, state_db], ../nimbus/db/ledger,
../nimbus/utils/[utils, debug], ../nimbus/utils/[utils, debug],
../nimbus/evm/tracer/legacy_tracer, ../nimbus/evm/tracer/legacy_tracer,
../nimbus/evm/tracer/json_tracer, ../nimbus/evm/tracer/json_tracer,
@ -187,8 +187,8 @@ proc testGetMultiKeys(chain: ChainRef, parentHeader, currentHeader: BlockHeader)
# use the MultiKeysRef to build the block proofs # use the MultiKeysRef to build the block proofs
let let
ac = newAccountStateDB(chain.com.db, currentHeader.stateRoot) ac = LedgerRef.init(chain.com.db, currentHeader.stateRoot)
blockProofs = getBlockProofs(state_db.ReadOnlyStateDB(ac), mkeys) blockProofs = getBlockProofs(ac, mkeys)
if blockProofs.len() != 0: if blockProofs.len() != 0:
raise newException(ValidationError, "Expected blockProofs.len() == 0") raise newException(ValidationError, "Expected blockProofs.len() == 0")

View File

@ -12,14 +12,12 @@ import
web3/eth_api, web3/eth_api,
nimcrypto/[keccak, hash], nimcrypto/[keccak, hash],
eth/[common, rlp, keys, trie/trie_defs, trie/hexary_proof_verification], eth/[common, rlp, keys, trie/trie_defs, trie/hexary_proof_verification],
../nimbus/db/state_db,
../nimbus/db/[ledger, core_db], ../nimbus/db/[ledger, core_db],
../nimbus/common/chain_config, ../nimbus/common/chain_config,
../nimbus/rpc/p2p ../nimbus/rpc/p2p
type type
Hash256 = eth_types.Hash256 Hash256 = eth_types.Hash256
ReadOnlyStateDB = state_db.ReadOnlyStateDB
func ethAddr*(x: Address): EthAddress = func ethAddr*(x: Address): EthAddress =
EthAddress x EthAddress x
@ -79,7 +77,7 @@ proc setupStateDB(genAccounts: GenesisAlloc, stateDB: LedgerRef): Hash256 =
proc checkProofsForExistingLeafs( proc checkProofsForExistingLeafs(
genAccounts: GenesisAlloc, genAccounts: GenesisAlloc,
accDB: ReadOnlyStateDB, accDB: LedgerRef,
stateRoot: Hash256) = stateRoot: Hash256) =
for address, account in genAccounts: for address, account in genAccounts:
@ -106,7 +104,7 @@ proc checkProofsForExistingLeafs(
proc checkProofsForMissingLeafs( proc checkProofsForMissingLeafs(
genAccounts: GenesisAlloc, genAccounts: GenesisAlloc,
accDB: ReadOnlyStateDB, accDB: LedgerRef,
stateRoot: Hash256) = stateRoot: Hash256) =
let let
@ -137,10 +135,9 @@ proc getProofJsonMain*() =
coreDb = newCoreDbRef(DefaultDbMemory) coreDb = newCoreDbRef(DefaultDbMemory)
accountsCache = LedgerRef.init(coreDb, emptyRlpHash) accountsCache = LedgerRef.init(coreDb, emptyRlpHash)
stateRootHash = setupStateDB(accounts, accountsCache) stateRootHash = setupStateDB(accounts, accountsCache)
accountDb = newAccountStateDB(coreDb, stateRootHash) accountDb = LedgerRef.init(coreDb, stateRootHash)
readOnlyDb = ReadOnlyStateDB(accountDb)
checkProofsForExistingLeafs(accounts, readOnlyDb, stateRootHash) checkProofsForExistingLeafs(accounts, accountDb, stateRootHash)
test "Get proofs for missing leafs": test "Get proofs for missing leafs":
for file in genesisFiles: for file in genesisFiles:
@ -150,10 +147,9 @@ proc getProofJsonMain*() =
coreDb = newCoreDbRef(DefaultDbMemory) coreDb = newCoreDbRef(DefaultDbMemory)
accountsCache = LedgerRef.init(coreDb, emptyRlpHash) accountsCache = LedgerRef.init(coreDb, emptyRlpHash)
stateRootHash = setupStateDB(accounts, accountsCache) stateRootHash = setupStateDB(accounts, accountsCache)
accountDb = newAccountStateDB(coreDb, stateRootHash) accountDb = LedgerRef.init(coreDb, stateRootHash)
readOnlyDb = ReadOnlyStateDB(accountDb)
checkProofsForMissingLeafs(accounts, readOnlyDb, stateRootHash) checkProofsForMissingLeafs(accounts, accountDb, stateRootHash)
when isMainModule: when isMainModule:
getProofJsonMain() getProofJsonMain()

View File

@ -1,109 +0,0 @@
# Nimbus
# Copyright (c) 2022-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
std/[os, sequtils, strformat, strutils, times],
./replay/[pp, gunzip],
../nimbus/core/[pow, pow/pow_cache],
eth/common,
unittest2
const
baseDir = [".", "tests", ".." / "tests", $DirSep] # path containg repo
repoDir = ["replay"] # alternative repos
specsDump = "mainspecs2k.txt.gz"
# ------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------
proc say*(noisy = false; pfx = "***"; args: varargs[string, `$`]) =
if noisy:
if args.len == 0:
echo "*** ", pfx
elif 0 < pfx.len and pfx[^1] != ' ':
echo pfx, " ", args.toSeq.join
else:
echo pfx, args.toSeq.join
proc findFilePath(file: string): string =
result = "?unknown?" / file
for dir in baseDir:
for repo in repoDir:
let path = dir / repo / file
if path.fileExists:
return path
# ------------------------------------------------------------------------------
# Test Runners
# ------------------------------------------------------------------------------
proc runPowTests(noisy = true; file = specsDump;
nVerify = int.high; nFakeMiner = 0, nRealMiner = 0) =
let
filePath = file.findFilePath
fileInfo = file.splitFile.name.split(".")[0]
powCache = PowCacheRef.new # so we can inspect the LRU caches
pow = PowRef.new(powCache)
var specsList: seq[PowSpecs]
suite &"PoW: Header test specs from {fileInfo} capture":
block:
test "Loading from capture":
for (lno,line) in gunzipLines(filePath):
let specs = line.undumpPowSpecs
if 0 < specs.number:
specsList.add specs
check line == specs.dumpPowSpecs
noisy.say "***", " block range #",
specsList[0].number, " .. #", specsList[^1].number
# Adjust number of tests
let
startVerify = max(0, specsList.len - nVerify)
nDoVerify = specsList.len - startVerify
block:
test &"Running single getPowDigest() to fill the cache":
if nVerify <= 0:
skip()
else:
noisy.showElapsed(&"first getPowDigest() instance"):
let p = specsList[startVerify]
check pow.getPowDigest(p).mixDigest == p.mixHash
test &"Running getPowDigest() on {nDoVerify} specs records":
if nVerify <= 0:
skip()
else:
noisy.showElapsed(&"all {nDoVerify} getPowDigest() instances"):
for n in startVerify ..< specsList.len:
let p = specsList[n]
check pow.getPowDigest(p).mixDigest == p.mixHash
# ------------------------------------------------------------------------------
# Main function(s)
# ------------------------------------------------------------------------------
proc powMain*(noisy = defined(debug)) =
noisy.runPowTests(nVerify = 100)
when isMainModule:
# Note:
# 0 < nFakeMiner: allow ~20 minuntes for building lookup table
# 0 < nRealMiner: takes days/months/years ...
true.runPowTests(nVerify = 200, nFakeMiner = 200, nRealMiner = 5)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -33,7 +33,7 @@ import
../nimbus/db/opts, ../nimbus/db/opts,
../nimbus/db/core_db, ../nimbus/db/core_db,
../nimbus/db/core_db/persistent, ../nimbus/db/core_db/persistent,
../nimbus/db/state_db/base, ../nimbus/db/ledger,
./rpc/experimental_rpc_client ./rpc/experimental_rpc_client
const const
@ -53,7 +53,7 @@ template toHash256(hash: untyped): Hash256 =
fromHex(Hash256, hash.toHex()) fromHex(Hash256, hash.toHex())
proc updateStateUsingProofsAndCheckStateRoot( proc updateStateUsingProofsAndCheckStateRoot(
stateDB: AccountStateDB, stateDB: LedgerRef,
expectedStateRoot: Hash256, expectedStateRoot: Hash256,
proofs: seq[ProofResponse]) = proofs: seq[ProofResponse]) =
@ -125,7 +125,7 @@ proc rpcGetProofsTrackStateChangesMain*() =
let let
blockHeader = waitFor client.eth_getBlockByNumber(blockId(START_BLOCK), false) blockHeader = waitFor client.eth_getBlockByNumber(blockId(START_BLOCK), false)
stateDB = newAccountStateDB(com.db, blockHeader.stateRoot.toHash256()) stateDB = LedgerRef.init(com.db, blockHeader.stateRoot.toHash256())
for i in START_BLOCK..END_BLOCK: for i in START_BLOCK..END_BLOCK:
let let

1
vendor/ethash vendored

@ -1 +0,0 @@
Subproject commit 953b8ed994d5f14569ca255cfe75bb4507025dcc

2
vendor/nim-bearssl vendored

@ -1 +1 @@
Subproject commit d81b37dc2011bf3a2bd93500489877c2ce8e6ac3 Subproject commit a806cbfab5fe8de49c76139f8705fff79daf99ee