mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 13:24:21 +00:00
Jordan/custom network (#962)
* Rearrange/rename test_kintsugu => test_custom_network why: Debug, fix and test more general problems related to running nimbus on a custom network. * Update UInt265/Json parser for --custom-network command line option why: As found out with the Kintsugi configuration, block number and balance have the same Nim type which led to misunderstandings. This patch makes sure that UInt265 encoded string values "0x11" decodes to 17, and "b" and "11" to 11. * Refactored genesis.toBlock() => genesis.toBlockHeader() why: The function toBlock(g,db) may return different results depending on whether the db descriptor argument is nil, or initialised. This is due to the db.config data sub-descriptor which may give various outcomes for the baseFee field of the genesis header. Also, the version where db is non-nil initialised is used internally only. So the public rewrite toBlockHeader() that replaces the toBlock() function expects a full set of NetworkParams. * update comments * Rename toBlockHeader() => toGenesisHeader() why: Polymorphic prototype used for BaseChainDB or NetworkParams argument. With a BaseChainDB descriptor argument, the name shall imply that the header is generated from the config fields rather than fetched from the database. * Added command line option --static-peers-file why: Handy feature to keep peer nodes in a file, similar to the --bootstrap-file option.
This commit is contained in:
parent
0060462dc0
commit
215e9856d3
@ -8,7 +8,7 @@
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[tables, strutils, options, times],
|
||||
std/[tables, strutils,sequtils, options, times],
|
||||
eth/[common, rlp, p2p], stint, stew/[byteutils],
|
||||
nimcrypto/hash,
|
||||
json_serialization, chronicles,
|
||||
@ -139,16 +139,26 @@ 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) =
|
||||
proc readValue(reader: var JsonReader, value: var UInt256) =
|
||||
## Mixin for `Json.loadFile()`. Note that this driver applies the same
|
||||
## to `BlockNumber` fields as well as generic `UInt265` fields like the
|
||||
## account `balance`.
|
||||
let tok = reader.lexer.tok
|
||||
if tok == tkInt:
|
||||
value = toBlockNumber(reader.lexer.absintVal)
|
||||
value = reader.lexer.absintVal.u256
|
||||
reader.lexer.next()
|
||||
elif tok == tkString:
|
||||
value = UInt256.fromHex(reader.lexer.strVal)
|
||||
# Make sure that "0x11" decodes to 17, "b" and "11" decode to 11.
|
||||
if reader.lexer.strVal.filterIt(it.isDigit.not).len == 0:
|
||||
try: value = reader.lexer.strVal.parse(UInt256, radix = 10)
|
||||
except: reader.raiseUnexpectedValue("int string overflow")
|
||||
else:
|
||||
# note that radix is static, so 16 (or 10) cannot be a variable
|
||||
try: value = reader.lexer.strVal.parse(UInt256, radix = 16)
|
||||
except: reader.raiseUnexpectedValue("hex string parse error")
|
||||
reader.lexer.next()
|
||||
else:
|
||||
reader.raiseUnexpectedValue("expect int or hex string")
|
||||
reader.raiseUnexpectedValue("expect int or hex/int string")
|
||||
|
||||
proc readValue(reader: var JsonReader, value: var ChainId) =
|
||||
value = reader.readValue(int).ChainId
|
||||
|
@ -268,6 +268,13 @@ type
|
||||
defaultValueDesc: ""
|
||||
name: "static-peers" }: seq[string]
|
||||
|
||||
staticPeersFile {.
|
||||
desc: "Specifies a line-delimited file of trusted peers addresses(enode URL)" &
|
||||
"to be added to the --staticPeers list. If the first line equals to the word `override`, "&
|
||||
"the file contents will replace the --staticPeers list"
|
||||
defaultValue: ""
|
||||
name: "static-peers-file" }: InputFile
|
||||
|
||||
listenAddress* {.
|
||||
desc: "Listening IP address for Ethereum P2P and Discovery traffic"
|
||||
defaultValue: defaultListenAddress
|
||||
@ -529,7 +536,7 @@ iterator strippedLines(filename: string): (int, string) =
|
||||
yield (i, stripped)
|
||||
inc i
|
||||
|
||||
proc loadBootstrapFile(fileName: string, output: var seq[Enode]) =
|
||||
proc loadEnodeFile(fileName: string; output: var seq[Enode]; info: string) =
|
||||
if fileName.len == 0:
|
||||
return
|
||||
|
||||
@ -542,15 +549,21 @@ proc loadBootstrapFile(fileName: string, output: var seq[Enode]) =
|
||||
|
||||
let res = ENode.fromString(ln)
|
||||
if res.isErr:
|
||||
warn "Ignoring invalid bootstrap address", address=ln, line=i, file=fileName
|
||||
warn "Ignoring invalid address", address=ln, line=i, file=fileName, purpose=info
|
||||
continue
|
||||
|
||||
output.add res.get()
|
||||
|
||||
except IOError as e:
|
||||
error "Could not read bootstrap file", msg = e.msg
|
||||
error "Could not read file", msg = e.msg, purpose = info
|
||||
quit 1
|
||||
|
||||
proc loadBootstrapFile(fileName: string, output: var seq[Enode]) =
|
||||
fileName.loadEnodeFile(output, "bootstrap")
|
||||
|
||||
proc loadStaticPeersFile(fileName: string, output: var seq[Enode]) =
|
||||
fileName.loadEnodeFile(output, "static peers")
|
||||
|
||||
proc getNetworkId(conf: NimbusConf): Option[NetworkId] =
|
||||
if conf.network.len == 0:
|
||||
return none NetworkId
|
||||
@ -628,6 +641,7 @@ proc getBootNodes*(conf: NimbusConf): seq[Enode] =
|
||||
|
||||
proc getStaticPeers*(conf: NimbusConf): seq[Enode] =
|
||||
result.append(conf.staticPeers)
|
||||
loadStaticPeersFile(string conf.staticPeersFile, result)
|
||||
|
||||
proc makeConfig*(cmdLine = commandLineParams()): NimbusConf =
|
||||
{.push warning[ProveInit]: off.}
|
||||
|
@ -5,18 +5,27 @@ import
|
||||
./db/[db_chain, state_db],
|
||||
"."/[constants, chain_config, forks, p2p/gaslimit]
|
||||
|
||||
proc toBlock*(g: Genesis, db: BaseChainDB = nil):
|
||||
BlockHeader {.raises: [Defect, RlpError].} =
|
||||
let (tdb, pruneTrie) = if db.isNil: (newMemoryDB(), true)
|
||||
else: (db.db, db.pruneTrie)
|
||||
{.push raises: [Defect].}
|
||||
|
||||
# For `eth/trie/db.newMemoryDB()`, the following initialiation is part of
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc initDbAccounts(db: BaseChainDB): BlockHeader
|
||||
{.raises: [Defect, RlpError].} =
|
||||
## Initialise block chain DB accounts derived from the `genesis.alloc` table
|
||||
## of the `db` descriptor argument.
|
||||
##
|
||||
## The function returns the `Genesis` block header.
|
||||
##
|
||||
|
||||
# For `eth/trie/db.newMemoryDB()`, the following initialisation is part of
|
||||
# the constructor function which is missing for the permanent constructor
|
||||
# function `eth/trie/db.trieDB()`.
|
||||
if not db.isNil:
|
||||
tdb.put(emptyRlpHash.data, emptyRlp)
|
||||
db.db.put(emptyRlpHash.data, emptyRlp)
|
||||
|
||||
var sdb = newAccountStateDB(tdb, emptyRlpHash, pruneTrie)
|
||||
var sdb = newAccountStateDB(db.db, emptyRlpHash, db.pruneTrie)
|
||||
let g = db.genesis
|
||||
|
||||
for address, account in g.alloc:
|
||||
sdb.setAccount(address, newAccount(account.nonce, account.balance))
|
||||
@ -45,8 +54,8 @@ proc toBlock*(g: Genesis, db: BaseChainDB = nil):
|
||||
#
|
||||
# This kludge also fixes the initial crash described in
|
||||
# https://github.com/status-im/nimbus-eth1/issues/932.
|
||||
if not db.isNil and db.pruneTrie:
|
||||
tdb.put(emptyRlpHash.data, emptyRlp) # <-- kludge
|
||||
if not db.isNil and db.pruneTrie and 0 < account.storage.len:
|
||||
db.db.put(emptyRlpHash.data, emptyRlp) # <-- kludge
|
||||
|
||||
for k, v in account.storage:
|
||||
sdb.setStorage(address, k, v)
|
||||
@ -68,7 +77,7 @@ proc toBlock*(g: Genesis, db: BaseChainDB = nil):
|
||||
|
||||
if g.baseFeePerGas.isSome:
|
||||
result.baseFee = g.baseFeePerGas.get()
|
||||
elif db.isNil.not and db.config.toFork(0.toBlockNumber) >= FkLondon:
|
||||
elif db.config.toFork(0.toBlockNumber) >= FkLondon:
|
||||
result.baseFee = EIP1559_INITIAL_BASE_FEE.u256
|
||||
|
||||
if g.gasLimit.isZero:
|
||||
@ -77,9 +86,34 @@ proc toBlock*(g: Genesis, db: BaseChainDB = nil):
|
||||
if g.difficulty.isZero:
|
||||
result.difficulty = GENESIS_DIFFICULTY
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc initializeEmptyDb*(db: BaseChainDB) =
|
||||
proc toGenesisHeader*(params: NetworkParams): BlockHeader
|
||||
{.raises: [Defect, RlpError].} =
|
||||
## Generate the genesis block header from the `params` argument value.
|
||||
newBaseChainDB(
|
||||
newMemoryDb(),
|
||||
id = params.config.chainID.NetworkId,
|
||||
params = params,
|
||||
pruneTrie = true).initDbAccounts
|
||||
|
||||
proc toGenesisHeader*(db: BaseChainDB): BlockHeader
|
||||
{.raises: [Defect, RlpError].} =
|
||||
## Generate the genesis block header from the `genesis` and `config`
|
||||
## fields of the argument `db` descriptor.
|
||||
NetworkParams(
|
||||
config: db.config,
|
||||
genesis: db.genesis).toGenesisHeader
|
||||
|
||||
proc initializeEmptyDb*(db: BaseChainDB)
|
||||
{.raises: [Defect, CatchableError].} =
|
||||
trace "Writing genesis to DB"
|
||||
let b = db.genesis.toBlock(db)
|
||||
let b = db.initDbAccounts
|
||||
doAssert(b.blockNumber.isZero, "can't commit genesis block with number > 0")
|
||||
discard db.persistHeaderToDb(b)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -132,7 +132,7 @@ func calculateForkIds(c: ChainConfig,
|
||||
|
||||
proc setForkId(c: Chain)
|
||||
{. raises: [Defect,CatchableError].} =
|
||||
c.blockZeroHash = toBlock(c.db.genesis).blockHash
|
||||
c.blockZeroHash = c.db.toGenesisHeader.blockHash
|
||||
let genesisCRC = crc32(0, c.blockZeroHash.data)
|
||||
c.forkIds = calculateForkIds(c.db.config, genesisCRC)
|
||||
|
||||
|
@ -12,7 +12,7 @@ import ../test_macro
|
||||
cliBuilder:
|
||||
import ./test_code_stream,
|
||||
./test_accounts_cache,
|
||||
./test_kintsugi,
|
||||
./test_custom_network,
|
||||
./test_gas_meter,
|
||||
./test_memory,
|
||||
./test_stack,
|
||||
|
130
tests/replay/pp.nim
Normal file
130
tests/replay/pp.nim
Normal file
@ -0,0 +1,130 @@
|
||||
# Nimbus
|
||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
# http://opensource.org/licenses/MIT)
|
||||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
## Pretty printing, an alternative to `$` for debugging
|
||||
## ----------------------------------------------------
|
||||
|
||||
import
|
||||
std/[sequtils, strformat, strutils, tables, times],
|
||||
../../nimbus/[chain_config, constants],
|
||||
eth/[common, trie/trie_defs]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, units pretty printer
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc ppMs*(elapsed: Duration): string =
|
||||
result = $elapsed.inMilliSeconds
|
||||
let ns = elapsed.inNanoSeconds mod 1_000_000
|
||||
if ns != 0:
|
||||
# to rounded deca milli seconds
|
||||
let dm = (ns + 5_000i64) div 10_000i64
|
||||
result &= &".{dm:02}"
|
||||
result &= "ms"
|
||||
|
||||
proc ppSecs*(elapsed: Duration): string =
|
||||
result = $elapsed.inSeconds
|
||||
let ns = elapsed.inNanoseconds mod 1_000_000_000
|
||||
if ns != 0:
|
||||
# to rounded decs seconds
|
||||
let ds = (ns + 5_000_000i64) div 10_000_000i64
|
||||
result &= &".{ds:02}"
|
||||
result &= "s"
|
||||
|
||||
proc toKMG*[T](s: T): string =
|
||||
proc subst(s: var string; tag, new: string): bool =
|
||||
if tag.len < s.len and s[s.len - tag.len ..< s.len] == tag:
|
||||
s = s[0 ..< s.len - tag.len] & new
|
||||
return true
|
||||
result = $s
|
||||
for w in [("000", "K"),("000K","M"),("000M","G"),("000G","T"),
|
||||
("000T","P"),("000P","E"),("000E","Z"),("000Z","Y")]:
|
||||
if not result.subst(w[0],w[1]):
|
||||
return
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, pretty printer
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc pp*(s: string; hex = false): string =
|
||||
if hex:
|
||||
let n = (s.len + 1) div 2
|
||||
(if s.len < 20: s else: s[0 .. 5] & ".." & s[s.len-8 .. s.len-1]) &
|
||||
"[" & (if 0 < n: "#" & $n else: "") & "]"
|
||||
elif s.len <= 30:
|
||||
s
|
||||
else:
|
||||
(if (s.len and 1) == 0: s[0 ..< 8] else: "0" & s[0 ..< 7]) &
|
||||
"..(" & $s.len & ").." & s[s.len-16 ..< s.len]
|
||||
|
||||
proc pp*(b: Blob): string =
|
||||
b.mapIt(it.toHex(2)).join.toLowerAscii.pp(hex = true)
|
||||
|
||||
proc pp*(a: Hash256; collapse = true): string =
|
||||
if not collapse:
|
||||
a.data.mapIt(it.toHex(2)).join.toLowerAscii
|
||||
elif a == emptyRlpHash:
|
||||
"emptyRlpHash"
|
||||
elif a == EMPTY_UNCLE_HASH:
|
||||
"EMPTY_UNCLE_HASH"
|
||||
elif a == EMPTY_SHA3:
|
||||
"EMPTY_SHA3"
|
||||
else:
|
||||
a.data.mapIt(it.toHex(2)).join[56 .. 63].toLowerAscii
|
||||
|
||||
proc pp*(a: EthAddress): string =
|
||||
a.mapIt(it.toHex(2)).join[32 .. 39].toLowerAscii
|
||||
|
||||
proc pp*(a: BlockNonce): string =
|
||||
a.mapIt(it.toHex(2)).join.toLowerAscii
|
||||
|
||||
proc pp*(h: BlockHeader; sep = " "): string =
|
||||
"" &
|
||||
&"hash={h.blockHash.pp}{sep}" &
|
||||
&"blockNumber={h.blockNumber}{sep}" &
|
||||
&"parentHash={h.parentHash.pp}{sep}" &
|
||||
&"coinbase={h.coinbase.pp}{sep}" &
|
||||
&"gasLimit={h.gasLimit}{sep}" &
|
||||
&"gasUsed={h.gasUsed}{sep}" &
|
||||
&"timestamp={h.timestamp.toUnix}{sep}" &
|
||||
&"extraData={h.extraData.pp}{sep}" &
|
||||
&"difficulty={h.difficulty}{sep}" &
|
||||
&"mixDigest={h.mixDigest.pp}{sep}" &
|
||||
&"nonce={h.nonce.pp}{sep}" &
|
||||
&"ommersHash={h.ommersHash.pp}{sep}" &
|
||||
&"txRoot={h.txRoot.pp}{sep}" &
|
||||
&"receiptRoot={h.receiptRoot.pp}{sep}" &
|
||||
&"stateRoot={h.stateRoot.pp}{sep}" &
|
||||
&"baseFee={h.baseFee}"
|
||||
|
||||
proc pp*(g: Genesis; sep = " "): string =
|
||||
"" &
|
||||
&"nonce={g.nonce.pp}{sep}" &
|
||||
&"timestamp={g.timestamp.toUnix}{sep}" &
|
||||
&"extraData={g.extraData.pp}{sep}" &
|
||||
&"gasLimit={g.gasLimit}{sep}" &
|
||||
&"difficulty={g.difficulty}{sep}" &
|
||||
&"mixHash={g.mixHash.pp}{sep}" &
|
||||
&"coinbase={g.coinbase.pp}{sep}" &
|
||||
&"alloc=<{g.alloc.len} accounts>{sep}" &
|
||||
&"number={g.number}{sep}" &
|
||||
&"gasUser={g.gasUser}{sep}" &
|
||||
&"parentHash={g.parentHash.pp}{sep}" &
|
||||
&"baseFeePerGas={g.baseFeePerGas}"
|
||||
|
||||
proc pp*(h: BlockHeader; indent: int): string =
|
||||
h.pp("\n" & " ".repeat(max(1,indent)))
|
||||
|
||||
proc pp*(g: Genesis; indent: int): string =
|
||||
g.pp("\n" & " ".repeat(max(1,indent)))
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
@ -64,7 +64,7 @@ proc dumpGroupBeginNl*(db: BaseChainDB;
|
||||
proc dumpGroupNl*(db: BaseChainDB; headers: openArray[BlockHeader];
|
||||
bodies: openArray[BlockBody]): string =
|
||||
## Add this below the line `transaction.commit()` in the function
|
||||
## `p2p/chain.persist_blocks.persistBlocksImpl()`:
|
||||
## `p2p/chain/persist_blocks.persistBlocksImpl()`:
|
||||
## ::
|
||||
## dumpStream.write c.db.dumpGroupNl(headers,bodies)
|
||||
##
|
||||
@ -72,7 +72,8 @@ proc dumpGroupNl*(db: BaseChainDB; headers: openArray[BlockHeader];
|
||||
## that could be initialised with
|
||||
## ::
|
||||
## var dumpStream: File
|
||||
## dumpStream.open("./dump-stream.out", fmWrite)
|
||||
## if dumpStream.isNil:
|
||||
## doAssert dumpStream.open("./dump-stream.out", fmWrite)
|
||||
##
|
||||
db.dumpGroupBeginNl(headers) &
|
||||
toSeq(countup(0, headers.len-1))
|
||||
|
@ -8,19 +8,33 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
## This unit test was roughly inspired by repeated failings of running nimbus
|
||||
## similar to
|
||||
## ::
|
||||
## nimbus \
|
||||
## --data-dir:./kintsugi/tmp \
|
||||
## --custom-network:kintsugi-network.json \
|
||||
## --bootstrap-file:kintsugi-bootnodes.txt \
|
||||
## --prune-mode:full ...
|
||||
##
|
||||
## from `issue 932` <https://github.com/status-im/nimbus-eth1/issues/932>`_.
|
||||
|
||||
import
|
||||
std/[distros, os, strformat, strutils],
|
||||
std/[distros, os, strformat, strutils, sequtils],
|
||||
../nimbus/[chain_config, config, genesis],
|
||||
../nimbus/db/[db_chain, select_backend],
|
||||
./replay/pp,
|
||||
eth/[common, p2p, trie/db],
|
||||
nimcrypto/hash,
|
||||
unittest2
|
||||
|
||||
const
|
||||
baseDir = [".", "tests", ".." / "tests", $DirSep] # path containg repo
|
||||
repoDir = ["status", "replay"] # alternative repo paths
|
||||
jFile = "nimbus_kintsugi.json"
|
||||
repoDir = ["customgenesis", "."] # alternative repo paths
|
||||
jFile = "kintsugi.json"
|
||||
|
||||
when defined(windows):
|
||||
|
||||
when not defined(linux):
|
||||
const isUbuntu32bit = false
|
||||
else:
|
||||
# The `detectOs(Ubuntu)` directive is not Windows compatible, causes an
|
||||
@ -62,9 +76,14 @@ proc flushDbDir(s: string) =
|
||||
# Typically under Windows: there might be stale file locks.
|
||||
try: dataDir.removeDir except: discard
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private functions
|
||||
# ------------------------------------------------------------------------------
|
||||
proc say*(noisy = false; pfx = "***"; args: varargs[string, `$`]) =
|
||||
if noisy:
|
||||
if args.len == 0:
|
||||
echo "*** ", pfx
|
||||
elif 0 < pfx.len and pfx[^1] != ' ':
|
||||
echo pfx, " ", args.toSeq.join
|
||||
else:
|
||||
echo pfx, args.toSeq.join
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Test Runner
|
||||
@ -81,15 +100,16 @@ proc runner(noisy = true; file = jFile) =
|
||||
defer:
|
||||
if not disablePersistentDB: tmpDir.flushDbDir
|
||||
|
||||
suite &"Kintsugi test scenario":
|
||||
suite "Kintsugi custom network test scenario":
|
||||
var
|
||||
params: NetworkParams
|
||||
mdb, ddb: BaseChainDB
|
||||
|
||||
test &"Load params from {fileInfo}":
|
||||
noisy.say "***", "custom-file=", filePath
|
||||
check filePath.loadNetworkParams(params)
|
||||
|
||||
test &"Construct in-memory BaseChainDB":
|
||||
test "Construct in-memory BaseChainDB":
|
||||
mdb = newBaseChainDB(
|
||||
newMemoryDb(),
|
||||
id = params.config.chainID.NetworkId,
|
||||
@ -105,49 +125,47 @@ proc runner(noisy = true; file = jFile) =
|
||||
# previous clean up.
|
||||
tmpDir.flushDbDir
|
||||
|
||||
# The effect of this constructor is roughly equivalent to the command
|
||||
# line invocation of nimbus as
|
||||
#
|
||||
# nimbus \
|
||||
# --data-dir:$tmpDir \
|
||||
# --custom-network:$filePath \
|
||||
# --prune-mode:full ...
|
||||
#
|
||||
# as described in https://github.com/status-im/nimbus-eth1/issues/932.
|
||||
# Constructor ...
|
||||
ddb = newBaseChainDB(
|
||||
tmpDir.newChainDb.trieDB,
|
||||
id = params.config.chainID.NetworkId,
|
||||
pruneTrie = true,
|
||||
params = params)
|
||||
|
||||
test "Initialise in-memory Genesis":
|
||||
mdb.initializeEmptyDb
|
||||
|
||||
#[
|
||||
test "Initialise persistent Genesis, expect AssertionError":
|
||||
if disablePersistentDB:
|
||||
skip()
|
||||
else:
|
||||
expect AssertionError:
|
||||
ddb.initializeEmptyDb
|
||||
#]#
|
||||
# Verify variant of `toBlockHeader()`. The function `pp()` is used
|
||||
# (rather than blockHash()) for readable error report (if any).
|
||||
let
|
||||
storedhHeaderPP = mdb.getBlockHeader(0.u256).pp
|
||||
onTheFlyHeaderPP = mdb.toGenesisHeader.pp
|
||||
check storedhHeaderPP == onTheFlyHeaderPP
|
||||
|
||||
test "Initialise persistent Genesis (kludge)":
|
||||
test "Initialise persistent Genesis":
|
||||
if disablePersistentDB:
|
||||
skip()
|
||||
else:
|
||||
ddb.initializeEmptyDb
|
||||
|
||||
# Must be the same as the in-memory DB value
|
||||
check ddb.getBlockHash(0.u256) == mdb.getBlockHash(0.u256)
|
||||
|
||||
let
|
||||
storedhHeaderPP = ddb.getBlockHeader(0.u256).pp
|
||||
onTheFlyHeaderPP = ddb.toGenesisHeader.pp
|
||||
check storedhHeaderPP == onTheFlyHeaderPP
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Main function(s)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc kintsugiMain*(noisy = defined(debug)) =
|
||||
proc customNetworkMain*(noisy = defined(debug)) =
|
||||
noisy.runner
|
||||
|
||||
when isMainModule:
|
||||
var noisy = defined(debug)
|
||||
#noisy = true
|
||||
|
||||
noisy = true
|
||||
noisy.runner
|
||||
|
||||
# ------------------------------------------------------------------------------
|
@ -3,45 +3,51 @@ import
|
||||
unittest2, eth/common, nimcrypto/hash,
|
||||
../nimbus/[genesis, config, chain_config]
|
||||
|
||||
const dataFolder = "tests" / "customgenesis"
|
||||
const
|
||||
baseDir = [".", "tests", ".." / "tests", $DirSep] # path containg repo
|
||||
repoDir = ["customgenesis", "status"] # alternative repo paths
|
||||
|
||||
proc findFilePath(file: string): string =
|
||||
result = "?unknown?" / file
|
||||
for dir in baseDir:
|
||||
for repo in repoDir:
|
||||
let path = dir / repo / file
|
||||
if path.fileExists:
|
||||
return path
|
||||
|
||||
proc genesisTest() =
|
||||
suite "Genesis":
|
||||
test "Correct mainnet hash":
|
||||
let g = networkParams(MainNet).genesis
|
||||
let b = g.toBlock
|
||||
let b = networkParams(MainNet).toGenesisHeader
|
||||
check(b.blockHash == "D4E56740F876AEF8C010B86A40D5F56745A118D0906A34E69AEC8C0DB1CB8FA3".toDigest)
|
||||
|
||||
test "Correct ropstennet hash":
|
||||
let g = networkParams(RopstenNet).genesis
|
||||
let b = g.toBlock
|
||||
let b = networkParams(RopstenNet).toGenesisHeader
|
||||
check(b.blockHash == "41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d".toDigest)
|
||||
|
||||
test "Correct rinkebynet hash":
|
||||
let g = networkParams(RinkebyNet).genesis
|
||||
let b = g.toBlock
|
||||
let b = networkParams(RinkebyNet).toGenesisHeader
|
||||
check(b.blockHash == "6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177".toDigest)
|
||||
|
||||
test "Correct goerlinet hash":
|
||||
let g = networkParams(GoerliNet).genesis
|
||||
let b = g.toBlock
|
||||
let b = networkParams(GoerliNet).toGenesisHeader
|
||||
check(b.blockHash == "bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a".toDigest)
|
||||
|
||||
proc customGenesisTest() =
|
||||
suite "Custom Genesis":
|
||||
test "loadCustomGenesis":
|
||||
var cga, cgb, cgc: NetworkParams
|
||||
check loadNetworkParams(dataFolder / "berlin2000.json", cga)
|
||||
check loadNetworkParams(dataFolder / "chainid7.json", cgb)
|
||||
check loadNetworkParams(dataFolder / "noconfig.json", cgc)
|
||||
check loadNetworkParams("berlin2000.json".findFilePath, cga)
|
||||
check loadNetworkParams("chainid7.json".findFilePath, cgb)
|
||||
check loadNetworkParams("noconfig.json".findFilePath, cgc)
|
||||
check cga.config.poaEngine == false
|
||||
check cgb.config.poaEngine == false
|
||||
check cgc.config.poaEngine == false
|
||||
|
||||
test "calaveras.json":
|
||||
var cg: NetworkParams
|
||||
check loadNetworkParams(dataFolder / "calaveras.json", cg)
|
||||
let h = toBlock(cg.genesis, nil)
|
||||
check loadNetworkParams("calaveras.json".findFilePath, cg)
|
||||
let h = cg.toGenesisHeader
|
||||
let stateRoot = "664c93de37eb4a72953ea42b8c046cdb64c9f0b0bca5505ade8d970d49ebdb8c".toDigest
|
||||
let genesisHash = "eb9233d066c275efcdfed8037f4fc082770176aefdbcb7691c71da412a5670f2".toDigest
|
||||
check h.stateRoot == stateRoot
|
||||
@ -50,6 +56,16 @@ proc customGenesisTest() =
|
||||
check cg.config.cliquePeriod == 30
|
||||
check cg.config.cliqueEpoch == 30000
|
||||
|
||||
test "kintsugi.json":
|
||||
var cg: NetworkParams
|
||||
check loadNetworkParams("kintsugi.json".findFilePath, cg)
|
||||
let h = cg.toGenesisHeader
|
||||
let stateRoot = "3b84f313bfd49c03cc94729ade2e0de220688f813c0c895a99bd46ecc9f45e1e".toDigest
|
||||
let genesisHash = "a28d8d73e087a01d09d8cb806f60863652f30b6b6dfa4e0157501ff07d422399".toDigest
|
||||
check h.stateRoot == stateRoot
|
||||
check h.blockHash == genesisHash
|
||||
check cg.config.poaEngine == false
|
||||
|
||||
proc genesisMain*() =
|
||||
genesisTest()
|
||||
customGenesisTest()
|
||||
|
@ -12,7 +12,7 @@ import
|
||||
std/[strformat, sequtils, strutils, times],
|
||||
../../nimbus/utils/tx_pool/[tx_chain, tx_desc, tx_gauge, tx_item, tx_tabs],
|
||||
../../nimbus/utils/tx_pool/tx_tasks/[tx_packer, tx_recover],
|
||||
../replay/undump,
|
||||
../replay/[pp, undump],
|
||||
eth/[common, keys],
|
||||
stew/[keyed_queue, sorted_set],
|
||||
stint
|
||||
@ -20,6 +20,7 @@ import
|
||||
# Make sure that the runner can stay on public view without the need
|
||||
# to import `tx_pool/*` sup-modules
|
||||
export
|
||||
pp,
|
||||
tx_chain.TxChainGasLimits,
|
||||
tx_chain.`maxMode=`,
|
||||
tx_chain.clearAccounts,
|
||||
@ -102,52 +103,10 @@ proc toXX(h: Hash256): string =
|
||||
proc toXX(v: int64; r,s: UInt256): string =
|
||||
v.toXX & ":" & ($r).joinXX & ":" & ($s).joinXX
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, units pretty printer
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc ppMs*(elapsed: Duration): string =
|
||||
result = $elapsed.inMilliSeconds
|
||||
let ns = elapsed.inNanoSeconds mod 1_000_000
|
||||
if ns != 0:
|
||||
# to rounded deca milli seconds
|
||||
let dm = (ns + 5_000i64) div 10_000i64
|
||||
result &= &".{dm:02}"
|
||||
result &= "ms"
|
||||
|
||||
proc ppSecs*(elapsed: Duration): string =
|
||||
result = $elapsed.inSeconds
|
||||
let ns = elapsed.inNanoseconds mod 1_000_000_000
|
||||
if ns != 0:
|
||||
# to rounded decs seconds
|
||||
let ds = (ns + 5_000_000i64) div 10_000_000i64
|
||||
result &= &".{ds:02}"
|
||||
result &= "s"
|
||||
|
||||
proc toKMG*[T](s: T): string =
|
||||
proc subst(s: var string; tag, new: string): bool =
|
||||
if tag.len < s.len and s[s.len - tag.len ..< s.len] == tag:
|
||||
s = s[0 ..< s.len - tag.len] & new
|
||||
return true
|
||||
result = $s
|
||||
for w in [("000", "K"),("000K","M"),("000M","G"),("000G","T"),
|
||||
("000T","P"),("000P","E"),("000E","Z"),("000Z","Y")]:
|
||||
if not result.subst(w[0],w[1]):
|
||||
return
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions, pretty printer
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc pp*(a: BlockNonce): string =
|
||||
a.mapIt(it.toHex(2)).join.toLowerAscii
|
||||
|
||||
proc pp*(a: EthAddress): string =
|
||||
a.mapIt(it.toHex(2)).join[32 .. 39].toLowerAscii
|
||||
|
||||
proc pp*(a: Hash256): string =
|
||||
a.data.mapIt(it.toHex(2)).join[56 .. 63].toLowerAscii
|
||||
|
||||
proc pp*(q: seq[(EthAddress,int)]): string =
|
||||
"[" & q.mapIt(&"{it[0].pp}:{it[1]:03d}").join(",") & "]"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user