nimbus-eth1/nimbus/chain_config.nim

191 lines
6.5 KiB
Nim
Raw Normal View History

# 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], stint, stew/[byteutils],
nimcrypto/hash,
json_serialization, chronicles,
json_serialization/std/options as jsoptions,
json_serialization/std/tables as jstable,
json_serialization/lexer
type
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]
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
Genesis* = object
nonce* : BlockNonce
timestamp* : EthTime
extraData* : seq[byte]
gasLimit* : GasInt
difficulty* : DifficultyInt
mixHash* : Hash256
coinbase* : EthAddress
alloc* : GenesisAlloc
GenesisAlloc* = Table[EthAddress, GenesisAccount]
GenesisAccount* = object
code* : seq[byte]
storage*: Table[UInt256, UInt256]
balance*: UInt256
nonce* : AccountNonce
CustomGenesis* = object
config* : ChainConfig
genesis*: Genesis
AddressBalance = object
address {.rlpCustomSerialization.}: EthAddress
account {.rlpCustomSerialization.}: GenesisAccount
CustomChain = object
config : ChainOptions
genesis: Genesis
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 loadCustomGenesis*(fileName: string, cg: var CustomGenesis): bool =
var cc: CustomChain
try:
cc = Json.loadFile(fileName, CustomChain, allowUnknownFields = true)
except IOError as e:
error "Genesis config file error", fileName, msg=e.msg
return false
except JsonReaderError as e:
error "Invalid genesis config file format", fileName, msg=e.formatMsg("")
return false
except:
var msg = getCurrentExceptionMsg()
error "Error loading genesis block config 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
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(berlinBlock, high(BlockNumber).toBlockNumber)
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