311 lines
8.5 KiB
Nim
311 lines
8.5 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2022 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
# at your option.
|
|
# This file may not be copied, modified, or distributed except according to
|
|
# those terms.
|
|
|
|
import
|
|
std/options,
|
|
eth/common,
|
|
json_serialization,
|
|
../utils/utils,
|
|
./evmforks
|
|
|
|
type
|
|
ConsensusType* {.pure.} = enum
|
|
# Proof of Work
|
|
# algorithm: Ethash
|
|
POW
|
|
|
|
# Proof of Authority
|
|
# algorithm: Clique
|
|
POA
|
|
|
|
# Proof of Stake
|
|
# algorithm: Casper
|
|
POS
|
|
|
|
HardFork* = enum
|
|
Frontier
|
|
Homestead
|
|
DAOFork
|
|
Tangerine # a.k.a. EIP150
|
|
Spurious # a.k.a. EIP158
|
|
Byzantium
|
|
Constantinople
|
|
Petersburg # a.k.a. ConstantinopleFix
|
|
Istanbul
|
|
MuirGlacier
|
|
Berlin
|
|
London
|
|
ArrowGlacier
|
|
GrayGlacier
|
|
MergeFork # a.k.a. Paris
|
|
Shanghai
|
|
Cancun
|
|
|
|
CliqueOptions* = object
|
|
epoch* : Option[int]
|
|
period*: Option[int]
|
|
|
|
# if you add more fork block
|
|
# please update forkBlockField constant too
|
|
ChainConfig* = ref object
|
|
chainId* : ChainId
|
|
homesteadBlock* : Option[BlockNumber]
|
|
daoForkBlock* : Option[BlockNumber]
|
|
daoForkSupport* : bool
|
|
eip150Block* : Option[BlockNumber]
|
|
eip150Hash* : Hash256
|
|
eip155Block* : Option[BlockNumber]
|
|
eip158Block* : Option[BlockNumber]
|
|
byzantiumBlock* : Option[BlockNumber]
|
|
constantinopleBlock*: Option[BlockNumber]
|
|
petersburgBlock* : Option[BlockNumber]
|
|
istanbulBlock* : Option[BlockNumber]
|
|
muirGlacierBlock* : Option[BlockNumber]
|
|
berlinBlock* : Option[BlockNumber]
|
|
londonBlock* : Option[BlockNumber]
|
|
arrowGlacierBlock* : Option[BlockNumber]
|
|
grayGlacierBlock* : Option[BlockNumber]
|
|
mergeForkBlock* : Option[BlockNumber]
|
|
shanghaiBlock* : Option[BlockNumber]
|
|
cancunBlock* : Option[BlockNumber]
|
|
|
|
clique* : CliqueOptions
|
|
terminalTotalDifficulty*: Option[UInt256]
|
|
consensusType*
|
|
{.dontSerialize.} : ConsensusType
|
|
|
|
ForkToBlockNumber* = array[HardFork, Option[BlockNumber]]
|
|
ForkOptional* = object
|
|
name*: string
|
|
number*: Option[BlockNumber]
|
|
|
|
const
|
|
# this table is used for generate
|
|
# code at compile time to check
|
|
# the order of blok number in ChainConfig
|
|
forkBlockField* = [
|
|
"homesteadBlock",
|
|
"daoForkBlock",
|
|
"eip150Block",
|
|
"eip155Block",
|
|
"eip158Block",
|
|
"byzantiumBlock",
|
|
"constantinopleBlock",
|
|
"petersburgBlock",
|
|
"istanbulBlock",
|
|
"muirGlacierBlock",
|
|
"berlinBlock",
|
|
"londonBlock",
|
|
"arrowGlacierBlock",
|
|
"grayGlacierBlock",
|
|
"mergeForkBlock",
|
|
"shanghaiBlock",
|
|
"cancunBlock",
|
|
]
|
|
|
|
# this table is used to generate
|
|
# code to build fork to block number
|
|
# array
|
|
forkBlockNumber* = [
|
|
Homestead: "homesteadBlock",
|
|
DAOFork: "daoForkBlock",
|
|
Tangerine: "eip150Block",
|
|
Spurious: "eip158Block",
|
|
Byzantium: "byzantiumBlock",
|
|
Constantinople: "constantinopleBlock",
|
|
Petersburg: "petersburgBlock",
|
|
Istanbul: "istanbulBlock",
|
|
MuirGlacier: "muirGlacierBlock",
|
|
Berlin: "berlinBlock",
|
|
London: "londonBlock",
|
|
ArrowGlacier: "arrowGlacierBlock",
|
|
GrayGlacier: "grayGlacierBlock",
|
|
MergeFork: "mergeForkBlock",
|
|
Shanghai: "shanghaiBlock",
|
|
Cancun: "cancunBlock",
|
|
]
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Map HardFork to EVM/EVMC Fork
|
|
# ------------------------------------------------------------------------------
|
|
|
|
const
|
|
ToEVMFork*: array[HardFork, EVMFork] = [
|
|
FkFrontier, # Frontier
|
|
FkHomestead, # Homestead
|
|
FkHomestead, # DAOFork
|
|
FkTangerine, # Tangerine
|
|
FkSpurious, # Spurious
|
|
FkByzantium, # Byzantium
|
|
FkConstantinople, # Constantinople
|
|
FkPetersburg, # Petersburg
|
|
FkIstanbul, # Istanbul
|
|
FkIstanbul, # MuirGlacier
|
|
FkBerlin, # Berlin
|
|
FkLondon, # London
|
|
FkLondon, # ArrowGlacier
|
|
FkLondon, # GrayGlacier
|
|
FkParis, # MergeFork
|
|
FkShanghai, # Shanghai
|
|
FkCancun, # Cancun
|
|
]
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Block reward helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
func eth(n: int): UInt256 {.compileTime.} =
|
|
n.u256 * pow(10.u256, 18)
|
|
|
|
const
|
|
eth5 = 5.eth
|
|
eth3 = 3.eth
|
|
eth2 = 2.eth
|
|
eth0 = 0.u256
|
|
|
|
BlockRewards*: array[HardFork, UInt256] = [
|
|
eth5, # Frontier
|
|
eth5, # Homestead
|
|
eth5, # DAOFork
|
|
eth5, # Tangerine
|
|
eth5, # Spurious
|
|
eth3, # Byzantium
|
|
eth2, # Constantinople
|
|
eth2, # Petersburg
|
|
eth2, # Istanbul
|
|
eth2, # MuirGlacier
|
|
eth2, # Berlin
|
|
eth2, # London
|
|
eth2, # ArrowGlacier
|
|
eth2, # GrayGlacier
|
|
eth0, # MergeFork
|
|
eth0, # Shanghai
|
|
eth0, # Cancun
|
|
]
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Fork ID helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
func toNextFork(n: Option[BlockNumber]): uint64 =
|
|
if n.isSome:
|
|
n.get.truncate(uint64)
|
|
else:
|
|
0'u64
|
|
|
|
func getNextFork(c: ChainConfig, fork: HardFork): uint64 =
|
|
let next: array[HardFork, uint64] = [
|
|
0'u64,
|
|
toNextFork(c.homesteadBlock),
|
|
toNextFork(c.daoForkBlock),
|
|
toNextFork(c.eip150Block),
|
|
toNextFork(c.eip158Block),
|
|
toNextFork(c.byzantiumBlock),
|
|
toNextFork(c.constantinopleBlock),
|
|
toNextFork(c.petersburgBlock),
|
|
toNextFork(c.istanbulBlock),
|
|
toNextFork(c.muirGlacierBlock),
|
|
toNextFork(c.berlinBlock),
|
|
toNextFork(c.londonBlock),
|
|
toNextFork(c.arrowGlacierBlock),
|
|
toNextFork(c.grayGlacierBlock),
|
|
toNextFork(c.mergeForkBlock),
|
|
toNextFork(c.shanghaiBlock),
|
|
toNextFork(c.cancunBlock),
|
|
]
|
|
|
|
if fork == high(HardFork):
|
|
result = 0
|
|
return
|
|
|
|
result = next[fork]
|
|
for x in fork..high(HardFork):
|
|
if result != next[x]:
|
|
result = next[x]
|
|
break
|
|
|
|
func calculateForkId(c: ChainConfig, fork: HardFork,
|
|
prevCRC: uint32, prevFork: uint64): ForkID =
|
|
result.nextFork = c.getNextFork(fork)
|
|
|
|
if result.nextFork != prevFork:
|
|
result.crc = crc32(prevCRC, toBytesBE(prevFork))
|
|
else:
|
|
result.crc = prevCRC
|
|
|
|
func calculateForkIds*(c: ChainConfig,
|
|
genesisCRC: uint32): array[HardFork, ForkID] =
|
|
var prevCRC = genesisCRC
|
|
var prevFork = c.getNextFork(Frontier)
|
|
|
|
for fork in HardFork:
|
|
result[fork] = calculateForkId(c, fork, prevCRC, prevFork)
|
|
prevFork = result[fork].nextFork
|
|
prevCRC = result[fork].crc
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# BlockNumber + TD comparator
|
|
# ------------------------------------------------------------------------------
|
|
|
|
type
|
|
BlockToForkFunc* = proc(data, number, td: UInt256): bool
|
|
{.gcsafe, noSideEffect, nimcall, raises: [Defect, CatchableError].}
|
|
|
|
BlockToFork* = object
|
|
# `data` can be blockNumber or TTD
|
|
data* : UInt256
|
|
toFork*: BlockToForkFunc
|
|
|
|
BlockToForks* = array[HardFork, BlockToFork]
|
|
|
|
func forkTrue(data, number, td: UInt256): bool
|
|
{.gcsafe, nimcall, raises: [Defect, CatchableError].} =
|
|
# frontier always return true
|
|
true
|
|
|
|
func forkFalse(data, number, td: UInt256): bool
|
|
{.gcsafe, nimcall, raises: [Defect, CatchableError].} =
|
|
# forkBlock.isNone always return false
|
|
false
|
|
|
|
func forkMaybe(data, number, td: UInt256): bool
|
|
{.gcsafe, nimcall, raises: [Defect, CatchableError].} =
|
|
# data is a blockNumber
|
|
number >= data
|
|
|
|
func mergeMaybe(data, number, td: UInt256): bool
|
|
{.gcsafe, nimcall, raises: [Defect, CatchableError].} =
|
|
# data is a TTD
|
|
td >= data
|
|
|
|
proc blockToForks*(conf: ChainConfig, map: ForkToBlockNumber): BlockToForks =
|
|
# between Frontier and latest HardFork
|
|
# can be a match or not
|
|
for fork, number in map:
|
|
if number.isSome:
|
|
result[fork].data = number.get()
|
|
result[fork].toFork = forkMaybe
|
|
else:
|
|
result[fork].toFork = forkFalse
|
|
|
|
# Frontier always return true
|
|
result[Frontier].toFork = forkTrue
|
|
|
|
# special case for MergeFork
|
|
# if MergeForkBlock.isSome, it takes precedence over TTD
|
|
# if MergeForkBlock.isNone, compare TD with TTD
|
|
if map[MergeFork].isNone and
|
|
conf.terminalTotalDifficulty.isSome:
|
|
result[MergeFork].data = conf.terminalTotalDifficulty.get()
|
|
result[MergeFork].toFork = mergeMaybe
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|