From 53589b5a7d4e4e5214227852ad280eaa2789c40a Mon Sep 17 00:00:00 2001 From: zah Date: Fri, 8 Sep 2023 08:53:27 +0300 Subject: [PATCH] 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 --- .gitmodules | 7 +- beacon_chain/el/el_manager.nim | 1 + beacon_chain/networking/network_metadata.nim | 239 +++++++++++++----- .../networking/network_metadata_downloads.nim | 62 +++++ beacon_chain/nimbus_beacon_node.nim | 59 +++-- beacon_chain/nimbus_light_client.nim | 10 +- beacon_chain/rpc/rest_config_api.nim | 2 +- beacon_chain/spec/datatypes/constants.nim | 3 - beacon_chain/spec/forks.nim | 8 +- beacon_chain/spec/presets.nim | 9 +- docs/e2store.md | 2 +- tests/test_keymanager_api.nim | 2 +- tests/test_network_metadata.nim | 2 +- vendor/holesky | 1 + vendor/nim-chronos | 2 +- 15 files changed, 306 insertions(+), 103 deletions(-) create mode 100644 beacon_chain/networking/network_metadata_downloads.nim create mode 160000 vendor/holesky diff --git a/.gitmodules b/.gitmodules index e585d0175..5b662e2b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -59,7 +59,7 @@ path = vendor/nim-chronos url = https://github.com/status-im/nim-chronos.git ignore = untracked - branch = master + branch = nimbus-v23.9.0 [submodule "vendor/nim-chronicles"] path = vendor/nim-chronicles url = https://github.com/status-im/nim-chronicles.git @@ -220,3 +220,8 @@ url = https://github.com/arnetheduck/nim-results.git ignore = untracked branch = master +[submodule "vendor/holesky"] + path = vendor/holesky + url = https://github.com/eth-clients/holesky + ignore = untracked + branch = main diff --git a/beacon_chain/el/el_manager.nim b/beacon_chain/el/el_manager.nim index 38c3320cb..9cec29915 100644 --- a/beacon_chain/el/el_manager.nim +++ b/beacon_chain/el/el_manager.nim @@ -1402,6 +1402,7 @@ proc exchangeConfigWithSingleEL(m: ELManager, connection: ELConnection) {.async. of rinkeby: 4.Quantity of goerli: 5.Quantity of sepolia: 11155111.Quantity # https://chainid.network/ + of holesky: 17000.Quantity if expectedChain != providerChain: warn "The specified EL client is connected to a different chain", url = connection.engineUrl, diff --git a/beacon_chain/networking/network_metadata.nim b/beacon_chain/networking/network_metadata.nim index ebe61fab3..18dd422ad 100644 --- a/beacon_chain/networking/network_metadata.nim +++ b/beacon_chain/networking/network_metadata.nim @@ -13,7 +13,7 @@ import web3/[ethtypes, conversions], chronicles, eth/common/eth_types_json_serialization, - ../spec/eth2_ssz_serialization + ../spec/[eth2_ssz_serialization, forks] # TODO(zah): # We can compress the embedded states with snappy before embedding them here. @@ -45,6 +45,29 @@ type rinkeby goerli 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 case incompatible*: bool @@ -62,22 +85,13 @@ type depositContractBlock*: uint64 depositContractBlockHash*: Eth2Digest - # `genesisData` will have `len == 0` for networks with a still - # unknown genesis state. - when incbinEnabled: - genesisData*: seq[byte] - else: - genesisData*: string - + genesis*: GenesisMetadata genesisDepositsSnapshot*: string else: incompatibilityDesc*: string -template genesisBytes*(metadata: Eth2NetworkMetadata): auto = - when incbinEnabled: - metadata.genesisData - else: - metadata.genesisData.toOpenArrayByte(0, metadata.genesisData.high) +func hasGenesis*(metadata: Eth2NetworkMetadata): bool = + metadata.genesis.kind != NoGenesis proc readBootstrapNodes*(path: string): seq[string] {.raises: [IOError].} = # 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*( - path: string, eth1Network = none(Eth1Network), loadGenesis = true): + path: string, + eth1Network = none(Eth1Network), + isCompileTime = false, + downloadGenesisFrom = none(DownloadInfo), + useBakedInGenesis = none(string)): Eth2NetworkMetadata {.raises: [CatchableError].} = # Load data in eth2-networks format # https://github.com/eth-clients/eth2-networks @@ -166,11 +184,6 @@ proc loadEth2NetworkMetadata*( readBootstrapNodes(bootstrapNodesPath) & readBootEnr(bootEnrPath)) - genesisData = if loadGenesis and fileExists(genesisPath): - readFile(genesisPath) - else: - "" - genesisDepositsSnapshot = if fileExists(genesisDepositsSnapshotPath): readFile(genesisDepositsSnapshotPath) else: @@ -183,9 +196,18 @@ proc loadEth2NetworkMetadata*( bootstrapNodes: bootstrapNodes, depositContractBlock: depositContractBlock, depositContractBlockHash: depositContractBlockHash, - genesisData: - when incbinEnabled: toBytes genesisData - else: genesisData, + genesis: + if downloadGenesisFrom.isSome: + 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) except PresetIncompatibleError as err: @@ -195,10 +217,14 @@ proc loadEth2NetworkMetadata*( proc loadCompileTimeNetworkMetadata( path: string, eth1Network = none(Eth1Network), - loadGenesis = true): Eth2NetworkMetadata {.raises: [].} = + useBakedInGenesis = none(string), + downloadGenesisFrom = none(DownloadInfo)): Eth2NetworkMetadata {.raises: [].} = if fileExists(path & "/config.yaml"): try: - result = loadEth2NetworkMetadata(path, eth1Network, loadGenesis) + result = loadEth2NetworkMetadata(path, eth1Network, + isCompileTime = true, + downloadGenesisFrom = downloadGenesisFrom, + useBakedInGenesis = useBakedInGenesis) if result.incompatible: macros.error "The current build is misconfigured. " & "Attempt to load an incompatible network metadata: " & @@ -209,27 +235,36 @@ proc loadCompileTimeNetworkMetadata( macros.error "config.yaml not found for network '" & path when const_preset == "gnosis": - import stew/assign2 - when incbinEnabled: let - gnosisGenesis {.importc: "gnosis_mainnet_genesis".}: ptr UncheckedArray[byte] - gnosisGenesisSize {.importc: "gnosis_mainnet_genesis_size".}: int + gnosisGenesis* {.importc: "gnosis_mainnet_genesis".}: ptr UncheckedArray[byte] + gnosisGenesisSize* {.importc: "gnosis_mainnet_genesis_size".}: int - chiadoGenesis {.importc: "gnosis_chiado_genesis".}: ptr UncheckedArray[byte] - chiadoGenesisSize {.importc: "gnosis_chiado_genesis_size".}: int + chiadoGenesis* {.importc: "gnosis_chiado_genesis".}: ptr UncheckedArray[byte] + chiadoGenesisSize* {.importc: "gnosis_chiado_genesis_size".}: int # let `.incbin` in assembly file find the binary file through search path {.passc: "-I" & vendorDir.} {.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 gnosisMetadata = loadCompileTimeNetworkMetadata( vendorDir & "/gnosis-chain-configs/mainnet", - none(Eth1Network), not incbinEnabled) + none(Eth1Network), + useBakedInGenesis = some "gnosis") + chiadoMetadata = loadCompileTimeNetworkMetadata( vendorDir & "/gnosis-chain-configs/chiado", - none(Eth1Network), not incbinEnabled) + none(Eth1Network), + useBakedInGenesis = some "chiado") static: for network in [gnosisMetadata, chiadoMetadata]: @@ -242,38 +277,62 @@ when const_preset == "gnosis": doAssert network.cfg.DENEB_FORK_EPOCH == FAR_FUTURE_EPOCH elif const_preset == "mainnet": - import stew/assign2 - when incbinEnabled: # Nim is very inefficent at loading large constants from binary files so we # use this trick instead which saves significant amounts of compile time let - mainnetGenesis {.importc: "eth2_mainnet_genesis".}: ptr UncheckedArray[byte] - mainnetGenesisSize {.importc: "eth2_mainnet_genesis_size".}: int + mainnetGenesis* {.importc: "eth2_mainnet_genesis".}: ptr UncheckedArray[byte] + mainnetGenesisSize* {.importc: "eth2_mainnet_genesis_size".}: int - praterGenesis {.importc: "eth2_goerli_genesis".}: ptr UncheckedArray[byte] - praterGenesisSize {.importc: "eth2_goerli_genesis_size".}: int + praterGenesis* {.importc: "eth2_goerli_genesis".}: ptr UncheckedArray[byte] + praterGenesisSize* {.importc: "eth2_goerli_genesis_size".}: int - sepoliaGenesis {.importc: "eth2_sepolia_genesis".}: ptr UncheckedArray[byte] - sepoliaGenesisSize {.importc: "eth2_sepolia_genesis_size".}: int + sepoliaGenesis* {.importc: "eth2_sepolia_genesis".}: ptr UncheckedArray[byte] + sepoliaGenesisSize* {.importc: "eth2_sepolia_genesis_size".}: int # let `.incbin` in assembly file find the binary file through search path {.passc: "-I" & vendorDir.} {.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 mainnetMetadata = loadCompileTimeNetworkMetadata( - vendorDir & "/eth2-networks/shared/mainnet", some mainnet, not incbinEnabled) + vendorDir & "/eth2-networks/shared/mainnet", + some mainnet, + useBakedInGenesis = some "mainnet") + 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( - vendorDir & "/sepolia/bepolia", some sepolia, not incbinEnabled) + vendorDir & "/sepolia/bepolia", + some sepolia, + useBakedInGenesis = some "sepolia") static: - for network in [mainnetMetadata, praterMetadata, sepoliaMetadata]: + for network in [mainnetMetadata, praterMetadata, sepoliaMetadata, holeskyMetadata]: 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.BELLATRIX_FORK_EPOCH < FAR_FUTURE_EPOCH doAssert network.cfg.CAPELLA_FORK_EPOCH < FAR_FUTURE_EPOCH @@ -295,40 +354,30 @@ proc getMetadataForNetwork*( if networkName == "ropsten": 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 = when const_preset == "gnosis": case toLowerAscii(networkName) of "gnosis": - withGenesis(gnosisMetadata, gnosisGenesis) + gnosisMetadata of "gnosis-chain": warn "`--network:gnosis-chain` is deprecated, " & "use `--network:gnosis` instead" - withGenesis(gnosisMetadata, gnosisGenesis) + gnosisMetadata of "chiado": - withGenesis(chiadoMetadata, chiadoGenesis) + chiadoMetadata else: loadRuntimeMetadata() elif const_preset == "mainnet": case toLowerAscii(networkName) of "mainnet": - withGenesis(mainnetMetadata, mainnetGenesis) + mainnetMetadata of "prater", "goerli": - withGenesis(praterMetadata, praterGenesis) + praterMetadata + of "holesky": + holeskyMetadata of "sepolia": - withGenesis(sepoliaMetadata, sepoliaGenesis) + sepoliaMetadata else: loadRuntimeMetadata() @@ -373,3 +422,67 @@ proc getRuntimeConfig*( of true: # `getMetadataForNetwork` / `loadCompileTimeNetworkMetadata` 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 diff --git a/beacon_chain/networking/network_metadata_downloads.nim b/beacon_chain/networking/network_metadata_downloads.nim new file mode 100644 index 000000000..e3520de24 --- /dev/null +++ b/beacon_chain/networking/network_metadata_downloads.nim @@ -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") diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index 663efdcd0..7997f978c 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -15,7 +15,7 @@ import eth/p2p/discoveryv5/[enr, random2], ./consensus_object_pools/blob_quarantine, ./consensus_object_pools/vanity_logs/vanity_logs, - ./networking/topic_params, + ./networking/[topic_params, network_metadata_downloads], ./rpc/[rest_api, state_ttl_cache], ./spec/datatypes/[altair, bellatrix, phase0], ./spec/[deposit_snapshots, engine_authentication, weak_subjectivity], @@ -462,8 +462,8 @@ const proc init*(T: type BeaconNode, rng: ref HmacDrbgContext, config: BeaconNodeConf, - metadata: Eth2NetworkMetadata): BeaconNode - {.raises: [CatchableError].} = + metadata: Eth2NetworkMetadata): Future[BeaconNode] + {.async, raises: [CatchableError].} = var taskpool: TaskPoolPtr template cfg: auto = metadata.cfg @@ -541,18 +541,31 @@ proc init*(T: type BeaconNode, if engineApiUrls.len == 0: notice "Running without execution client - validator features disabled (see https://nimbus.guide/eth1.html)" - var genesisState = - 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 + var networkGenesisValidatorsRoot = metadata.bakedGenesisValidatorsRoot 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: fatal "No database and no genesis snapshot found. Please supply a genesis.ssz " & "with the network configuration" @@ -573,6 +586,8 @@ proc init*(T: type BeaconNode, # answering genesis queries if not genesisState.isNil: ChainDAGRef.preInit(db, genesisState[]) + networkGenesisValidatorsRoot = + Opt.some(getStateField(genesisState[], genesis_validators_root)) if not checkpointState.isNil: if genesisState.isNil or @@ -605,12 +620,6 @@ proc init*(T: type BeaconNode, validatorMonitor[].addMonitor(key, Opt.none(ValidatorIndex)) let - networkGenesisValidatorsRoot = - if not genesisState.isNil: - Opt.some(getStateField(genesisState[], genesis_validators_root)) - else: - Opt.none(Eth2Digest) - dag = loadChainDag( config, cfg, db, eventBus, validatorMonitor, networkGenesisValidatorsRoot) @@ -1893,7 +1902,7 @@ proc doRunBeaconNode(config: var BeaconNodeConf, rng: ref HmacDrbgContext) {.rai bnStatus = BeaconNodeStatus.Stopping 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: let res = @@ -2042,8 +2051,14 @@ proc handleStartUpCmd(config: var BeaconNodeConf) {.raises: [CatchableError].} = kind: TrustedNodeSyncKind.StateId, stateId: "finalized") genesis = - if network.genesisData.len > 0: - newClone(readSszForkedHashedBeaconState(cfg, network.genesisBytes)) + if network.hasGenesis: + 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 if config.blockId.isSome(): diff --git a/beacon_chain/nimbus_light_client.nim b/beacon_chain/nimbus_light_client.nim index 2ab4eb52a..18d50c6d4 100644 --- a/beacon_chain/nimbus_light_client.nim +++ b/beacon_chain/nimbus_light_client.nim @@ -11,7 +11,7 @@ import eth/db/kvstore_sqlite3, ./el/el_manager, ./gossip_processing/optimistic_processor, - ./networking/[topic_params, network_metadata], + ./networking/[topic_params, network_metadata_downloads], ./spec/beaconstate, ./spec/datatypes/[phase0, altair, bellatrix, capella, deneb], "."/[filepath, light_client, light_client_db, nimbus_binary_common, version] @@ -63,9 +63,15 @@ programMain: template cfg(): auto = metadata.cfg 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 = try: - newClone(readSszForkedHashedBeaconState(cfg, metadata.genesisBytes)) + newClone(readSszForkedHashedBeaconState(cfg, genesisBytes)) except CatchableError as err: raiseAssert "Invalid baked-in state: " & err.msg diff --git a/beacon_chain/rpc/rest_config_api.nim b/beacon_chain/rpc/rest_config_api.nim index f8365cd4e..15884b39e 100644 --- a/beacon_chain/rpc/rest_config_api.nim +++ b/beacon_chain/rpc/rest_config_api.nim @@ -138,7 +138,7 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) = TERMINAL_BLOCK_HASH: $cfg.TERMINAL_BLOCK_HASH, 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: Base10.toString(cfg.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT), MIN_GENESIS_TIME: diff --git a/beacon_chain/spec/datatypes/constants.nim b/beacon_chain/spec/datatypes/constants.nim index 299c29812..d0f6259af 100644 --- a/beacon_chain/spec/datatypes/constants.nim +++ b/beacon_chain/spec/datatypes/constants.nim @@ -57,9 +57,6 @@ const # 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]) - # 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 PROPOSER_SCORE_BOOST*: uint64 = 40 diff --git a/beacon_chain/spec/forks.nim b/beacon_chain/spec/forks.nim index a27e29c97..a5744202c 100644 --- a/beacon_chain/spec/forks.nim +++ b/beacon_chain/spec/forks.nim @@ -981,10 +981,10 @@ func getForkSchedule*(cfg: RuntimeConfig): array[5, Fork] = type # The first few fields of a state, shared across all forks - BeaconStateHeader = object - genesis_time: uint64 - genesis_validators_root: Eth2Digest - slot: Slot + BeaconStateHeader* = object + genesis_time*: uint64 + genesis_validators_root*: Eth2Digest + slot*: Slot func readSszForkedHashedBeaconState*( consensusFork: ConsensusFork, data: openArray[byte]): diff --git a/beacon_chain/spec/presets.nim b/beacon_chain/spec/presets.nim index 277d017b5..b058a872d 100644 --- a/beacon_chain/spec/presets.nim +++ b/beacon_chain/spec/presets.nim @@ -76,6 +76,9 @@ type DEPOSIT_NETWORK_ID*: uint64 DEPOSIT_CONTRACT_ADDRESS*: Eth1Address + # Not actively used, but part of the spec + TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH*: Epoch + PresetFile* = object values*: Table[string, string] missingValues*: seq[string] @@ -118,6 +121,7 @@ when const_preset == "mainnet": # * 'prater' - testnet # * 'ropsten' - testnet # * 'sepolia' - testnet + # * 'holesky' - testnet # Must match the regex: [a-z0-9\-] CONFIG_NAME: "", @@ -221,6 +225,7 @@ elif const_preset == "gnosis": # * 'prater' - testnet # * 'ropsten' - testnet # * 'sepolia' - testnet + # * 'holesky' - testnet # Must match the regex: [a-z0-9\-] CONFIG_NAME: "", @@ -319,6 +324,7 @@ elif const_preset == "minimal": # * 'prater' - testnet # * 'ropsten' - testnet # * 'sepolia' - testnet + # * 'holesky' - testnet # Must match the regex: [a-z0-9\-] CONFIG_NAME: "minimal", @@ -586,9 +592,6 @@ proc readRuntimeConfig*( checkCompatibility BLOB_SIDECAR_SUBNET_COUNT 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 checkCompatibility PROPOSER_SCORE_BOOST diff --git a/docs/e2store.md b/docs/e2store.md index b145ddc5d..725fda503 100644 --- a/docs/e2store.md +++ b/docs/e2store.md @@ -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: `---.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 * `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` diff --git a/tests/test_keymanager_api.nim b/tests/test_keymanager_api.nim index b1a6a7067..67799e771 100644 --- a/tests/test_keymanager_api.nim +++ b/tests/test_keymanager_api.nim @@ -301,7 +301,7 @@ proc startBeaconNode(basePort: int) {.raises: [CatchableError].} = let 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 # setting its `bnStatus` to `Stopping`. diff --git a/tests/test_network_metadata.nim b/tests/test_network_metadata.nim index ad4e4f660..6ab46cbd3 100644 --- a/tests/test_network_metadata.nim +++ b/tests/test_network_metadata.nim @@ -17,7 +17,7 @@ template checkRoot(name, root) = metadata = getMetadataForNetwork(name) cfg = metadata.cfg state = newClone(readSszForkedHashedBeaconState( - metadata.cfg, metadata.genesisBytes)) + metadata.cfg, metadata.genesis.bakedBytes)) check: $getStateRoot(state[]) == root diff --git a/vendor/holesky b/vendor/holesky new file mode 160000 index 000000000..f1ad227a2 --- /dev/null +++ b/vendor/holesky @@ -0,0 +1 @@ +Subproject commit f1ad227a2511ea26f5d043fad15d9431fd681941 diff --git a/vendor/nim-chronos b/vendor/nim-chronos index 6c2ea6751..176d462b0 160000 --- a/vendor/nim-chronos +++ b/vendor/nim-chronos @@ -1 +1 @@ -Subproject commit 6c2ea675123ed0bf5c5d76c92ed4985bacd1a9ec +Subproject commit 176d462b076db24d9f71ddb40163d1ef82823771