nimbus-eth1/nimbus/chain_config.nim

364 lines
13 KiB
Nim

# Nimbus
# Copyright (c) 2021 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/[tables, strutils, options, times],
eth/[common, rlp, p2p], stint, stew/[byteutils],
nimcrypto/hash,
json_serialization, chronicles,
json_serialization/std/options as jsoptions,
json_serialization/std/tables as jstable,
json_serialization/lexer,
"."/[forks, genesis_alloc]
type
CliqueOptions = object
epoch : Option[int]
period: Option[int]
ChainOptions = 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]
clique : CliqueOptions
ChainConfig* = object
chainId* : ChainId
homesteadBlock* : BlockNumber
daoForkBlock* : BlockNumber
daoForkSupport* : bool
# EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
eip150Block* : BlockNumber
eip150Hash* : Hash256
eip155Block* : BlockNumber
eip158Block* : BlockNumber
byzantiumBlock* : BlockNumber
constantinopleBlock*: BlockNumber
petersburgBlock* : BlockNumber
istanbulBlock* : BlockNumber
muirGlacierBlock* : BlockNumber
berlinBlock* : BlockNumber
londonBlock* : BlockNumber
poaEngine* : bool
cliquePeriod* : int
cliqueEpoch* : int
Genesis* = object
nonce* : BlockNonce
timestamp* : EthTime
extraData* : seq[byte]
gasLimit* : GasInt
difficulty* : DifficultyInt
mixHash* : Hash256
coinbase* : EthAddress
alloc* : GenesisAlloc
baseFeePerGas*: Option[UInt256]
GenesisAlloc* = Table[EthAddress, GenesisAccount]
GenesisAccount* = object
code* : seq[byte]
storage*: Table[UInt256, UInt256]
balance*: UInt256
nonce* : AccountNonce
NetworkParams* = object
config* : ChainConfig
genesis*: Genesis
AddressBalance = object
address {.rlpCustomSerialization.}: EthAddress
account {.rlpCustomSerialization.}: GenesisAccount
CustomChain = object
config : ChainOptions
genesis: Genesis
const
CustomNet* = 0.NetworkId
# these are public network id
MainNet* = 1.NetworkId
# No longer used: MordenNet = 2
RopstenNet* = 3.NetworkId
RinkebyNet* = 4.NetworkId
GoerliNet* = 5.NetworkId
KovanNet* = 42.NetworkId
proc read(rlp: var Rlp, x: var AddressBalance, _: type EthAddress): EthAddress {.inline.} =
let val = rlp.read(UInt256).toByteArrayBE()
result[0 .. ^1] = val.toOpenArray(12, val.high)
proc read(rlp: var Rlp, x: var AddressBalance, _: type GenesisAccount): GenesisAccount {.inline.} =
GenesisAccount(balance: rlp.read(UInt256))
func decodePrealloc*(data: seq[byte]): GenesisAlloc =
for tup in rlp.decode(data, seq[AddressBalance]):
result[tup.address] = tup.account
proc readValue(reader: var JsonReader, value: var BlockNumber) =
let tok = reader.lexer.tok
if tok == tkInt:
value = toBlockNumber(reader.lexer.absintVal)
reader.lexer.next()
elif tok == tkString:
value = UInt256.fromHex(reader.lexer.strVal)
reader.lexer.next()
else:
reader.raiseUnexpectedValue("expect int or hex string")
proc readValue(reader: var JsonReader, value: var ChainId) =
value = reader.readValue(int).ChainId
proc readValue(reader: var JsonReader, value: var Hash256) =
value = Hash256.fromHex(reader.readValue(string))
proc readValue(reader: var JsonReader, value: var BlockNonce) =
value = fromHex[uint64](reader.readValue(string)).toBlockNonce
proc readValue(reader: var JsonReader, value: var EthTime) =
value = fromHex[int64](reader.readValue(string)).fromUnix
proc readValue(reader: var JsonReader, value: var seq[byte]) =
value = hexToSeqByte(reader.readValue(string))
proc readValue(reader: var JsonReader, value: var GasInt) =
value = fromHex[GasInt](reader.readValue(string))
proc readValue(reader: var JsonReader, value: var EthAddress) =
value = parseAddress(reader.readValue(string))
proc readValue(reader: var JsonReader, value: var AccountNonce) =
value = fromHex[uint64](reader.readValue(string))
template to(a: string, b: type EthAddress): EthAddress =
# json_serialization decode table stuff
parseAddress(a)
template to(a: string, b: type UInt256): UInt256 =
# json_serialization decode table stuff
UInt256.fromHex(a)
proc loadNetworkParams*(fileName: string, cg: var NetworkParams):
bool {.raises: [Defect].} =
var cc: CustomChain
try:
cc = Json.loadFile(fileName, CustomChain, allowUnknownFields = true)
except IOError as e:
error "Network params I/O error", fileName, msg=e.msg
return false
except JsonReaderError as e:
error "Invalid network params file format", fileName, msg=e.formatMsg("")
return false
except:
var msg = getCurrentExceptionMsg()
error "Error loading network params file", fileName, msg
return false
cg.genesis = cc.genesis
cg.config.chainId = cc.config.chainId
cg.config.daoForkSupport = cc.config.daoForkSupport
cg.config.eip150Hash = cc.config.eip150Hash
cg.config.poaEngine = false
if cc.config.clique.period.isSome or
cc.config.clique.epoch.isSome:
cg.config.poaEngine = true
if cc.config.clique.period.isSome:
cg.config.cliquePeriod = cc.config.clique.period.get()
if cc.config.clique.epoch.isSome:
cg.config.cliqueEpoch = cc.config.clique.epoch.get()
template validateFork(forkName: untyped, nextBlock: BlockNumber) =
let fork = astToStr(forkName)
if cc.config.forkName.isSome:
cg.config.forkName = cc.config.forkName.get()
else:
cg.config.forkName = nextBlock
if cg.config.forkName > nextBlock:
error "Forks can't be assigned out of order", fork=fork
return false
validateFork(londonBlock, high(BlockNumber).toBlockNumber)
validateFork(berlinBlock, cg.config.londonBlock)
validateFork(muirGlacierBlock, cg.config.berlinBlock)
validateFork(istanbulBlock, cg.config.muirGlacierBlock)
validateFork(petersburgBlock, cg.config.istanbulBlock)
validateFork(constantinopleBlock, cg.config.petersburgBlock)
validateFork(byzantiumBlock, cg.config.constantinopleBlock)
validateFork(eip158Block, cg.config.byzantiumBlock)
validateFork(eip155Block, cg.config.eip158Block)
validateFork(eip150Block, cg.config.eip155Block)
validateFork(daoForkBlock, cg.config.eip150Block)
validateFork(homesteadBlock, cg.config.daoForkBlock)
return true
proc parseGenesisAlloc*(data: string, ga: var GenesisAlloc): bool =
try:
ga = Json.decode(data, GenesisAlloc, allowUnknownFields = true)
except JsonReaderError as e:
error "Invalid genesis config file format", msg=e.formatMsg("")
return false
return true
proc toFork*(c: ChainConfig, number: BlockNumber): Fork =
if number >= c.londonBlock: FkLondon
elif number >= c.berlinBlock: FkBerlin
elif number >= c.istanbulBlock: FkIstanbul
elif number >= c.petersburgBlock: FkPetersburg
elif number >= c.constantinopleBlock: FkConstantinople
elif number >= c.byzantiumBlock: FkByzantium
elif number >= c.eip158Block: FkSpurious
elif number >= c.eip150Block: FkTangerine
elif number >= c.homesteadBlock: FkHomestead
else: FkFrontier
proc chainConfigForNetwork(id: NetworkId): ChainConfig =
# For some public networks, NetworkId and ChainId value are identical
# but that is not always the case
result = case id
of MainNet:
ChainConfig(
poaEngine: false,
chainId: MainNet.ChainId,
homesteadBlock: 1_150_000.toBlockNumber, # 14/03/2016 20:49:53
daoForkBlock: 1_920_000.toBlockNumber,
daoForkSupport: true,
eip150Block: 2_463_000.toBlockNumber, # 18/10/2016 17:19:31
eip150Hash: toDigest("2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
eip155Block: 2_675_000.toBlockNumber, # 22/11/2016 18:15:44
eip158Block: 2_675_000.toBlockNumber,
byzantiumBlock: 4_370_000.toBlockNumber, # 16/10/2017 09:22:11
constantinopleBlock: 7_280_000.toBlockNumber, # Never Occured in MainNet
petersburgBlock:7_280_000.toBlockNumber, # 28/02/2019 07:52:04
istanbulBlock: 9_069_000.toBlockNumber, # 08/12/2019 12:25:09
muirGlacierBlock: 9_200_000.toBlockNumber, # 02/01/2020 08:30:49
berlinBlock: 12_244_000.toBlockNumber, # 15/04/2021 10:07:03
londonBlock: 12_965_000.toBlockNumber, # 05/08/2021 12:33:42
)
of RopstenNet:
ChainConfig(
poaEngine: false,
chainId: RopstenNet.ChainId,
homesteadBlock: 0.toBlockNumber,
daoForkSupport: false,
eip150Block: 0.toBlockNumber,
eip150Hash: toDigest("41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
eip155Block: 10.toBlockNumber,
eip158Block: 10.toBlockNumber,
byzantiumBlock: 1_700_000.toBlockNumber,
constantinopleBlock: 4_230_000.toBlockNumber,
petersburgBlock:4_939_394.toBlockNumber,
istanbulBlock: 6_485_846.toBlockNumber,
muirGlacierBlock: 7_117_117.toBlockNumber,
berlinBlock: 9_812_189.toBlockNumber,
londonBlock: 10_499_401.toBlockNumber # June 24, 2021
)
of RinkebyNet:
ChainConfig(
poaEngine: true,
chainId: RinkebyNet.ChainId,
homesteadBlock: 1.toBlockNumber,
daoForkSupport: false,
eip150Block: 2.toBlockNumber,
eip150Hash: toDigest("9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"),
eip155Block: 3.toBlockNumber,
eip158Block: 3.toBlockNumber,
byzantiumBlock: 1_035_301.toBlockNumber,
constantinopleBlock: 3_660_663.toBlockNumber,
petersburgBlock:4_321_234.toBlockNumber,
istanbulBlock: 5_435_345.toBlockNumber,
muirGlacierBlock: 8_290_928.toBlockNumber, # never occured in rinkeby network
berlinBlock: 8_290_928.toBlockNumber,
londonBlock: 8_897_988.toBlockNumber # July 7, 2021
)
of GoerliNet:
ChainConfig(
poaEngine: true,
chainId: GoerliNet.ChainId,
homesteadBlock: 0.toBlockNumber,
daoForkSupport: false,
eip150Block: 0.toBlockNumber,
eip150Hash: toDigest("0000000000000000000000000000000000000000000000000000000000000000"),
eip155Block: 0.toBlockNumber,
eip158Block: 0.toBlockNumber,
byzantiumBlock: 0.toBlockNumber,
constantinopleBlock: 0.toBlockNumber,
petersburgBlock: 0.toBlockNumber,
istanbulBlock: 1_561_651.toBlockNumber,
muirGlacierBlock: 4_460_644.toBlockNumber, # never occured in goerli network
berlinBlock: 4_460_644.toBlockNumber,
londonBlock: 5_062_605.toBlockNumber # June 30, 2021
)
else:
ChainConfig()
proc genesisBlockForNetwork(id: NetworkId): Genesis =
result = case id
of MainNet:
Genesis(
nonce: 66.toBlockNonce,
extraData: hexToSeqByte("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
gasLimit: 5000,
difficulty: 17179869184.u256,
alloc: decodePrealloc(mainnetAllocData)
)
of RopstenNet:
Genesis(
nonce: 66.toBlockNonce,
extraData: hexToSeqByte("0x3535353535353535353535353535353535353535353535353535353535353535"),
gasLimit: 16777216,
difficulty: 1048576.u256,
alloc: decodePrealloc(testnetAllocData)
)
of RinkebyNet:
Genesis(
nonce: 0.toBlockNonce,
timestamp: initTime(0x58ee40ba, 0),
extraData: hexToSeqByte("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
gasLimit: 4700000,
difficulty: 1.u256,
alloc: decodePrealloc(rinkebyAllocData)
)
of GoerliNet:
Genesis(
nonce: 0.toBlockNonce,
timestamp: initTime(0x5c51a607, 0),
extraData: hexToSeqByte("0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
gasLimit: 0xa00000,
difficulty: 1.u256,
alloc: decodePrealloc(goerliAllocData)
)
else:
Genesis()
proc networkParams*(id: NetworkId): NetworkParams =
result.genesis = genesisBlockForNetwork(id)
result.config = chainConfigForNetwork(id)