mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-29 13:35:38 +00:00
43d93bcdab
The reverse slot hash mechanism causes quite a bit of database traffic but is broadly not useful except for iterating the storage of an account, something that a validator never does (it's used by the tracers). This flag adds one more thing that is not stored in the database, to be explored more comprehensively when designing full, validator and archive modes with different pruning options in the future. `ldb` says this is 60gb of data (!): ``` ldb --db=. --ignore_unknown_options --column_family=KvtGen approxsize --hex --from=0x05 --to=0x05ffffffffffffffffffffffffffffffffffffffffffffff 66488353954 ```
141 lines
4.5 KiB
Nim
141 lines
4.5 KiB
Nim
# 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
|
|
../../../nimbus/[
|
|
utils/utils,
|
|
common/common,
|
|
constants,
|
|
db/ledger,
|
|
transaction,
|
|
evm/state,
|
|
evm/types,
|
|
core/dao,
|
|
core/validate,
|
|
core/chain/chain_desc,
|
|
core/executor/calculate_reward,
|
|
core/executor/process_transaction,
|
|
core/executor/process_block
|
|
],
|
|
chronicles,
|
|
results
|
|
|
|
{.push raises: [].}
|
|
|
|
proc processBlock(
|
|
vmState: BaseVMState; ## Parent environment of header/body block
|
|
blk: EthBlock; ## Header/body block to add to the blockchain
|
|
): Result[void, string] =
|
|
## Generalised function to processes `(header,body)` pair for any network,
|
|
## regardless of PoA or not.
|
|
##
|
|
## Rather than calculating the PoA state change here, it is done with the
|
|
## verification in the `chain/persist_blocks.persistBlocks()` method. So
|
|
## the `poa` descriptor is currently unused and only provided for later
|
|
## implementations (but can be savely removed, as well.)
|
|
## variant of `processBlock()` where the `header` argument is explicitely set.
|
|
template header: BlockHeader = blk.header
|
|
var dbTx = vmState.com.db.ctx.newTransaction()
|
|
defer: dbTx.dispose()
|
|
|
|
let com = vmState.com
|
|
if com.daoForkSupport and
|
|
com.daoForkBlock.get == header.number:
|
|
vmState.mutateStateDB:
|
|
db.applyDAOHardFork()
|
|
|
|
if header.parentBeaconBlockRoot.isSome:
|
|
? vmState.processBeaconBlockRoot(header.parentBeaconBlockRoot.get)
|
|
|
|
? processTransactions(vmState, header, blk.transactions)
|
|
|
|
if com.isShanghaiOrLater(header.timestamp):
|
|
for withdrawal in blk.withdrawals.get:
|
|
vmState.stateDB.addBalance(withdrawal.address, withdrawal.weiAmount)
|
|
|
|
if header.ommersHash != EMPTY_UNCLE_HASH:
|
|
discard com.db.persistUncles(blk.uncles)
|
|
|
|
# EIP-3675: no reward for miner in POA/POS
|
|
if com.consensus == ConsensusType.POW:
|
|
vmState.calculateReward(header, blk.uncles)
|
|
|
|
vmState.mutateStateDB:
|
|
let clearEmptyAccount = com.isSpuriousOrLater(header.number)
|
|
db.persist(clearEmptyAccount)
|
|
|
|
dbTx.commit()
|
|
|
|
ok()
|
|
|
|
proc getVmState(c: ChainRef, header: BlockHeader):
|
|
Result[BaseVMState, void] =
|
|
if c.vmState.isNil.not:
|
|
return ok(c.vmState)
|
|
|
|
let vmState = BaseVMState()
|
|
if not vmState.init(header, c.com, storeSlotHash = storeSlotHash):
|
|
debug "Cannot initialise VmState",
|
|
number = header.number
|
|
return err()
|
|
|
|
return ok(vmState)
|
|
|
|
# A stripped down version of persistBlocks without validation
|
|
# intended to accepts invalid block
|
|
proc setBlock*(c: ChainRef; blk: EthBlock): Result[void, string] =
|
|
template header: BlockHeader = blk.header
|
|
let dbTx = c.db.ctx.newTransaction()
|
|
defer: dbTx.dispose()
|
|
|
|
c.com.hardForkTransition(header)
|
|
|
|
# Needed for figuring out whether KVT cleanup is due (see at the end)
|
|
let
|
|
vmState = c.getVmState(header).valueOr:
|
|
return err("no vmstate")
|
|
stateRootChpt = vmState.parent.stateRoot # Check point
|
|
? vmState.processBlock(blk)
|
|
|
|
if not c.db.persistHeader(
|
|
header, c.com.consensus == ConsensusType.POS, c.com.startOfHistory):
|
|
return err("Could not persist header")
|
|
|
|
try:
|
|
c.db.persistTransactions(header.number, header.txRoot, blk.transactions)
|
|
c.db.persistReceipts(header.receiptsRoot, vmState.receipts)
|
|
|
|
if blk.withdrawals.isSome:
|
|
c.db.persistWithdrawals(header.withdrawalsRoot, blk.withdrawals.get)
|
|
except CatchableError as exc:
|
|
return err(exc.msg)
|
|
|
|
# update currentBlock *after* we persist it
|
|
# so the rpc return consistent result
|
|
# between eth_blockNumber and eth_syncing
|
|
c.com.syncCurrent = header.number
|
|
|
|
dbTx.commit()
|
|
|
|
# The `c.db.persistent()` call is ignored by the legacy DB which
|
|
# automatically saves persistently when reaching the zero level transaction.
|
|
#
|
|
# For the `Aristo` database, this code position is only reached if the
|
|
# the parent state of the first block (as registered in `headers[0]`) was
|
|
# the canonical state before updating. So this state will be saved with
|
|
# `persistent()` together with the respective block number.
|
|
c.db.persistent(header.number - 1)
|
|
|
|
ok()
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|