# 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. {.push raises: [].} import std/tables, eth/eip1559, eth/common/[hashes, accounts, headers, addresses], ../db/[ledger, core_db], ../constants, ./chain_config # Annotation helpers {.pragma: noRaise, gcsafe, raises: [].} {.pragma: rlpRaise, gcsafe, raises: [RlpError].} {.pragma: catchRaise, gcsafe, raises: [CatchableError].} type GenesisAddAccountFn = proc( address: Address; nonce: AccountNonce; balance: UInt256; code: openArray[byte]) {.catchRaise.} GenesisSetStorageFn = proc( address: Address; slot: UInt256; val: UInt256) {.rlpRaise.} GenesisCommitFn = proc() {.noRaise.} GenesisRootHashFn = proc: Hash32 {.noRaise.} GenesisLedgerRef* = ref object ## Exportable ledger DB just for initialising Genesis. ## addAccount: GenesisAddAccountFn setStorage: GenesisSetStorageFn commit: GenesisCommitFn rootHash: GenesisRootHashFn # ------------------------------------------------------------------------------ # Private functions # ------------------------------------------------------------------------------ proc initAccountsLedgerRef( db: CoreDbRef; ): GenesisLedgerRef = ## Methods jump table let ac = LedgerRef.init(db, EMPTY_ROOT_HASH) GenesisLedgerRef( addAccount: proc( address: Address; nonce: AccountNonce; balance: UInt256; code: openArray[byte]; ) = ac.setNonce(address, nonce) ac.setBalance(address, balance) ac.setCode(address, @code), setStorage: proc( address: Address; slot: UInt256; val: UInt256; ) = ac.setStorage(address, slot, val), commit: proc() = ac.persist(), rootHash: proc(): Hash32 = ac.state()) # ------------------------------------------------------------------------------ # Public functions # ------------------------------------------------------------------------------ proc newStateDB*( db: CoreDbRef; ): GenesisLedgerRef = db.initAccountsLedgerRef() proc toGenesisHeader*( g: Genesis; sdb: GenesisLedgerRef; fork: HardFork; ): Header {.gcsafe, raises: [CatchableError].} = ## Initialise block chain DB accounts derived from the `genesis.alloc` table ## of the `db` descriptor argument. ## ## The function returns the `Genesis` block header. ## for address, account in g.alloc: sdb.addAccount(address, account.nonce, account.balance, account.code) for k, v in account.storage: sdb.setStorage(address, k, v) sdb.commit() result = Header( nonce: g.nonce, timestamp: g.timestamp, extraData: g.extraData, gasLimit: g.gasLimit, difficulty: g.difficulty, mixHash: g.mixHash, coinbase: g.coinbase, stateRoot: sdb.rootHash(), parentHash: GENESIS_PARENT_HASH, transactionsRoot: EMPTY_ROOT_HASH, receiptsRoot: EMPTY_ROOT_HASH, ommersHash: EMPTY_UNCLE_HASH ) if g.baseFeePerGas.isSome: result.baseFeePerGas = Opt.some(g.baseFeePerGas.get) elif fork >= London: result.baseFeePerGas = Opt.some(EIP1559_INITIAL_BASE_FEE) if g.gasLimit == 0: result.gasLimit = GENESIS_GAS_LIMIT if g.difficulty.isZero and fork <= London: result.difficulty = GENESIS_DIFFICULTY if fork >= Shanghai: result.withdrawalsRoot = Opt.some(EMPTY_ROOT_HASH) if fork >= Cancun: result.blobGasUsed = Opt.some g.blobGasUsed.get(0'u64) result.excessBlobGas = Opt.some g.excessBlobGas.get(0'u64) result.parentBeaconBlockRoot = Opt.some g.parentBeaconBlockRoot.get(default(Hash32)) proc toGenesisHeader*( genesis: Genesis; fork: HardFork; db = CoreDbRef(nil)): Header {.gcsafe, raises: [CatchableError].} = ## Generate the genesis block header from the `genesis` and `config` ## argument value. let db = if db.isNil: AristoDbMemory.newCoreDbRef() else: db sdb = db.newStateDB() toGenesisHeader(genesis, sdb, fork) proc toGenesisHeader*( params: NetworkParams; db = CoreDbRef(nil) ): Header {.raises: [CatchableError].} = ## Generate the genesis block header from the `genesis` and `config` ## argument value. let map = toForkTransitionTable(params.config) let fork = map.toHardFork(forkDeterminationInfo(0.BlockNumber, params.genesis.timestamp)) toGenesisHeader(params.genesis, fork, db) # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------