Add metadata for the Holesky network (#5337)
* Add metadata for the Holesky network * Add copyright banner to the new Nim module * Working version * Bump Chronos to fix downloading from Github * Add checksum check of the downloaded file * Clean up debugging code and obsolete imports
This commit is contained in:
parent
c5a79a6f8f
commit
53589b5a7d
|
@ -59,7 +59,7 @@
|
||||||
path = vendor/nim-chronos
|
path = vendor/nim-chronos
|
||||||
url = https://github.com/status-im/nim-chronos.git
|
url = https://github.com/status-im/nim-chronos.git
|
||||||
ignore = untracked
|
ignore = untracked
|
||||||
branch = master
|
branch = nimbus-v23.9.0
|
||||||
[submodule "vendor/nim-chronicles"]
|
[submodule "vendor/nim-chronicles"]
|
||||||
path = vendor/nim-chronicles
|
path = vendor/nim-chronicles
|
||||||
url = https://github.com/status-im/nim-chronicles.git
|
url = https://github.com/status-im/nim-chronicles.git
|
||||||
|
@ -220,3 +220,8 @@
|
||||||
url = https://github.com/arnetheduck/nim-results.git
|
url = https://github.com/arnetheduck/nim-results.git
|
||||||
ignore = untracked
|
ignore = untracked
|
||||||
branch = master
|
branch = master
|
||||||
|
[submodule "vendor/holesky"]
|
||||||
|
path = vendor/holesky
|
||||||
|
url = https://github.com/eth-clients/holesky
|
||||||
|
ignore = untracked
|
||||||
|
branch = main
|
||||||
|
|
|
@ -1402,6 +1402,7 @@ proc exchangeConfigWithSingleEL(m: ELManager, connection: ELConnection) {.async.
|
||||||
of rinkeby: 4.Quantity
|
of rinkeby: 4.Quantity
|
||||||
of goerli: 5.Quantity
|
of goerli: 5.Quantity
|
||||||
of sepolia: 11155111.Quantity # https://chainid.network/
|
of sepolia: 11155111.Quantity # https://chainid.network/
|
||||||
|
of holesky: 17000.Quantity
|
||||||
if expectedChain != providerChain:
|
if expectedChain != providerChain:
|
||||||
warn "The specified EL client is connected to a different chain",
|
warn "The specified EL client is connected to a different chain",
|
||||||
url = connection.engineUrl,
|
url = connection.engineUrl,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import
|
||||||
web3/[ethtypes, conversions],
|
web3/[ethtypes, conversions],
|
||||||
chronicles,
|
chronicles,
|
||||||
eth/common/eth_types_json_serialization,
|
eth/common/eth_types_json_serialization,
|
||||||
../spec/eth2_ssz_serialization
|
../spec/[eth2_ssz_serialization, forks]
|
||||||
|
|
||||||
# TODO(zah):
|
# TODO(zah):
|
||||||
# We can compress the embedded states with snappy before embedding them here.
|
# We can compress the embedded states with snappy before embedding them here.
|
||||||
|
@ -45,6 +45,29 @@ type
|
||||||
rinkeby
|
rinkeby
|
||||||
goerli
|
goerli
|
||||||
sepolia
|
sepolia
|
||||||
|
holesky
|
||||||
|
|
||||||
|
GenesisMetadataKind* = enum
|
||||||
|
NoGenesis
|
||||||
|
UserSuppliedFile
|
||||||
|
BakedIn
|
||||||
|
BakedInUrl
|
||||||
|
|
||||||
|
DownloadInfo* = object
|
||||||
|
url: string
|
||||||
|
digest: Eth2Digest
|
||||||
|
|
||||||
|
GenesisMetadata* = object
|
||||||
|
case kind*: GenesisMetadataKind
|
||||||
|
of NoGenesis:
|
||||||
|
discard
|
||||||
|
of UserSuppliedFile:
|
||||||
|
path*: string
|
||||||
|
of BakedIn:
|
||||||
|
networkName*: string
|
||||||
|
of BakedInUrl:
|
||||||
|
url*: string
|
||||||
|
digest*: Eth2Digest
|
||||||
|
|
||||||
Eth2NetworkMetadata* = object
|
Eth2NetworkMetadata* = object
|
||||||
case incompatible*: bool
|
case incompatible*: bool
|
||||||
|
@ -62,22 +85,13 @@ type
|
||||||
depositContractBlock*: uint64
|
depositContractBlock*: uint64
|
||||||
depositContractBlockHash*: Eth2Digest
|
depositContractBlockHash*: Eth2Digest
|
||||||
|
|
||||||
# `genesisData` will have `len == 0` for networks with a still
|
genesis*: GenesisMetadata
|
||||||
# unknown genesis state.
|
|
||||||
when incbinEnabled:
|
|
||||||
genesisData*: seq[byte]
|
|
||||||
else:
|
|
||||||
genesisData*: string
|
|
||||||
|
|
||||||
genesisDepositsSnapshot*: string
|
genesisDepositsSnapshot*: string
|
||||||
else:
|
else:
|
||||||
incompatibilityDesc*: string
|
incompatibilityDesc*: string
|
||||||
|
|
||||||
template genesisBytes*(metadata: Eth2NetworkMetadata): auto =
|
func hasGenesis*(metadata: Eth2NetworkMetadata): bool =
|
||||||
when incbinEnabled:
|
metadata.genesis.kind != NoGenesis
|
||||||
metadata.genesisData
|
|
||||||
else:
|
|
||||||
metadata.genesisData.toOpenArrayByte(0, metadata.genesisData.high)
|
|
||||||
|
|
||||||
proc readBootstrapNodes*(path: string): seq[string] {.raises: [IOError].} =
|
proc readBootstrapNodes*(path: string): seq[string] {.raises: [IOError].} =
|
||||||
# Read a list of ENR values from a YAML file containing a flat list of entries
|
# Read a list of ENR values from a YAML file containing a flat list of entries
|
||||||
|
@ -98,7 +112,11 @@ proc readBootEnr*(path: string): seq[string] {.raises: [IOError].} =
|
||||||
@[]
|
@[]
|
||||||
|
|
||||||
proc loadEth2NetworkMetadata*(
|
proc loadEth2NetworkMetadata*(
|
||||||
path: string, eth1Network = none(Eth1Network), loadGenesis = true):
|
path: string,
|
||||||
|
eth1Network = none(Eth1Network),
|
||||||
|
isCompileTime = false,
|
||||||
|
downloadGenesisFrom = none(DownloadInfo),
|
||||||
|
useBakedInGenesis = none(string)):
|
||||||
Eth2NetworkMetadata {.raises: [CatchableError].} =
|
Eth2NetworkMetadata {.raises: [CatchableError].} =
|
||||||
# Load data in eth2-networks format
|
# Load data in eth2-networks format
|
||||||
# https://github.com/eth-clients/eth2-networks
|
# https://github.com/eth-clients/eth2-networks
|
||||||
|
@ -166,11 +184,6 @@ proc loadEth2NetworkMetadata*(
|
||||||
readBootstrapNodes(bootstrapNodesPath) &
|
readBootstrapNodes(bootstrapNodesPath) &
|
||||||
readBootEnr(bootEnrPath))
|
readBootEnr(bootEnrPath))
|
||||||
|
|
||||||
genesisData = if loadGenesis and fileExists(genesisPath):
|
|
||||||
readFile(genesisPath)
|
|
||||||
else:
|
|
||||||
""
|
|
||||||
|
|
||||||
genesisDepositsSnapshot = if fileExists(genesisDepositsSnapshotPath):
|
genesisDepositsSnapshot = if fileExists(genesisDepositsSnapshotPath):
|
||||||
readFile(genesisDepositsSnapshotPath)
|
readFile(genesisDepositsSnapshotPath)
|
||||||
else:
|
else:
|
||||||
|
@ -183,9 +196,18 @@ proc loadEth2NetworkMetadata*(
|
||||||
bootstrapNodes: bootstrapNodes,
|
bootstrapNodes: bootstrapNodes,
|
||||||
depositContractBlock: depositContractBlock,
|
depositContractBlock: depositContractBlock,
|
||||||
depositContractBlockHash: depositContractBlockHash,
|
depositContractBlockHash: depositContractBlockHash,
|
||||||
genesisData:
|
genesis:
|
||||||
when incbinEnabled: toBytes genesisData
|
if downloadGenesisFrom.isSome:
|
||||||
else: genesisData,
|
GenesisMetadata(kind: BakedInUrl,
|
||||||
|
url: downloadGenesisFrom.get.url,
|
||||||
|
digest: downloadGenesisFrom.get.digest)
|
||||||
|
elif useBakedInGenesis.isSome:
|
||||||
|
GenesisMetadata(kind: BakedIn, networkName: useBakedInGenesis.get)
|
||||||
|
elif fileExists(genesisPath) and not isCompileTime:
|
||||||
|
GenesisMetadata(kind: UserSuppliedFile, path: genesisPath)
|
||||||
|
else:
|
||||||
|
GenesisMetadata(kind: NoGenesis)
|
||||||
|
,
|
||||||
genesisDepositsSnapshot: genesisDepositsSnapshot)
|
genesisDepositsSnapshot: genesisDepositsSnapshot)
|
||||||
|
|
||||||
except PresetIncompatibleError as err:
|
except PresetIncompatibleError as err:
|
||||||
|
@ -195,10 +217,14 @@ proc loadEth2NetworkMetadata*(
|
||||||
proc loadCompileTimeNetworkMetadata(
|
proc loadCompileTimeNetworkMetadata(
|
||||||
path: string,
|
path: string,
|
||||||
eth1Network = none(Eth1Network),
|
eth1Network = none(Eth1Network),
|
||||||
loadGenesis = true): Eth2NetworkMetadata {.raises: [].} =
|
useBakedInGenesis = none(string),
|
||||||
|
downloadGenesisFrom = none(DownloadInfo)): Eth2NetworkMetadata {.raises: [].} =
|
||||||
if fileExists(path & "/config.yaml"):
|
if fileExists(path & "/config.yaml"):
|
||||||
try:
|
try:
|
||||||
result = loadEth2NetworkMetadata(path, eth1Network, loadGenesis)
|
result = loadEth2NetworkMetadata(path, eth1Network,
|
||||||
|
isCompileTime = true,
|
||||||
|
downloadGenesisFrom = downloadGenesisFrom,
|
||||||
|
useBakedInGenesis = useBakedInGenesis)
|
||||||
if result.incompatible:
|
if result.incompatible:
|
||||||
macros.error "The current build is misconfigured. " &
|
macros.error "The current build is misconfigured. " &
|
||||||
"Attempt to load an incompatible network metadata: " &
|
"Attempt to load an incompatible network metadata: " &
|
||||||
|
@ -209,27 +235,36 @@ proc loadCompileTimeNetworkMetadata(
|
||||||
macros.error "config.yaml not found for network '" & path
|
macros.error "config.yaml not found for network '" & path
|
||||||
|
|
||||||
when const_preset == "gnosis":
|
when const_preset == "gnosis":
|
||||||
import stew/assign2
|
|
||||||
|
|
||||||
when incbinEnabled:
|
when incbinEnabled:
|
||||||
let
|
let
|
||||||
gnosisGenesis {.importc: "gnosis_mainnet_genesis".}: ptr UncheckedArray[byte]
|
gnosisGenesis* {.importc: "gnosis_mainnet_genesis".}: ptr UncheckedArray[byte]
|
||||||
gnosisGenesisSize {.importc: "gnosis_mainnet_genesis_size".}: int
|
gnosisGenesisSize* {.importc: "gnosis_mainnet_genesis_size".}: int
|
||||||
|
|
||||||
chiadoGenesis {.importc: "gnosis_chiado_genesis".}: ptr UncheckedArray[byte]
|
chiadoGenesis* {.importc: "gnosis_chiado_genesis".}: ptr UncheckedArray[byte]
|
||||||
chiadoGenesisSize {.importc: "gnosis_chiado_genesis_size".}: int
|
chiadoGenesisSize* {.importc: "gnosis_chiado_genesis_size".}: int
|
||||||
|
|
||||||
# let `.incbin` in assembly file find the binary file through search path
|
# let `.incbin` in assembly file find the binary file through search path
|
||||||
{.passc: "-I" & vendorDir.}
|
{.passc: "-I" & vendorDir.}
|
||||||
{.compile: "network_metadata_gnosis.S".}
|
{.compile: "network_metadata_gnosis.S".}
|
||||||
|
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
gnosisGenesis* = slurp(
|
||||||
|
vendorDir & "/gnosis-chain-configs/mainnet/genesis.ssz")
|
||||||
|
|
||||||
|
chiadoGenesis* = slurp(
|
||||||
|
vendorDir & "/gnosis-chain-configs/chiado/genesis.ssz")
|
||||||
|
|
||||||
const
|
const
|
||||||
gnosisMetadata = loadCompileTimeNetworkMetadata(
|
gnosisMetadata = loadCompileTimeNetworkMetadata(
|
||||||
vendorDir & "/gnosis-chain-configs/mainnet",
|
vendorDir & "/gnosis-chain-configs/mainnet",
|
||||||
none(Eth1Network), not incbinEnabled)
|
none(Eth1Network),
|
||||||
|
useBakedInGenesis = some "gnosis")
|
||||||
|
|
||||||
chiadoMetadata = loadCompileTimeNetworkMetadata(
|
chiadoMetadata = loadCompileTimeNetworkMetadata(
|
||||||
vendorDir & "/gnosis-chain-configs/chiado",
|
vendorDir & "/gnosis-chain-configs/chiado",
|
||||||
none(Eth1Network), not incbinEnabled)
|
none(Eth1Network),
|
||||||
|
useBakedInGenesis = some "chiado")
|
||||||
|
|
||||||
static:
|
static:
|
||||||
for network in [gnosisMetadata, chiadoMetadata]:
|
for network in [gnosisMetadata, chiadoMetadata]:
|
||||||
|
@ -242,38 +277,62 @@ when const_preset == "gnosis":
|
||||||
doAssert network.cfg.DENEB_FORK_EPOCH == FAR_FUTURE_EPOCH
|
doAssert network.cfg.DENEB_FORK_EPOCH == FAR_FUTURE_EPOCH
|
||||||
|
|
||||||
elif const_preset == "mainnet":
|
elif const_preset == "mainnet":
|
||||||
import stew/assign2
|
|
||||||
|
|
||||||
when incbinEnabled:
|
when incbinEnabled:
|
||||||
# Nim is very inefficent at loading large constants from binary files so we
|
# Nim is very inefficent at loading large constants from binary files so we
|
||||||
# use this trick instead which saves significant amounts of compile time
|
# use this trick instead which saves significant amounts of compile time
|
||||||
let
|
let
|
||||||
mainnetGenesis {.importc: "eth2_mainnet_genesis".}: ptr UncheckedArray[byte]
|
mainnetGenesis* {.importc: "eth2_mainnet_genesis".}: ptr UncheckedArray[byte]
|
||||||
mainnetGenesisSize {.importc: "eth2_mainnet_genesis_size".}: int
|
mainnetGenesisSize* {.importc: "eth2_mainnet_genesis_size".}: int
|
||||||
|
|
||||||
praterGenesis {.importc: "eth2_goerli_genesis".}: ptr UncheckedArray[byte]
|
praterGenesis* {.importc: "eth2_goerli_genesis".}: ptr UncheckedArray[byte]
|
||||||
praterGenesisSize {.importc: "eth2_goerli_genesis_size".}: int
|
praterGenesisSize* {.importc: "eth2_goerli_genesis_size".}: int
|
||||||
|
|
||||||
sepoliaGenesis {.importc: "eth2_sepolia_genesis".}: ptr UncheckedArray[byte]
|
sepoliaGenesis* {.importc: "eth2_sepolia_genesis".}: ptr UncheckedArray[byte]
|
||||||
sepoliaGenesisSize {.importc: "eth2_sepolia_genesis_size".}: int
|
sepoliaGenesisSize* {.importc: "eth2_sepolia_genesis_size".}: int
|
||||||
|
|
||||||
# let `.incbin` in assembly file find the binary file through search path
|
# let `.incbin` in assembly file find the binary file through search path
|
||||||
{.passc: "-I" & vendorDir.}
|
{.passc: "-I" & vendorDir.}
|
||||||
{.compile: "network_metadata_mainnet.S".}
|
{.compile: "network_metadata_mainnet.S".}
|
||||||
|
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
mainnetGenesis* = slurp(
|
||||||
|
vendorDir & "/eth2-networks/shared/mainnet/genesis.ssz")
|
||||||
|
|
||||||
|
praterGenesis* = slurp(
|
||||||
|
vendorDir & "/eth2-networks/shared/prater/genesis.ssz")
|
||||||
|
|
||||||
|
sepoliaGenesis* = slurp(
|
||||||
|
vendorDir & "/sepolia/bepolia/genesis.ssz")
|
||||||
|
|
||||||
const
|
const
|
||||||
mainnetMetadata = loadCompileTimeNetworkMetadata(
|
mainnetMetadata = loadCompileTimeNetworkMetadata(
|
||||||
vendorDir & "/eth2-networks/shared/mainnet", some mainnet, not incbinEnabled)
|
vendorDir & "/eth2-networks/shared/mainnet",
|
||||||
|
some mainnet,
|
||||||
|
useBakedInGenesis = some "mainnet")
|
||||||
|
|
||||||
praterMetadata = loadCompileTimeNetworkMetadata(
|
praterMetadata = loadCompileTimeNetworkMetadata(
|
||||||
vendorDir & "/eth2-networks/shared/prater", some goerli, not incbinEnabled)
|
vendorDir & "/eth2-networks/shared/prater",
|
||||||
|
some goerli,
|
||||||
|
useBakedInGenesis = some "prater")
|
||||||
|
|
||||||
|
holeskyMetadata = loadCompileTimeNetworkMetadata(
|
||||||
|
vendorDir & "/holesky/custom_config_data",
|
||||||
|
some holesky,
|
||||||
|
downloadGenesisFrom = some DownloadInfo(
|
||||||
|
url: "https://github.com/status-im/nimbus-eth2/releases/download/v23.8.0/holesky-genesis.ssz.snappy-framed",
|
||||||
|
digest: Eth2Digest.fromHex "0x76631cd0b9ddc5b2c766b496e23f16759ce1181446a4efb40e5540cd15b78a07"))
|
||||||
|
|
||||||
sepoliaMetadata = loadCompileTimeNetworkMetadata(
|
sepoliaMetadata = loadCompileTimeNetworkMetadata(
|
||||||
vendorDir & "/sepolia/bepolia", some sepolia, not incbinEnabled)
|
vendorDir & "/sepolia/bepolia",
|
||||||
|
some sepolia,
|
||||||
|
useBakedInGenesis = some "sepolia")
|
||||||
|
|
||||||
static:
|
static:
|
||||||
for network in [mainnetMetadata, praterMetadata, sepoliaMetadata]:
|
for network in [mainnetMetadata, praterMetadata, sepoliaMetadata, holeskyMetadata]:
|
||||||
checkForkConsistency(network.cfg)
|
checkForkConsistency(network.cfg)
|
||||||
|
|
||||||
for network in [mainnetMetadata, praterMetadata, sepoliaMetadata]:
|
for network in [mainnetMetadata, praterMetadata, sepoliaMetadata, holeskyMetadata]:
|
||||||
doAssert network.cfg.ALTAIR_FORK_EPOCH < FAR_FUTURE_EPOCH
|
doAssert network.cfg.ALTAIR_FORK_EPOCH < FAR_FUTURE_EPOCH
|
||||||
doAssert network.cfg.BELLATRIX_FORK_EPOCH < FAR_FUTURE_EPOCH
|
doAssert network.cfg.BELLATRIX_FORK_EPOCH < FAR_FUTURE_EPOCH
|
||||||
doAssert network.cfg.CAPELLA_FORK_EPOCH < FAR_FUTURE_EPOCH
|
doAssert network.cfg.CAPELLA_FORK_EPOCH < FAR_FUTURE_EPOCH
|
||||||
|
@ -295,40 +354,30 @@ proc getMetadataForNetwork*(
|
||||||
if networkName == "ropsten":
|
if networkName == "ropsten":
|
||||||
warn "Ropsten is unsupported; https://blog.ethereum.org/2022/11/30/ropsten-shutdown-announcement suggests migrating to Goerli or Sepolia"
|
warn "Ropsten is unsupported; https://blog.ethereum.org/2022/11/30/ropsten-shutdown-announcement suggests migrating to Goerli or Sepolia"
|
||||||
|
|
||||||
template withGenesis(metadata, genesis: untyped): untyped =
|
|
||||||
when incbinEnabled:
|
|
||||||
var tmp = metadata
|
|
||||||
case tmp.incompatible
|
|
||||||
of false:
|
|
||||||
assign(tmp.genesisData, genesis.toOpenArray(0, `genesis Size` - 1))
|
|
||||||
of true:
|
|
||||||
raiseAssert "Unreachable" # `loadCompileTimeNetworkMetadata`
|
|
||||||
tmp
|
|
||||||
else:
|
|
||||||
metadata
|
|
||||||
|
|
||||||
let metadata =
|
let metadata =
|
||||||
when const_preset == "gnosis":
|
when const_preset == "gnosis":
|
||||||
case toLowerAscii(networkName)
|
case toLowerAscii(networkName)
|
||||||
of "gnosis":
|
of "gnosis":
|
||||||
withGenesis(gnosisMetadata, gnosisGenesis)
|
gnosisMetadata
|
||||||
of "gnosis-chain":
|
of "gnosis-chain":
|
||||||
warn "`--network:gnosis-chain` is deprecated, " &
|
warn "`--network:gnosis-chain` is deprecated, " &
|
||||||
"use `--network:gnosis` instead"
|
"use `--network:gnosis` instead"
|
||||||
withGenesis(gnosisMetadata, gnosisGenesis)
|
gnosisMetadata
|
||||||
of "chiado":
|
of "chiado":
|
||||||
withGenesis(chiadoMetadata, chiadoGenesis)
|
chiadoMetadata
|
||||||
else:
|
else:
|
||||||
loadRuntimeMetadata()
|
loadRuntimeMetadata()
|
||||||
|
|
||||||
elif const_preset == "mainnet":
|
elif const_preset == "mainnet":
|
||||||
case toLowerAscii(networkName)
|
case toLowerAscii(networkName)
|
||||||
of "mainnet":
|
of "mainnet":
|
||||||
withGenesis(mainnetMetadata, mainnetGenesis)
|
mainnetMetadata
|
||||||
of "prater", "goerli":
|
of "prater", "goerli":
|
||||||
withGenesis(praterMetadata, praterGenesis)
|
praterMetadata
|
||||||
|
of "holesky":
|
||||||
|
holeskyMetadata
|
||||||
of "sepolia":
|
of "sepolia":
|
||||||
withGenesis(sepoliaMetadata, sepoliaGenesis)
|
sepoliaMetadata
|
||||||
else:
|
else:
|
||||||
loadRuntimeMetadata()
|
loadRuntimeMetadata()
|
||||||
|
|
||||||
|
@ -373,3 +422,67 @@ proc getRuntimeConfig*(
|
||||||
of true:
|
of true:
|
||||||
# `getMetadataForNetwork` / `loadCompileTimeNetworkMetadata`
|
# `getMetadataForNetwork` / `loadCompileTimeNetworkMetadata`
|
||||||
raiseAssert "Unreachable"
|
raiseAssert "Unreachable"
|
||||||
|
|
||||||
|
template bakedInGenesisStateAsBytes(networkName: untyped): untyped =
|
||||||
|
when incbinEnabled:
|
||||||
|
`networkName Genesis`.toOpenArray(0, `networkName GenesisSize` - 1)
|
||||||
|
else:
|
||||||
|
`networkName Genesis`.toOpenArrayByte(0, `networkName Genesis`.high)
|
||||||
|
|
||||||
|
const
|
||||||
|
availableOnlyInMainnetBuild =
|
||||||
|
"Baked-in genesis states for the official Ethereum " &
|
||||||
|
"networks are available only in the mainnet build of Nimbus"
|
||||||
|
|
||||||
|
availableOnlyInGnosisBuild =
|
||||||
|
"Baked-in genesis states for the Gnosis network " &
|
||||||
|
"are available only in the gnosis build of Nimbus"
|
||||||
|
|
||||||
|
when const_preset in ["mainnet", "gnosis"]:
|
||||||
|
template bakedBytes*(metadata: GenesisMetadata): auto =
|
||||||
|
case metadata.networkName
|
||||||
|
of "mainnet":
|
||||||
|
when const_preset == "mainnet":
|
||||||
|
bakedInGenesisStateAsBytes mainnet
|
||||||
|
else:
|
||||||
|
raiseAssert availableOnlyInMainnetBuild
|
||||||
|
of "prater":
|
||||||
|
when const_preset == "mainnet":
|
||||||
|
bakedInGenesisStateAsBytes prater
|
||||||
|
else:
|
||||||
|
raiseAssert availableOnlyInMainnetBuild
|
||||||
|
of "sepolia":
|
||||||
|
when const_preset == "mainnet":
|
||||||
|
bakedInGenesisStateAsBytes sepolia
|
||||||
|
else:
|
||||||
|
raiseAssert availableOnlyInMainnetBuild
|
||||||
|
of "gnosis":
|
||||||
|
when const_preset == "gnosis":
|
||||||
|
bakedInGenesisStateAsBytes gnosis
|
||||||
|
else:
|
||||||
|
raiseAssert availableOnlyInGnosisBuild
|
||||||
|
of "chiado":
|
||||||
|
when const_preset == "gnosis":
|
||||||
|
bakedInGenesisStateAsBytes chiado
|
||||||
|
else:
|
||||||
|
raiseAssert availableOnlyInGnosisBuild
|
||||||
|
else:
|
||||||
|
raiseAssert "The baked network metadata should use one of the name above"
|
||||||
|
|
||||||
|
func bakedGenesisValidatorsRoot*(metadata: Eth2NetworkMetadata): Opt[Eth2Digest] =
|
||||||
|
if metadata.genesis.kind == BakedIn:
|
||||||
|
try:
|
||||||
|
let header = SSZ.decode(
|
||||||
|
toOpenArray(metadata.genesis.bakedBytes, 0, sizeof(BeaconStateHeader) - 1),
|
||||||
|
BeaconStateHeader)
|
||||||
|
Opt.some header.genesis_validators_root
|
||||||
|
except SerializationError as err:
|
||||||
|
raiseAssert "Invalid baken-in genesis state"
|
||||||
|
else:
|
||||||
|
Opt.none Eth2Digest
|
||||||
|
else:
|
||||||
|
func bakedBytes*(metadata: GenesisMetadata): seq[byte] =
|
||||||
|
raiseAssert "Baked genesis states are not available in the current build mode"
|
||||||
|
|
||||||
|
func bakedGenesisValidatorsRoot*(metadata: Eth2NetworkMetadata): Opt[Eth2Digest] =
|
||||||
|
Opt.none Eth2Digest
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# beacon_chain
|
||||||
|
# Copyright (c) 2023 Status Research & Development GmbH
|
||||||
|
# Licensed and distributed under either of
|
||||||
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
import
|
||||||
|
std/uri,
|
||||||
|
stew/io2, chronos, chronos/apps/http/httpclient, snappy,
|
||||||
|
../spec/digest
|
||||||
|
|
||||||
|
import network_metadata
|
||||||
|
export network_metadata
|
||||||
|
|
||||||
|
type
|
||||||
|
HttpFetchError* = object of CatchableError
|
||||||
|
status*: int
|
||||||
|
|
||||||
|
DigestMismatchError* = object of CatchableError
|
||||||
|
|
||||||
|
proc downloadFile(url: Uri): Future[seq[byte]] {.async.} =
|
||||||
|
var httpSession = HttpSessionRef.new()
|
||||||
|
let response = await httpSession.fetch(url)
|
||||||
|
if response[0] == 200:
|
||||||
|
return response[1]
|
||||||
|
else:
|
||||||
|
raise (ref HttpFetchError)(
|
||||||
|
msg: "Unexpected status code " & $response[0] & " when fetching " & $url,
|
||||||
|
status: response[0])
|
||||||
|
|
||||||
|
proc fetchBytes*(metadata: GenesisMetadata): Future[seq[byte]] {.async.} =
|
||||||
|
case metadata.kind
|
||||||
|
of NoGenesis:
|
||||||
|
raiseAssert "fetchBytes should be called only when metadata.hasGenesis is true"
|
||||||
|
of BakedIn:
|
||||||
|
result = @(metadata.bakedBytes)
|
||||||
|
of BakedInUrl:
|
||||||
|
result = decodeFramed(await downloadFile(parseUri metadata.url))
|
||||||
|
if eth2digest(result) != metadata.digest:
|
||||||
|
raise (ref DigestMismatchError)(
|
||||||
|
msg: "The downloaded genesis state cannot be verified (checksum mismatch)")
|
||||||
|
of UserSuppliedFile:
|
||||||
|
result = readAllBytes(metadata.path).tryGet()
|
||||||
|
|
||||||
|
proc sourceDesc*(metadata: GenesisMetadata): string =
|
||||||
|
case metadata.kind
|
||||||
|
of NoGenesis:
|
||||||
|
"no genesis"
|
||||||
|
of BakedIn:
|
||||||
|
metadata.networkName
|
||||||
|
of BakedInUrl:
|
||||||
|
metadata.url
|
||||||
|
of UserSuppliedFile:
|
||||||
|
metadata.path
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
let holeskyMetadata = getMetadataForNetwork("holesky")
|
||||||
|
io2.writeFile(
|
||||||
|
"holesky-genesis.ssz",
|
||||||
|
waitFor holeskyMetadata.genesis.fetchBytes()
|
||||||
|
).expect("success")
|
|
@ -15,7 +15,7 @@ import
|
||||||
eth/p2p/discoveryv5/[enr, random2],
|
eth/p2p/discoveryv5/[enr, random2],
|
||||||
./consensus_object_pools/blob_quarantine,
|
./consensus_object_pools/blob_quarantine,
|
||||||
./consensus_object_pools/vanity_logs/vanity_logs,
|
./consensus_object_pools/vanity_logs/vanity_logs,
|
||||||
./networking/topic_params,
|
./networking/[topic_params, network_metadata_downloads],
|
||||||
./rpc/[rest_api, state_ttl_cache],
|
./rpc/[rest_api, state_ttl_cache],
|
||||||
./spec/datatypes/[altair, bellatrix, phase0],
|
./spec/datatypes/[altair, bellatrix, phase0],
|
||||||
./spec/[deposit_snapshots, engine_authentication, weak_subjectivity],
|
./spec/[deposit_snapshots, engine_authentication, weak_subjectivity],
|
||||||
|
@ -462,8 +462,8 @@ const
|
||||||
proc init*(T: type BeaconNode,
|
proc init*(T: type BeaconNode,
|
||||||
rng: ref HmacDrbgContext,
|
rng: ref HmacDrbgContext,
|
||||||
config: BeaconNodeConf,
|
config: BeaconNodeConf,
|
||||||
metadata: Eth2NetworkMetadata): BeaconNode
|
metadata: Eth2NetworkMetadata): Future[BeaconNode]
|
||||||
{.raises: [CatchableError].} =
|
{.async, raises: [CatchableError].} =
|
||||||
var taskpool: TaskPoolPtr
|
var taskpool: TaskPoolPtr
|
||||||
|
|
||||||
template cfg: auto = metadata.cfg
|
template cfg: auto = metadata.cfg
|
||||||
|
@ -541,18 +541,31 @@ proc init*(T: type BeaconNode,
|
||||||
if engineApiUrls.len == 0:
|
if engineApiUrls.len == 0:
|
||||||
notice "Running without execution client - validator features disabled (see https://nimbus.guide/eth1.html)"
|
notice "Running without execution client - validator features disabled (see https://nimbus.guide/eth1.html)"
|
||||||
|
|
||||||
var genesisState =
|
var networkGenesisValidatorsRoot = metadata.bakedGenesisValidatorsRoot
|
||||||
if metadata.genesisData.len > 0:
|
|
||||||
try:
|
|
||||||
newClone readSszForkedHashedBeaconState(cfg, metadata.genesisBytes)
|
|
||||||
except CatchableError as err:
|
|
||||||
raiseAssert "Invalid baked-in state of length " &
|
|
||||||
$metadata.genesisBytes.len & " and eth2digest " &
|
|
||||||
$eth2digest(metadata.genesisBytes) & ": " & err.msg
|
|
||||||
else:
|
|
||||||
nil
|
|
||||||
|
|
||||||
if not ChainDAGRef.isInitialized(db).isOk():
|
if not ChainDAGRef.isInitialized(db).isOk():
|
||||||
|
let genesisState =
|
||||||
|
if metadata.hasGenesis:
|
||||||
|
let genesisBytes = try:
|
||||||
|
if metadata.genesis.kind == BakedInUrl:
|
||||||
|
info "Obtaining genesis state", sourceUrl = metadata.genesis.url
|
||||||
|
await metadata.genesis.fetchBytes()
|
||||||
|
except CatchableError as err:
|
||||||
|
error "Failed to obtain genesis state",
|
||||||
|
source = metadata.genesis.sourceDesc,
|
||||||
|
err = err.msg
|
||||||
|
quit 1
|
||||||
|
try:
|
||||||
|
newClone readSszForkedHashedBeaconState(cfg, genesisBytes)
|
||||||
|
except CatchableError as err:
|
||||||
|
error "Invalid genesis state",
|
||||||
|
size = genesisBytes.len,
|
||||||
|
digest = eth2digest(genesisBytes),
|
||||||
|
err = err.msg
|
||||||
|
quit 1
|
||||||
|
else:
|
||||||
|
nil
|
||||||
|
|
||||||
if genesisState == nil and checkpointState == nil:
|
if genesisState == nil and checkpointState == nil:
|
||||||
fatal "No database and no genesis snapshot found. Please supply a genesis.ssz " &
|
fatal "No database and no genesis snapshot found. Please supply a genesis.ssz " &
|
||||||
"with the network configuration"
|
"with the network configuration"
|
||||||
|
@ -573,6 +586,8 @@ proc init*(T: type BeaconNode,
|
||||||
# answering genesis queries
|
# answering genesis queries
|
||||||
if not genesisState.isNil:
|
if not genesisState.isNil:
|
||||||
ChainDAGRef.preInit(db, genesisState[])
|
ChainDAGRef.preInit(db, genesisState[])
|
||||||
|
networkGenesisValidatorsRoot =
|
||||||
|
Opt.some(getStateField(genesisState[], genesis_validators_root))
|
||||||
|
|
||||||
if not checkpointState.isNil:
|
if not checkpointState.isNil:
|
||||||
if genesisState.isNil or
|
if genesisState.isNil or
|
||||||
|
@ -605,12 +620,6 @@ proc init*(T: type BeaconNode,
|
||||||
validatorMonitor[].addMonitor(key, Opt.none(ValidatorIndex))
|
validatorMonitor[].addMonitor(key, Opt.none(ValidatorIndex))
|
||||||
|
|
||||||
let
|
let
|
||||||
networkGenesisValidatorsRoot =
|
|
||||||
if not genesisState.isNil:
|
|
||||||
Opt.some(getStateField(genesisState[], genesis_validators_root))
|
|
||||||
else:
|
|
||||||
Opt.none(Eth2Digest)
|
|
||||||
|
|
||||||
dag = loadChainDag(
|
dag = loadChainDag(
|
||||||
config, cfg, db, eventBus,
|
config, cfg, db, eventBus,
|
||||||
validatorMonitor, networkGenesisValidatorsRoot)
|
validatorMonitor, networkGenesisValidatorsRoot)
|
||||||
|
@ -1893,7 +1902,7 @@ proc doRunBeaconNode(config: var BeaconNodeConf, rng: ref HmacDrbgContext) {.rai
|
||||||
bnStatus = BeaconNodeStatus.Stopping
|
bnStatus = BeaconNodeStatus.Stopping
|
||||||
c_signal(ansi_c.SIGTERM, SIGTERMHandler)
|
c_signal(ansi_c.SIGTERM, SIGTERMHandler)
|
||||||
|
|
||||||
let node = BeaconNode.init(rng, config, metadata)
|
let node = waitFor BeaconNode.init(rng, config, metadata)
|
||||||
|
|
||||||
if node.dag.cfg.DENEB_FORK_EPOCH != FAR_FUTURE_EPOCH:
|
if node.dag.cfg.DENEB_FORK_EPOCH != FAR_FUTURE_EPOCH:
|
||||||
let res =
|
let res =
|
||||||
|
@ -2042,8 +2051,14 @@ proc handleStartUpCmd(config: var BeaconNodeConf) {.raises: [CatchableError].} =
|
||||||
kind: TrustedNodeSyncKind.StateId,
|
kind: TrustedNodeSyncKind.StateId,
|
||||||
stateId: "finalized")
|
stateId: "finalized")
|
||||||
genesis =
|
genesis =
|
||||||
if network.genesisData.len > 0:
|
if network.hasGenesis:
|
||||||
newClone(readSszForkedHashedBeaconState(cfg, network.genesisBytes))
|
let genesisBytes = try: waitFor network.genesis.fetchBytes()
|
||||||
|
except CatchableError as err:
|
||||||
|
error "Failed to obtain genesis state",
|
||||||
|
source = network.genesis.sourceDesc,
|
||||||
|
err = err.msg
|
||||||
|
quit 1
|
||||||
|
newClone(readSszForkedHashedBeaconState(cfg, genesisBytes))
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
if config.blockId.isSome():
|
if config.blockId.isSome():
|
||||||
|
|
|
@ -11,7 +11,7 @@ import
|
||||||
eth/db/kvstore_sqlite3,
|
eth/db/kvstore_sqlite3,
|
||||||
./el/el_manager,
|
./el/el_manager,
|
||||||
./gossip_processing/optimistic_processor,
|
./gossip_processing/optimistic_processor,
|
||||||
./networking/[topic_params, network_metadata],
|
./networking/[topic_params, network_metadata_downloads],
|
||||||
./spec/beaconstate,
|
./spec/beaconstate,
|
||||||
./spec/datatypes/[phase0, altair, bellatrix, capella, deneb],
|
./spec/datatypes/[phase0, altair, bellatrix, capella, deneb],
|
||||||
"."/[filepath, light_client, light_client_db, nimbus_binary_common, version]
|
"."/[filepath, light_client, light_client_db, nimbus_binary_common, version]
|
||||||
|
@ -63,9 +63,15 @@ programMain:
|
||||||
template cfg(): auto = metadata.cfg
|
template cfg(): auto = metadata.cfg
|
||||||
|
|
||||||
let
|
let
|
||||||
|
genesisBytes = try: waitFor metadata.genesis.fetchBytes()
|
||||||
|
except CatchableError as err:
|
||||||
|
error "Failed to obtain genesis state",
|
||||||
|
source = metadata.genesis.sourceDesc,
|
||||||
|
err = err.msg
|
||||||
|
quit 1
|
||||||
genesisState =
|
genesisState =
|
||||||
try:
|
try:
|
||||||
newClone(readSszForkedHashedBeaconState(cfg, metadata.genesisBytes))
|
newClone(readSszForkedHashedBeaconState(cfg, genesisBytes))
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
raiseAssert "Invalid baked-in state: " & err.msg
|
raiseAssert "Invalid baked-in state: " & err.msg
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
TERMINAL_BLOCK_HASH:
|
TERMINAL_BLOCK_HASH:
|
||||||
$cfg.TERMINAL_BLOCK_HASH,
|
$cfg.TERMINAL_BLOCK_HASH,
|
||||||
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH:
|
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH:
|
||||||
Base10.toString(uint64(TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH)),
|
Base10.toString(uint64(cfg.TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH)),
|
||||||
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
|
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
|
||||||
Base10.toString(cfg.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT),
|
Base10.toString(cfg.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT),
|
||||||
MIN_GENESIS_TIME:
|
MIN_GENESIS_TIME:
|
||||||
|
|
|
@ -57,9 +57,6 @@ const
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/deneb/beacon-chain.md#domain-types
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/deneb/beacon-chain.md#domain-types
|
||||||
DOMAIN_BLOB_SIDECAR* = DomainType([byte 0x0b, 0x00, 0x00, 0x00])
|
DOMAIN_BLOB_SIDECAR* = DomainType([byte 0x0b, 0x00, 0x00, 0x00])
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/bellatrix/beacon-chain.md#transition-settings
|
|
||||||
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH* = FAR_FUTURE_EPOCH
|
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/phase0/fork-choice.md#configuration
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/phase0/fork-choice.md#configuration
|
||||||
PROPOSER_SCORE_BOOST*: uint64 = 40
|
PROPOSER_SCORE_BOOST*: uint64 = 40
|
||||||
|
|
||||||
|
|
|
@ -981,10 +981,10 @@ func getForkSchedule*(cfg: RuntimeConfig): array[5, Fork] =
|
||||||
|
|
||||||
type
|
type
|
||||||
# The first few fields of a state, shared across all forks
|
# The first few fields of a state, shared across all forks
|
||||||
BeaconStateHeader = object
|
BeaconStateHeader* = object
|
||||||
genesis_time: uint64
|
genesis_time*: uint64
|
||||||
genesis_validators_root: Eth2Digest
|
genesis_validators_root*: Eth2Digest
|
||||||
slot: Slot
|
slot*: Slot
|
||||||
|
|
||||||
func readSszForkedHashedBeaconState*(
|
func readSszForkedHashedBeaconState*(
|
||||||
consensusFork: ConsensusFork, data: openArray[byte]):
|
consensusFork: ConsensusFork, data: openArray[byte]):
|
||||||
|
|
|
@ -76,6 +76,9 @@ type
|
||||||
DEPOSIT_NETWORK_ID*: uint64
|
DEPOSIT_NETWORK_ID*: uint64
|
||||||
DEPOSIT_CONTRACT_ADDRESS*: Eth1Address
|
DEPOSIT_CONTRACT_ADDRESS*: Eth1Address
|
||||||
|
|
||||||
|
# Not actively used, but part of the spec
|
||||||
|
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH*: Epoch
|
||||||
|
|
||||||
PresetFile* = object
|
PresetFile* = object
|
||||||
values*: Table[string, string]
|
values*: Table[string, string]
|
||||||
missingValues*: seq[string]
|
missingValues*: seq[string]
|
||||||
|
@ -118,6 +121,7 @@ when const_preset == "mainnet":
|
||||||
# * 'prater' - testnet
|
# * 'prater' - testnet
|
||||||
# * 'ropsten' - testnet
|
# * 'ropsten' - testnet
|
||||||
# * 'sepolia' - testnet
|
# * 'sepolia' - testnet
|
||||||
|
# * 'holesky' - testnet
|
||||||
# Must match the regex: [a-z0-9\-]
|
# Must match the regex: [a-z0-9\-]
|
||||||
CONFIG_NAME: "",
|
CONFIG_NAME: "",
|
||||||
|
|
||||||
|
@ -221,6 +225,7 @@ elif const_preset == "gnosis":
|
||||||
# * 'prater' - testnet
|
# * 'prater' - testnet
|
||||||
# * 'ropsten' - testnet
|
# * 'ropsten' - testnet
|
||||||
# * 'sepolia' - testnet
|
# * 'sepolia' - testnet
|
||||||
|
# * 'holesky' - testnet
|
||||||
# Must match the regex: [a-z0-9\-]
|
# Must match the regex: [a-z0-9\-]
|
||||||
CONFIG_NAME: "",
|
CONFIG_NAME: "",
|
||||||
|
|
||||||
|
@ -319,6 +324,7 @@ elif const_preset == "minimal":
|
||||||
# * 'prater' - testnet
|
# * 'prater' - testnet
|
||||||
# * 'ropsten' - testnet
|
# * 'ropsten' - testnet
|
||||||
# * 'sepolia' - testnet
|
# * 'sepolia' - testnet
|
||||||
|
# * 'holesky' - testnet
|
||||||
# Must match the regex: [a-z0-9\-]
|
# Must match the regex: [a-z0-9\-]
|
||||||
CONFIG_NAME: "minimal",
|
CONFIG_NAME: "minimal",
|
||||||
|
|
||||||
|
@ -586,9 +592,6 @@ proc readRuntimeConfig*(
|
||||||
checkCompatibility BLOB_SIDECAR_SUBNET_COUNT
|
checkCompatibility BLOB_SIDECAR_SUBNET_COUNT
|
||||||
checkCompatibility MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS
|
checkCompatibility MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS
|
||||||
|
|
||||||
# Never pervasively implemented, still under discussion
|
|
||||||
checkCompatibility TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
|
||||||
|
|
||||||
# Isn't being used as a preset in the usual way: at any time, there's one correct value
|
# Isn't being used as a preset in the usual way: at any time, there's one correct value
|
||||||
checkCompatibility PROPOSER_SCORE_BOOST
|
checkCompatibility PROPOSER_SCORE_BOOST
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,7 @@ Each era is identified by when it ends. Thus, the genesis era is era `0`, follow
|
||||||
|
|
||||||
`.era` file names follow a simple convention: `<config-name>-<era-number>-<era-count>-<short-historical-root>.era`:
|
`.era` file names follow a simple convention: `<config-name>-<era-number>-<era-count>-<short-historical-root>.era`:
|
||||||
|
|
||||||
* `config-name` is the `CONFIG_NAME` field of the runtime configation (`mainnet`, `prater`, `sepolia`, etc)
|
* `config-name` is the `CONFIG_NAME` field of the runtime configation (`mainnet`, `prater`, `sepolia`, `holesky`, etc)
|
||||||
* `era-number` is the number of the _first_ era stored in the file - for example, the genesis era file has number 0 - as a 5-digit 0-filled decimal integer
|
* `era-number` is the number of the _first_ era stored in the file - for example, the genesis era file has number 0 - as a 5-digit 0-filled decimal integer
|
||||||
* `short-era-root` is the first 4 bytes of the last historical root in the _last_ state in the era file, lower-case hex-encoded (8 characters), except the genesis era which instead uses the `genesis_validators_root` field from the genesis state.
|
* `short-era-root` is the first 4 bytes of the last historical root in the _last_ state in the era file, lower-case hex-encoded (8 characters), except the genesis era which instead uses the `genesis_validators_root` field from the genesis state.
|
||||||
* The root is available as `state.historical_roots[era - 1]` except for genesis, which is `state.genesis_validators_root`
|
* The root is available as `state.historical_roots[era - 1]` except for genesis, which is `state.genesis_validators_root`
|
||||||
|
|
|
@ -301,7 +301,7 @@ proc startBeaconNode(basePort: int) {.raises: [CatchableError].} =
|
||||||
|
|
||||||
let
|
let
|
||||||
metadata = loadEth2NetworkMetadata(dataDir)
|
metadata = loadEth2NetworkMetadata(dataDir)
|
||||||
node = BeaconNode.init(rng, runNodeConf, metadata)
|
node = waitFor BeaconNode.init(rng, runNodeConf, metadata)
|
||||||
|
|
||||||
node.start() # This will run until the node is terminated by
|
node.start() # This will run until the node is terminated by
|
||||||
# setting its `bnStatus` to `Stopping`.
|
# setting its `bnStatus` to `Stopping`.
|
||||||
|
|
|
@ -17,7 +17,7 @@ template checkRoot(name, root) =
|
||||||
metadata = getMetadataForNetwork(name)
|
metadata = getMetadataForNetwork(name)
|
||||||
cfg = metadata.cfg
|
cfg = metadata.cfg
|
||||||
state = newClone(readSszForkedHashedBeaconState(
|
state = newClone(readSszForkedHashedBeaconState(
|
||||||
metadata.cfg, metadata.genesisBytes))
|
metadata.cfg, metadata.genesis.bakedBytes))
|
||||||
|
|
||||||
check:
|
check:
|
||||||
$getStateRoot(state[]) == root
|
$getStateRoot(state[]) == root
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit f1ad227a2511ea26f5d043fad15d9431fd681941
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6c2ea675123ed0bf5c5d76c92ed4985bacd1a9ec
|
Subproject commit 176d462b076db24d9f71ddb40163d1ef82823771
|
Loading…
Reference in New Issue