-
Notifications
You must be signed in to change notification settings - Fork 107
/
node.nim
149 lines (122 loc) · 5.02 KB
/
node.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# Nimbus
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http:https://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http:https://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,
vm_state,
vm_types,
core/dao,
core/validate,
core/chain/chain_desc,
core/executor/calculate_reward,
core/executor/process_transaction,
core/executor/process_block
],
chronicles,
stint,
results
{.push raises: [].}
proc processBlock(
vmState: BaseVMState; ## Parent environment of header/body block
header: BlockHeader; ## Header/body block to add to the blockchain
body: BlockBody): ValidationResult
{.gcsafe, raises: [CatchableError].} =
## 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.
var dbTx = vmState.com.db.beginTransaction()
defer: dbTx.dispose()
if vmState.com.daoForkSupport and
vmState.com.daoForkBlock.get == header.blockNumber:
vmState.mutateStateDB:
db.applyDAOHardFork()
if header.parentBeaconBlockRoot.isSome:
let r = vmState.processBeaconBlockRoot(header.parentBeaconBlockRoot.get)
if r.isErr:
error("error in processing beaconRoot", err=r.error)
let r = processTransactions(vmState, header, body.transactions)
if r.isErr:
error("error in processing transactions", err=r.error)
if vmState.determineFork >= FkShanghai:
for withdrawal in body.withdrawals.get:
vmState.stateDB.addBalance(withdrawal.address, withdrawal.weiAmount)
if header.ommersHash != EMPTY_UNCLE_HASH:
discard vmState.com.db.persistUncles(body.uncles)
# EIP-3675: no reward for miner in POA/POS
if vmState.com.consensus == ConsensusType.POW:
vmState.calculateReward(header, body)
vmState.mutateStateDB:
let clearEmptyAccount = vmState.determineFork >= FkSpurious
db.persist(clearEmptyAccount)
# `applyDeletes = false`
# If the trie pruning activated, each of the block will have its own state
# trie keep intact, rather than destroyed by trie pruning. But the current
# block will still get a pruned trie. If trie pruning deactivated,
# `applyDeletes` have no effects.
dbTx.commit(applyDeletes = false)
ValidationResult.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):
debug "Cannot initialise VmState",
number = header.blockNumber
return err()
return ok(vmState)
# A stripped down version of persistBlocks without validation
# intended to accepts invalid block
proc setBlock*(c: ChainRef; header: BlockHeader;
body: BlockBody): ValidationResult
{.inline, raises: [CatchableError].} =
let dbTx = c.db.beginTransaction()
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 ValidationResult.Error
stateRootChpt = vmState.parent.stateRoot # Check point
validationResult = vmState.processBlock(header, body)
if validationResult != ValidationResult.OK:
return validationResult
discard c.db.persistHeaderToDb(
header, c.com.consensus == ConsensusType.POS, c.com.startOfHistory)
discard c.db.persistTransactions(header.blockNumber, body.transactions)
discard c.db.persistReceipts(vmState.receipts)
if body.withdrawals.isSome:
discard c.db.persistWithdrawals(body.withdrawals.get)
# update currentBlock *after* we persist it
# so the rpc return consistent result
# between eth_blockNumber and eth_syncing
c.com.syncCurrent = header.blockNumber
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.blockNumber - 1)
ValidationResult.OK
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------