fixes crappy custom genesis and chain config parser

instead of using stdlib/json, now we switch to json_serialization
the result is much tidier code and more robust when parsing
optional fields.

fixes #635
This commit is contained in:
jangko 2021-05-13 16:01:58 +07:00
parent 6966324f3b
commit f2491e6307
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
14 changed files with 368 additions and 316 deletions

195
nimbus/chain_config.nim Normal file
View File

@ -0,0 +1,195 @@
# 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
# beware that although in some cases
# chainId have identical value to networkId
# they are separate entity
ChainId* = distinct uint
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

View File

@ -11,8 +11,9 @@ import
parseopt, strutils, macros, os, times, json, tables, stew/[byteutils],
chronos, eth/[keys, common, p2p, net/nat], chronicles, nimcrypto/hash,
eth/p2p/bootnodes, eth/p2p/rlpx_protocols/whisper_protocol,
./db/select_backend, eth/keys,
./vm_types2
./db/select_backend, eth/keys, ./chain_config
from ./vm_types2 import Fork
const
NimbusName* = "Nimbus"
@ -130,31 +131,6 @@ type
keystore*: JsonNode
unlocked*: bool
# beware that although in some cases
# chainId have identical value to networkId
# they are separate entity
ChainId* = distinct uint
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
NimbusConfiguration* = ref object
## Main Nimbus configuration object
dataDir*: string
@ -165,37 +141,13 @@ type
net*: NetConfiguration ## Network configuration
debug*: DebugConfiguration ## Debug configuration
shh*: WhisperConfig ## Whisper configuration
customGenesis*: CustomGenesisConfig ## Custom Genesis Configuration
customGenesis*: CustomGenesis ## Custom Genesis Configuration
# You should only create one instance of the RNG per application / library
# Ref is used so that it can be shared between components
rng*: ref BrHmacDrbgContext
accounts*: Table[EthAddress, NimbusAccount]
importFile*: string
CustomGenesisConfig* = object
chainId*: ChainId
homesteadBlock*: BlockNumber
daoForkBlock*: BlockNumber
daoForkSupport*: bool
eip150Block*: BlockNumber
eip150Hash*: Hash256
eip155Block*: BlockNumber
eip158Block*: BlockNumber
byzantiumBlock*: BlockNumber
constantinopleBlock*: BlockNumber
petersburgBlock*: BlockNumber
istanbulBlock*: BlockNumber
muirGlacierBlock*: BlockNumber
berlinBlock*: BlockNumber
nonce*: BlockNonce
extraData*: seq[byte]
gasLimit*: int64
difficulty*: UInt256
prealloc*: JsonNode
mixHash*: Hash256
coinBase*: EthAddress
timestamp*: EthTime
const
defaultRpcApi = {RpcFlags.Eth, RpcFlags.Shh}
defaultProtocols = {ProtocolFlags.Eth, ProtocolFlags.Shh}
@ -220,26 +172,6 @@ proc toFork*(c: ChainConfig, number: BlockNumber): Fork =
elif number >= c.homesteadBlock: FkHomestead
else: FkFrontier
proc privateChainConfig*(): ChainConfig =
let config = getConfiguration()
result = ChainConfig(
chainId: config.customGenesis.chainId,
homesteadBlock: config.customGenesis.homesteadBlock,
daoForkSupport: config.customGenesis.daoForkSupport,
daoForkBlock: config.customGenesis.daoForkBlock,
eip150Block: config.customGenesis.eip150Block,
eip150Hash: config.customGenesis.eip150Hash,
eip155Block: config.customGenesis.eip155Block,
eip158Block: config.customGenesis.eip158Block,
byzantiumBlock: config.customGenesis.byzantiumBlock,
constantinopleBlock: config.customGenesis.constantinopleBlock,
petersburgBlock: config.customGenesis.petersburgBlock,
istanbulBlock: config.customGenesis.istanbulBlock,
muirGlacierBlock: config.customGenesis.muirGlacierBlock,
berlinBlock: config.customGenesis.berlinBlock
)
trace "Custom genesis block configuration loaded", configuration=result
proc publicChainConfig*(id: PublicNetwork): ChainConfig =
# For some public networks, NetworkId and ChainId value are identical
# but that is not always the case
@ -311,155 +243,14 @@ proc publicChainConfig*(id: PublicNetwork): ChainConfig =
berlinBlock: 4_460_644.toBlockNumber
)
of CustomNet:
privateChainConfig()
let conf = getConfiguration()
trace "Custom genesis block configuration loaded", conf=conf.customGenesis.config
conf.customGenesis.config
else:
error "No chain config for public network", networkId = id
doAssert(false, "No chain config for " & $id)
ChainConfig()
proc processCustomGenesisConfig(customGenesis: JsonNode): ConfigStatus =
## Parses Custom Genesis Block config options when customnetwork option provided
template checkForFork(chain, currentFork, previousFork: untyped, optional = false) =
# Template to load fork blocks and validate order
let currentForkName = currentFork.astToStr()
if chain.hasKey(currentForkName) and not optional:
if chain[currentForkName].kind == JInt:
currentFork = chain[currentForkName].getInt().toBlockNumber
if currentFork < previousFork:
error "Forks can't be assigned out of order"
quit(1)
else:
error "Invalid block value provided for", currentForkName, invalidValue=currentFork
quit(1)
proc parseConfig(T: type, c: JsonNode, field: string): T =
when T is string:
c[field].getStr()
elif T is Uint256:
hexToUint[256](c[field].getStr())
elif T is bool:
c[field].getBool()
elif T is Hash256:
MDigest[256].fromHex(c[field].getStr())
elif T is uint:
c[field].getInt().uint
elif T is Blocknonce:
(parseHexInt(c[field].getStr()).uint64).toBlockNonce
elif T is EthTime:
fromHex[int64](c[field].getStr()).fromUnix
elif T is EthAddress:
parseAddress(c[field].getStr())
elif T is seq[byte]:
hexToSeqByte(c[field].getStr())
elif T is int64:
fromHex[int64](c[field].getStr())
elif T is ChainId:
c[field].getInt().T
template validateConfigValue(chainDetails, field, jtype, T: untyped, checkError: static[bool] = true) =
let fieldName = field.astToStr()
if chainDetails.hasKey(fieldName):
if chainDetails[fieldName].kind == jtype:
field = parseConfig(T, chainDetails, fieldName)
else:
error "Invalid value provided for ", fieldName
quit(1)
else:
when checkError:
error "No value found in genesis block for", fieldName
quit(1)
let config = getConfiguration()
result = Success
var
chainId = 1.ChainId
homesteadBlock, daoForkblock, eip150Block, eip155Block, eip158Block, byzantiumBlock, constantinopleBlock = high(BlockNumber).toBlockNumber
petersburgBlock, istanbulBlock, muirGlacierBlock, berlinBlock = high(BlockNumber).toBlockNumber
eip150Hash, mixHash : MDigest[256]
daoForkSupport = false
nonce = 66.toBlockNonce
extraData = hexToSeqByte("0x")
gasLimit = 16777216.int64
difficulty = 1048576.u256
alloc = parseJson("{}")
timestamp : EthTime
coinbase : EthAddress
if customGenesis.hasKey("config"):
# Validate all fork blocks for custom genesis
let forkDetails = customGenesis["config"]
validateConfigValue(forkDetails, chainId, JInt, ChainId, checkError=false)
checkForFork(forkDetails, homesteadBlock, 0.toBlockNumber)
validateConfigValue(forkDetails, daoForkSupport, JBool, bool, checkError=false)
if daoForkSupport == true:
checkForFork(forkDetails, daoForkBlock, 0.toBlockNumber)
checkForFork(forkDetails, eip150Block, homesteadBlock)
validateConfigValue(forkDetails, eip150Hash, JString, Hash256, checkError = false)
checkForFork(forkDetails, eip155Block, eip150Block)
checkForFork(forkDetails, eip158Block, eip155Block)
checkForFork(forkDetails, byzantiumBlock, eip158Block)
checkForFork(forkDetails, constantinopleBlock, byzantiumBlock)
checkForFork(forkDetails, petersburgBlock, constantinopleBlock)
checkForFork(forkDetails, istanbulBlock, petersburgBlock)
checkForFork(forkDetails, muirGlacierBlock, istanbulBlock, optional = true)
checkForFork(forkDetails, istanbulBlock, berlinBlock)
validateConfigValue(customGenesis, nonce, JString, BlockNonce, checkError = false)
validateConfigValue(customGenesis, extraData, JSTring, seq[byte], checkError = false)
validateConfigValue(customGenesis, gasLimit, JString, int64, checkError = false)
validateConfigValue(customGenesis, difficulty, JString, UInt256)
if customGenesis.hasKey("alloc"):
alloc = customGenesis["alloc"]
validateConfigValue(customGenesis, mixHash, JString, Hash256, checkError = false)
validateConfigValue(customGenesis, coinbase, JString, EthAddress, checkError = false)
validateConfigValue(customGenesis, timestamp, JString, EthTime, checkError = false)
config.customGenesis = CustomGenesisConfig(
chainId: chainId,
homesteadBlock: homesteadBlock,
eip150Block: eip150Block,
eip150Hash: eip150Hash,
eip155Block: eip155Block,
eip158Block: eip158Block,
daoForkSupport: daoForkSupport,
byzantiumBlock: byzantiumBlock,
constantinopleBlock: constantinopleBlock,
petersburgBlock: petersburgBlock,
istanbulBlock: istanbulBlock,
muirGlacierBlock: muirGlacierBlock,
berlinBlock: berlinBlock,
nonce: nonce,
extraData: extraData,
gasLimit: gasLimit,
difficulty: difficulty,
prealloc: alloc,
mixHash: mixHash,
coinbase: coinbase,
timestamp: timestamp
)
proc customGenesis(key, value: string): ConfigStatus =
if value == "":
error "No genesis block config provided for custom network", network=key
result = ErrorParseOption
else:
try:
result = processCustomGenesisConfig(parseFile(value))
except IOError:
error "Genesis block config file not found", invalidFileName=value
result = ErrorParseOption
except JsonParsingError:
error "Invalid genesis block config file format", invalidFileName=value
result = ErrorIncorrectOption
except:
var msg = getCurrentExceptionMsg()
error "Error loading genesis block config file", invalidFileName=msg
result = Error
proc processList(v: string, o: var seq[string]) =
## Process comma-separated list of strings.
if len(v) > 0:
@ -687,7 +478,8 @@ proc processNetArguments(key, value: string): ConfigStatus =
elif skey == "kovan":
config.net.setNetwork(KovanNet)
elif skey == "customnetwork":
result = customGenesis(key, value)
if not loadCustomGenesis(value, config.customGenesis):
result = Error
config.net.networkId = NetworkId(CustomNet)
elif skey == "networkid":
var res = 0

View File

@ -10,7 +10,7 @@ import
stew/[byteutils], eth/trie/[hexary, db],
eth/[common, rlp], chronicles,
../errors, ../constants, ./storage_types,
../utils, ../config
../utils, ../config, ../chain_config
type
BaseChainDB* = ref object

View File

@ -1,62 +1,10 @@
import
tables, json, times, strutils,
eth/[common, rlp, trie], stint, stew/[byteutils],
std/[json, strutils, times, tables],
eth/[common, rlp, trie], stew/[byteutils],
chronicles, eth/trie/db,
db/[db_chain, state_db], genesis_alloc, config, constants
type
Genesis* = object
config*: ChainConfig
nonce*: BlockNonce
timestamp*: EthTime
extraData*: seq[byte]
gasLimit*: GasInt
difficulty*: DifficultyInt
mixhash*: Hash256
coinbase*: EthAddress
alloc*: GenesisAlloc
GenesisAlloc = TableRef[EthAddress, GenesisAccount]
GenesisAccount = object
code*: seq[byte]
storage*: Table[UInt256, UInt256]
balance*: UInt256
nonce*: AccountNonce
func toAddress(n: UInt256): EthAddress =
let a = n.toByteArrayBE()
result[0 .. ^1] = a.toOpenArray(12, a.high)
func decodePrealloc(data: seq[byte]): GenesisAlloc =
result = newTable[EthAddress, GenesisAccount]()
for tup in rlp.decode(data, seq[(UInt256, UInt256)]):
result[toAddress(tup[0])] = GenesisAccount(balance: tup[1])
proc customNetPrealloc(genesisBlock: JsonNode): GenesisAlloc =
result = newTable[EthAddress, GenesisAccount]()
for address, account in genesisBlock.pairs():
let nonce = if "nonce" in account:
parseHexInt(account["nonce"].getStr).AccountNonce
else:
AccountNonce(0)
let code = if "code" in account:
hexToSeqByte(account["code"].getStr)
else:
@[]
var acc = GenesisAccount(
balance: fromHex(UInt256, account["balance"].getStr),
code: code,
nonce: nonce
)
if "storage" in account:
let storage = account["storage"]
for k, v in storage:
acc.storage[fromHex(UInt256, k)] = fromHex(UInt256, v.getStr)
result[parseAddress(address)] = acc
./db/[db_chain, state_db],
./genesis_alloc, ./config, ./constants,
./chain_config
proc defaultGenesisBlockForNetwork*(id: PublicNetwork): Genesis =
result = case id
@ -95,28 +43,13 @@ proc defaultGenesisBlockForNetwork*(id: PublicNetwork): Genesis =
alloc: decodePrealloc(goerliAllocData)
)
of CustomNet:
let genesis = getConfiguration().customGenesis
var alloc = new GenesisAlloc
assert(genesis.prealloc.isNil.not, "genesis prealloc should not nil")
if genesis.prealloc != parseJson("{}"):
alloc = customNetPrealloc(genesis.prealloc)
Genesis(
nonce: genesis.nonce,
extraData: genesis.extraData,
gasLimit: genesis.gasLimit,
difficulty: genesis.difficulty,
alloc: alloc,
timestamp: genesis.timestamp,
mixhash: genesis.mixHash,
coinbase: genesis.coinbase
)
let customGenesis = getConfiguration().customGenesis
customGenesis.genesis
else:
# TODO: Fill out the rest
error "No default genesis for network", id
doAssert(false, "No default genesis for " & $id)
Genesis()
result.config = publicChainConfig(id)
proc toBlock*(g: Genesis, db: BaseChainDB = nil): BlockHeader =
let (tdb, pruneTrie) = if db.isNil: (newMemoryDB(), true)
@ -130,8 +63,6 @@ proc toBlock*(g: Genesis, db: BaseChainDB = nil): BlockHeader =
for k, v in account.storage:
sdb.setStorage(address, k, v)
var root = sdb.rootHash
result = BlockHeader(
nonce: g.nonce,
timestamp: g.timestamp,
@ -140,7 +71,7 @@ proc toBlock*(g: Genesis, db: BaseChainDB = nil): BlockHeader =
difficulty: g.difficulty,
mixDigest: g.mixhash,
coinbase: g.coinbase,
stateRoot: root,
stateRoot: sdb.rootHash,
parentHash: GENESIS_PARENT_HASH,
txRoot: BLANK_ROOT_HASH,
receiptRoot: BLANK_ROOT_HASH,
@ -161,7 +92,4 @@ proc commit*(g: Genesis, db: BaseChainDB) =
proc initializeEmptyDb*(db: BaseChainDB) =
trace "Writing genesis to DB"
let networkId = getConfiguration().net.networkId.toPublicNetwork()
# if networkId == CustomNet:
# raise newException(Exception, "Custom genesis not implemented")
# else:
defaultGenesisBlockForNetwork(networkId).commit(db)

View File

@ -1,6 +1,6 @@
import ../db/db_chain, eth/common, chronicles, ../vm_state, ../vm_types,
../vm_computation, ../vm_message, ../vm_types2, stint, nimcrypto,
../utils, eth/trie/db, ./executor, ../config, ../genesis, ../utils,
../utils, eth/trie/db, ./executor, ../chain_config, ../genesis, ../utils,
stew/endians2
when not defined(release):

View File

@ -9,7 +9,7 @@
import hexstrings, eth/[common, rlp, keys, trie/db], stew/byteutils, nimcrypto,
../db/[db_chain, accounts_cache], strutils, algorithm, options, times, json,
../constants, stint, hexstrings, rpc_types, ../config,
../constants, stint, hexstrings, rpc_types, ../chain_config,
../vm_state_transactions, ../vm_state, ../vm_types, ../vm_types2,
../vm_computation, ../p2p/executor, ../utils, ../transaction,
../transaction/call_evm

View File

@ -1,6 +1,6 @@
import
times, eth/common, stint,
../constants, ../config
../constants, ../chain_config
const
ExpDiffPeriod = 100000.u256

View File

@ -10,7 +10,7 @@ import
strformat, times, options,
eth/[common, rlp],
./difficulty, ../constants,
../config
../chain_config
export BlockHeader

View File

@ -0,0 +1,56 @@
{
"config": {
"chainId": 1,
"homesteadBlock": 0,
"daoForkSupport": true,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 2000
},
"genesis": {
"nonce": "0x0",
"timestamp": "0x0",
"extraData": "0x00",
"gasLimit": "0x5f5e100",
"difficulty": "0x20000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"alloc": {
"0000000000000000000000000000000000000100": {
"code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160005500",
"balance": "0xba1a9ce0ba1a9ce"
},
"0000000000000000000000000000000000000101": {
"code": "0x60047fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160005500",
"balance": "0xba1a9ce0ba1a9ce"
},
"0000000000000000000000000000000000000102": {
"code": "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160005500",
"balance": "0xba1a9ce0ba1a9ce"
},
"0000000000000000000000000000000000000103": {
"code": "0x600060000160005500",
"balance": "0xba1a9ce0ba1a9ce"
},
"0000000000000000000000000000000000000104": {
"code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60010160005500",
"balance": "0xba1a9ce0ba1a9ce"
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "0xba1a9ce0ba1a9ce"
},
"cccccccccccccccccccccccccccccccccccccccc": {
"code": "0x600060006000600060006004356101000162fffffff100",
"balance": "0xba1a9ce0ba1a9ce"
}
},
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
}

View File

@ -0,0 +1,45 @@
{
"config": {
"chainId": 7,
"homesteadBlock": 0,
"eip150Block": 0,
"eip158Block": 0
},
"genesis": {
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x20000",
"extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x2fefd8",
"nonce": "0x0000000000000000",
"timestamp": "0x1234",
"alloc": {
"cf49fda3be353c69b41ed96333cd24302da4556f": {
"balance": "0x123450000000000000000"
},
"0161e041aad467a890839d5b08b138c1e6373072": {
"balance": "0x123450000000000000000"
},
"87da6a8c6e9eff15d703fc2773e32f6af8dbe301": {
"balance": "0x123450000000000000000"
},
"b97de4b8c857e4f6bc354f226dc3249aaee49209": {
"balance": "0x123450000000000000000"
},
"c5065c9eeebe6df2c2284d046bfc906501846c51": {
"balance": "0x123450000000000000000"
},
"0000000000000000000000000000000000000314": {
"balance": "0x0",
"code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a223e05d1461006a578063abd1a0cf1461008d578063abfced1d146100d4578063e05c914a14610110578063e6768b451461014c575b610000565b346100005761007761019d565b6040518082815260200191505060405180910390f35b34610000576100be600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101a3565b6040518082815260200191505060405180910390f35b346100005761010e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101ed565b005b346100005761014a600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610236565b005b346100005761017960048080359060200190919080359060200190919080359060200190919050506103c4565b60405180848152602001838152602001828152602001935050505060405180910390f35b60005481565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b5050565b7f6031a8d62d7c95988fa262657cd92107d90ed96e08d8f867d32f26edfe85502260405180905060405180910390a17f47e2689743f14e97f7dcfa5eec10ba1dff02f83b3d1d4b9c07b206cbbda66450826040518082815260200191505060405180910390a1817fa48a6b249a5084126c3da369fbc9b16827ead8cb5cdc094b717d3f1dcd995e2960405180905060405180910390a27f7890603b316f3509577afd111710f9ebeefa15e12f72347d9dffd0d65ae3bade81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff167f7efef9ea3f60ddc038e50cccec621f86a0195894dc0520482abf8b5c6b659e4160405180905060405180910390a28181604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a05b5050565b6000600060008585859250925092505b935093509390505600a165627a7a72305820aaf842d0d0c35c45622c5263cbb54813d2974d3999c8c38551d7c613ea2bc1170029",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x1234",
"0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9": "0x01"
}
},
"0000000000000000000000000000000000000315": {
"balance": "0x9999999999999999999999999999999",
"code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ef2769ca1461003e575b610000565b3461000057610078600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061007a565b005b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f1935050505015610106578173ffffffffffffffffffffffffffffffffffffffff167f30a3c50752f2552dcc2b93f5b96866280816a986c0c0408cb6778b9fa198288f826040518082815260200191505060405180910390a25b5b50505600a165627a7a72305820637991fabcc8abad4294bf2bb615db78fbec4edff1635a2647d3894e2daf6a610029"
}
}
}
}

View File

@ -0,0 +1,17 @@
{
"genesis": {
"coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
"difficulty" : "0x020000",
"extraData" : "0x42",
"gasLimit" : "0x2fefd8",
"mixHash" : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46",
"nonce" : "0x78cc16f7b4f65485",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x54c98c81",
"alloc" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance" : "0x09184e72a000"
}
}
}
}

View File

@ -16,7 +16,7 @@ import
../nimbus/db/[db_chain, accounts_cache],
../nimbus/utils/header,
../nimbus/p2p/[executor, dao],
../nimbus/config,
../nimbus/[config, chain_config],
../stateless/[tree_from_witness, witness_types]
type

View File

@ -1,6 +1,11 @@
import unittest2, ../nimbus/[genesis, config], eth/common, nimcrypto/hash
import
std/[os],
unittest2, eth/common, nimcrypto/hash,
../nimbus/[genesis, config, chain_config]
proc genesisMain*() =
const dataFolder = "tests" / "customgenesis"
proc genesisTest() =
suite "Genesis":
test "Correct mainnet hash":
let g = defaultGenesisBlockForNetwork(MainNet)
@ -22,5 +27,17 @@ proc genesisMain*() =
let b = g.toBlock
check(b.blockHash == "bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a".toDigest)
proc customGenesisTest() =
suite "Custom Genesis":
test "loadCustomGenesis":
var cga, cgb, cgc: CustomGenesis
check loadCustomGenesis(dataFolder / "berlin2000.json", cga)
check loadCustomGenesis(dataFolder / "chainid7.json", cgb)
check loadCustomGenesis(dataFolder / "noconfig.json", cgc)
proc genesisMain*() =
genesisTest()
customGenesisTest()
when isMainModule:
genesisMain()

View File

@ -13,7 +13,7 @@ import
eth/[p2p, common, trie/db, rlp, trie],
eth/p2p/rlpx_protocols/eth_protocol,
graphql, ../nimbus/graphql/ethapi, graphql/test_common,
../nimbus/[genesis, config], ../nimbus/db/[db_chain, state_db],
../nimbus/[genesis, config, chain_config], ../nimbus/db/[db_chain, state_db],
../nimbus/p2p/chain, ../premix/parser, ./test_helpers
type
@ -37,17 +37,19 @@ proc setupChain(chainDB: BaseChainDB) =
jn = v
break
let genesisBlock = jn.toBlock("genesisRLP")
let genesis = jn.toBlock("genesisRLP")
let conf = getConfiguration()
conf.customGenesis.nonce = genesisBlock.header.nonce
conf.customGenesis.extraData = genesisBlock.header.extraData
conf.customGenesis.gasLimit = genesisBlock.header.gasLimit
conf.customGenesis.difficulty = genesisBlock.header.difficulty
conf.customGenesis.mixHash = genesisBlock.header.mixDigest
conf.customGenesis.coinBase = genesisBlock.header.coinbase
conf.customGenesis.timestamp = genesisBlock.header.timestamp
conf.customGenesis.prealloc = jn["pre"]
conf.customGenesis.genesis.nonce = genesis.header.nonce
conf.customGenesis.genesis.extraData = genesis.header.extraData
conf.customGenesis.genesis.gasLimit = genesis.header.gasLimit
conf.customGenesis.genesis.difficulty = genesis.header.difficulty
conf.customGenesis.genesis.mixHash = genesis.header.mixDigest
conf.customGenesis.genesis.coinBase = genesis.header.coinbase
conf.customGenesis.genesis.timestamp = genesis.header.timestamp
if not parseGenesisAlloc($(jn["pre"]), conf.customGenesis.genesis.alloc):
quit(QuitFailure)
chainDB.initializeEmptyDb()
let blocks = jn["blocks"]
@ -68,7 +70,7 @@ proc setupChain(chainDB: BaseChainDB) =
proc graphqlMain*() =
let conf = getConfiguration()
conf.net.networkId = NetworkId(CustomNet)
conf.customGenesis = CustomGenesisConfig(
conf.customGenesis.config = ChainConfig(
chainId : MainNet.ChainId,
byzantiumBlock : 0.toBlockNumber,
constantinopleBlock : 0.toBlockNumber,