zah 8771e91d53
Support for driving multiple EL nodes from a single Nimbus BN (#4465)
* Support for driving multiple EL nodes from a single Nimbus BN

Full list of changes:

* Eth1Monitor has been renamed to ELManager to match its current
  responsibilities better.

* The ELManager is no longer optional in the code (it won't have
  a nil value under any circumstances).

* The support for subscribing for headers was removed as it only
  worked with WebSockets and contributed significant complexity
  while bringing only a very minor advantage.

* The `--web3-url` parameter has been deprecated in favor of a
  new `--el` parameter. The new parameter has a reasonable default
  value and supports specifying a different JWT for each connection.
  Each connection can also be configured with a different set of
  responsibilities (e.g. download deposits, validate blocks and/or
  produce blocks). On the command-line, these properties can be
  configured through URL properties stored in the #anchor part of
  the URL. In TOML files, they come with a very natural syntax
  (althrough the URL scheme is also supported).

* The previously scattered EL-related state and logic is now moved
  to `eth1_monitor.nim` (this module will be renamed to `el_manager.nim`
  in a follow-up commit). State is assigned properly either to the
  `ELManager` or the to individual `ELConnection` objects where
  appropriate.

  The ELManager executes all Engine API requests against all attached
  EL nodes, in parallel. It compares their results and if there is a
  disagreement regarding the validity of a certain payload, this is
  detected and the beacon node is protected from publishing a block
  with a potential execution layer consensus bug in it.

  The BN provides metrics per EL node for the number of successful or
  failed requests for each type Engine API requests. If an EL node
  goes offline and connectivity is resoted later, we report the
  problem and the remedy in edge-triggered fashion.

* More progress towards implementing Deneb block production in the VC
  and comparing the value of blocks produced by the EL and the builder
  API.

* Adds a Makefile target for the zhejiang testnet
2023-03-05 01:40:21 +00:00

1031 lines
40 KiB
Nim

# beacon_chain
# Copyright (c) 2021-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.
{.push raises: [].}
import
std/macros,
stew/assign2,
stew/results,
chronicles,
../extras,
"."/[
block_id, eth2_merkleization, eth2_ssz_serialization,
forks_light_client, presets],
./datatypes/[phase0, altair, bellatrix, capella, deneb],
./mev/bellatrix_mev, ./mev/capella_mev
export
extras, block_id, phase0, altair, bellatrix, capella, deneb,
eth2_merkleization, eth2_ssz_serialization, forks_light_client,
presets, bellatrix_mev, capella_mev
# This file contains helpers for dealing with forks - we have two ways we can
# deal with forks:
# * generics - this means using the static typing and differentiating forks
# at compile time - this is preferred in fork-specific code where the fork
# is known up-front, for example spec functions.
# * variants - this means using a variant object and determining the fork at
# runtime - this carries the obvious risk and complexity of dealing with
# runtime checking, but is of course needed for external data that may be
# of any fork kind.
#
# For generics, we define `Forky*` type classes that cover "similar" objects
# across forks - for variants, they're called `Forked*` instead.
# See withXxx and `init` for convenient ways of moving between these two worlds.
# A clever programmer would use templates, macros and dark magic to create all
# these types and converters :)
type
ConsensusFork* {.pure.} = enum
Phase0,
Altair,
Bellatrix,
Capella,
Deneb
ForkyBeaconState* =
phase0.BeaconState |
altair.BeaconState |
bellatrix.BeaconState |
capella.BeaconState |
deneb.BeaconState
ForkyHashedBeaconState* =
phase0.HashedBeaconState |
altair.HashedBeaconState |
bellatrix.HashedBeaconState |
capella.HashedBeaconState |
deneb.HashedBeaconState
ForkedHashedBeaconState* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.HashedBeaconState
of ConsensusFork.Altair: altairData*: altair.HashedBeaconState
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.HashedBeaconState
of ConsensusFork.Capella: capellaData*: capella.HashedBeaconState
of ConsensusFork.Deneb: denebData*: deneb.HashedBeaconState
ForkyExecutionPayload* =
bellatrix.ExecutionPayload |
capella.ExecutionPayload |
deneb.ExecutionPayload
ForkyExecutionPayloadHeader* =
bellatrix.ExecutionPayloadHeader |
capella.ExecutionPayloadHeader |
deneb.ExecutionPayloadHeader
ForkyBeaconBlockBody* =
phase0.BeaconBlockBody |
altair.BeaconBlockBody |
bellatrix.BeaconBlockBody |
capella.BeaconBlockBody |
deneb.BeaconBlockBody
ForkySigVerifiedBeaconBlockBody* =
phase0.SigVerifiedBeaconBlockBody |
altair.SigVerifiedBeaconBlockBody |
bellatrix.SigVerifiedBeaconBlockBody |
capella.SigVerifiedBeaconBlockBody |
deneb.SigVerifiedBeaconBlockBody
ForkyTrustedBeaconBlockBody* =
phase0.TrustedBeaconBlockBody |
altair.TrustedBeaconBlockBody |
bellatrix.TrustedBeaconBlockBody |
capella.TrustedBeaconBlockBody |
deneb.TrustedBeaconBlockBody
SomeForkyBeaconBlockBody* =
ForkyBeaconBlockBody |
ForkySigVerifiedBeaconBlockBody |
ForkyTrustedBeaconBlockBody
ForkyBeaconBlock* =
phase0.BeaconBlock |
altair.BeaconBlock |
bellatrix.BeaconBlock |
capella.BeaconBlock |
deneb.BeaconBlock
ForkySigVerifiedBeaconBlock* =
phase0.SigVerifiedBeaconBlock |
altair.SigVerifiedBeaconBlock |
bellatrix.SigVerifiedBeaconBlock |
capella.SigVerifiedBeaconBlock |
deneb.SigVerifiedBeaconBlock
ForkyTrustedBeaconBlock* =
phase0.TrustedBeaconBlock |
altair.TrustedBeaconBlock |
bellatrix.TrustedBeaconBlock |
capella.TrustedBeaconBlock |
deneb.TrustedBeaconBlock
SomeForkyBeaconBlock* =
ForkyBeaconBlock |
ForkySigVerifiedBeaconBlock |
ForkyTrustedBeaconBlock
ForkyExecutionPayloadForSigning* =
bellatrix.ExecutionPayloadForSigning |
capella.ExecutionPayloadForSigning |
deneb.ExecutionPayloadForSigning
ForkedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.BeaconBlock
of ConsensusFork.Altair: altairData*: altair.BeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.BeaconBlock
of ConsensusFork.Capella: capellaData*: capella.BeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.BeaconBlock
Web3SignerForkedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.BeaconBlock
of ConsensusFork.Altair: altairData*: altair.BeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: BeaconBlockHeader
of ConsensusFork.Capella: capellaData*: BeaconBlockHeader
of ConsensusFork.Deneb: denebData*: BeaconBlockHeader
ForkedBlindedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.BeaconBlock
of ConsensusFork.Altair: altairData*: altair.BeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix_mev.BlindedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella_mev.BlindedBeaconBlock
of ConsensusFork.Deneb: denebData*: capella_mev.BlindedBeaconBlock
ForkedTrustedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.TrustedBeaconBlock
of ConsensusFork.Altair: altairData*: altair.TrustedBeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.TrustedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.TrustedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.TrustedBeaconBlock
ForkySignedBeaconBlock* =
phase0.SignedBeaconBlock |
altair.SignedBeaconBlock |
bellatrix.SignedBeaconBlock |
capella.SignedBeaconBlock |
deneb.SignedBeaconBlock
ForkedSignedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
of ConsensusFork.Altair: altairData*: altair.SignedBeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.SignedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.SignedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.SignedBeaconBlock
ForkySignedBlindedBeaconBlock* =
phase0.SignedBeaconBlock |
altair.SignedBeaconBlock |
bellatrix_mev.SignedBlindedBeaconBlock |
capella_mev.SignedBlindedBeaconBlock
ForkedSignedBlindedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
of ConsensusFork.Altair: altairData*: altair.SignedBeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix_mev.SignedBlindedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella_mev.SignedBlindedBeaconBlock
of ConsensusFork.Deneb: denebData*: capella_mev.SignedBlindedBeaconBlock
ForkySigVerifiedSignedBeaconBlock* =
phase0.SigVerifiedSignedBeaconBlock |
altair.SigVerifiedSignedBeaconBlock |
bellatrix.SigVerifiedSignedBeaconBlock |
capella.SigVerifiedSignedBeaconBlock |
deneb.SigVerifiedSignedBeaconBlock
ForkyMsgTrustedSignedBeaconBlock* =
phase0.MsgTrustedSignedBeaconBlock |
altair.MsgTrustedSignedBeaconBlock |
bellatrix.MsgTrustedSignedBeaconBlock |
capella.MsgTrustedSignedBeaconBlock |
deneb.MsgTrustedSignedBeaconBlock
ForkyTrustedSignedBeaconBlock* =
phase0.TrustedSignedBeaconBlock |
altair.TrustedSignedBeaconBlock |
bellatrix.TrustedSignedBeaconBlock |
capella.TrustedSignedBeaconBlock |
deneb.TrustedSignedBeaconBlock
ForkedMsgTrustedSignedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.MsgTrustedSignedBeaconBlock
of ConsensusFork.Altair: altairData*: altair.MsgTrustedSignedBeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.MsgTrustedSignedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.MsgTrustedSignedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.MsgTrustedSignedBeaconBlock
ForkedTrustedSignedBeaconBlock* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.TrustedSignedBeaconBlock
of ConsensusFork.Altair: altairData*: altair.TrustedSignedBeaconBlock
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.TrustedSignedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.TrustedSignedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.TrustedSignedBeaconBlock
SomeForkySignedBeaconBlock* =
ForkySignedBeaconBlock |
ForkySigVerifiedSignedBeaconBlock |
ForkyMsgTrustedSignedBeaconBlock |
ForkyTrustedSignedBeaconBlock
EpochInfoFork* {.pure.} = enum
Phase0
Altair
ForkedEpochInfo* = object
case kind*: EpochInfoFork
of EpochInfoFork.Phase0: phase0Data*: phase0.EpochInfo
of EpochInfoFork.Altair: altairData*: altair.EpochInfo
ForkyEpochInfo* = phase0.EpochInfo | altair.EpochInfo
ForkDigests* = object
phase0*: ForkDigest
altair*: ForkDigest
bellatrix*: ForkDigest
capella*: ForkDigest
eip4844*: ForkDigest
macro getSymbolFromForkModule(fork: static ConsensusFork,
symbolName: static string): untyped =
let moduleName = case fork
of ConsensusFork.Phase0: "phase0"
of ConsensusFork.Altair: "altair"
of ConsensusFork.Bellatrix: "bellatrix"
of ConsensusFork.Capella: "capella"
of ConsensusFork.Deneb: "deneb"
newDotExpr(ident moduleName, ident symbolName)
template BeaconStateType*(fork: static ConsensusFork): auto =
getSymbolFromForkModule(fork, "BeaconState")
template BeaconBlockType*(fork: static ConsensusFork): auto =
getSymbolFromForkModule(fork, "BeaconBlock")
template BeaconBlockBodyType*(fork: static ConsensusFork): auto =
getSymbolFromForkModule(fork, "BeaconBlockBody")
template withStateFork*(
x: ConsensusFork, body: untyped): untyped =
case x
of ConsensusFork.Deneb:
const stateFork {.inject, used.} = ConsensusFork.Deneb
body
of ConsensusFork.Capella:
const stateFork {.inject, used.} = ConsensusFork.Capella
body
of ConsensusFork.Bellatrix:
const stateFork {.inject, used.} = ConsensusFork.Bellatrix
body
of ConsensusFork.Altair:
const stateFork {.inject, used.} = ConsensusFork.Altair
body
of ConsensusFork.Phase0:
const stateFork {.inject, used.} = ConsensusFork.Phase0
body
# TODO when https://github.com/nim-lang/Nim/issues/21086 fixed, use return type
# `ref T`
func new*(T: type ForkedHashedBeaconState, data: phase0.BeaconState):
ref ForkedHashedBeaconState =
(ref T)(kind: ConsensusFork.Phase0, phase0Data: phase0.HashedBeaconState(
data: data, root: hash_tree_root(data)))
func new*(T: type ForkedHashedBeaconState, data: altair.BeaconState):
ref ForkedHashedBeaconState =
(ref T)(kind: ConsensusFork.Altair, altairData: altair.HashedBeaconState(
data: data, root: hash_tree_root(data)))
func new*(T: type ForkedHashedBeaconState, data: bellatrix.BeaconState):
ref ForkedHashedBeaconState =
(ref T)(kind: ConsensusFork.Bellatrix, bellatrixData: bellatrix.HashedBeaconState(
data: data, root: hash_tree_root(data)))
func new*(T: type ForkedHashedBeaconState, data: capella.BeaconState):
ref ForkedHashedBeaconState =
(ref T)(kind: ConsensusFork.Capella, capellaData: capella.HashedBeaconState(
data: data, root: hash_tree_root(data)))
func new*(T: type ForkedHashedBeaconState, data: deneb.BeaconState):
ref ForkedHashedBeaconState =
(ref T)(kind: ConsensusFork.Deneb, denebData: deneb.HashedBeaconState(
data: data, root: hash_tree_root(data)))
template init*(T: type ForkedBeaconBlock, blck: phase0.BeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
template init*(T: type ForkedBeaconBlock, blck: altair.BeaconBlock): T =
T(kind: ConsensusFork.Altair, altairData: blck)
template init*(T: type ForkedBeaconBlock, blck: bellatrix.BeaconBlock): T =
T(kind: ConsensusFork.Bellatrix, bellatrixData: blck)
template init*(T: type ForkedBeaconBlock, blck: capella.BeaconBlock): T =
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedBeaconBlock, blck: deneb.BeaconBlock): T =
T(kind: ConsensusFork.Deneb, denebData: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: phase0.TrustedBeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: altair.TrustedBeaconBlock): T =
T(kind: ConsensusFork.Altair, altairData: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: bellatrix.TrustedBeaconBlock): T =
T(kind: ConsensusFork.Bellatrix, bellatrixData: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: capella.TrustedBeaconBlock): T =
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: phase0.SignedBeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: altair.SignedBeaconBlock): T =
T(kind: ConsensusFork.Altair, altairData: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: bellatrix.SignedBeaconBlock): T =
T(kind: ConsensusFork.Bellatrix, bellatrixData: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: capella.SignedBeaconBlock): T =
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: deneb.SignedBeaconBlock): T =
T(kind: ConsensusFork.Deneb, denebData: blck)
func init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
blockRoot: Eth2Digest, signature: ValidatorSig): T =
case forked.kind
of ConsensusFork.Phase0:
T(kind: ConsensusFork.Phase0,
phase0Data: phase0.SignedBeaconBlock(message: forked.phase0Data,
root: blockRoot,
signature: signature))
of ConsensusFork.Altair:
T(kind: ConsensusFork.Altair,
altairData: altair.SignedBeaconBlock(message: forked.altairData,
root: blockRoot,
signature: signature))
of ConsensusFork.Bellatrix:
T(kind: ConsensusFork.Bellatrix,
bellatrixData: bellatrix.SignedBeaconBlock(message: forked.bellatrixData,
root: blockRoot,
signature: signature))
of ConsensusFork.Capella:
T(kind: ConsensusFork.Capella,
capellaData: capella.SignedBeaconBlock(message: forked.capellaData,
root: blockRoot,
signature: signature))
of ConsensusFork.Deneb:
T(kind: ConsensusFork.Deneb,
denebData: deneb.SignedBeaconBlock(message: forked.denebData,
root: blockRoot,
signature: signature))
func init*(T: type ForkedSignedBlindedBeaconBlock,
forked: ForkedBlindedBeaconBlock, blockRoot: Eth2Digest,
signature: ValidatorSig): T =
case forked.kind
of ConsensusFork.Phase0:
T(kind: ConsensusFork.Phase0,
phase0Data: phase0.SignedBeaconBlock(message: forked.phase0Data,
root: blockRoot,
signature: signature))
of ConsensusFork.Altair:
T(kind: ConsensusFork.Altair,
altairData: altair.SignedBeaconBlock(message: forked.altairData,
root: blockRoot,
signature: signature))
of ConsensusFork.Bellatrix:
T(kind: ConsensusFork.Bellatrix,
bellatrixData: bellatrix_mev.SignedBlindedBeaconBlock(message: forked.bellatrixData,
signature: signature))
of ConsensusFork.Capella:
T(kind: ConsensusFork.Capella,
capellaData: capella_mev.SignedBlindedBeaconBlock(message: forked.capellaData,
signature: signature))
of ConsensusFork.Deneb:
discard $denebImplementationMissing & "forks.nim:init(T: type ForkedSignedBlindedBeaconBlock)"
T(kind: ConsensusFork.Deneb,
denebData: capella_mev.SignedBlindedBeaconBlock(message: forked.denebData,
signature: signature))
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: phase0.MsgTrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: altair.MsgTrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Altair, altairData: blck)
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: bellatrix.MsgTrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Bellatrix, bellatrixData: blck)
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: capella.MsgTrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: deneb.MsgTrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Deneb, eip4844Data: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: phase0.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: altair.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Altair, altairData: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: bellatrix.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Bellatrix, bellatrixData: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: capella.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: deneb.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Deneb, denebData: blck)
template toString*(kind: ConsensusFork): string =
case kind
of ConsensusFork.Phase0:
"phase0"
of ConsensusFork.Altair:
"altair"
of ConsensusFork.Bellatrix:
"bellatrix"
of ConsensusFork.Capella:
"capella"
of ConsensusFork.Deneb:
"deneb"
template toString*(kind: ConsensusFork): string =
case kind
of ConsensusFork.Phase0:
"phase0"
of ConsensusFork.Altair:
"altair"
of ConsensusFork.Bellatrix:
"bellatrix"
of ConsensusFork.Capella:
"capella"
of ConsensusFork.Deneb:
"deneb"
template toFork*[T:
phase0.BeaconState |
phase0.HashedBeaconState |
phase0.BeaconBlock |
phase0.SignedBeaconBlock |
phase0.TrustedBeaconBlock |
phase0.SigVerifiedSignedBeaconBlock |
phase0.MsgTrustedSignedBeaconBlock |
phase0.TrustedSignedBeaconBlock](
t: type T): ConsensusFork =
ConsensusFork.Phase0
template toFork*[T:
altair.BeaconState |
altair.HashedBeaconState |
altair.BeaconBlock |
altair.SignedBeaconBlock |
altair.TrustedBeaconBlock |
altair.SigVerifiedSignedBeaconBlock |
altair.MsgTrustedSignedBeaconBlock |
altair.TrustedSignedBeaconBlock](
t: type T): ConsensusFork =
ConsensusFork.Altair
template toFork*[T:
bellatrix.BeaconState |
bellatrix.HashedBeaconState |
bellatrix.ExecutionPayload |
bellatrix.ExecutionPayloadForSigning |
bellatrix.ExecutionPayloadHeader |
bellatrix.BeaconBlock |
bellatrix.SignedBeaconBlock |
bellatrix.TrustedBeaconBlock |
bellatrix.SigVerifiedSignedBeaconBlock |
bellatrix.MsgTrustedSignedBeaconBlock |
bellatrix.TrustedSignedBeaconBlock](
t: type T): ConsensusFork =
ConsensusFork.Bellatrix
template toFork*[T:
capella.BeaconState |
capella.HashedBeaconState |
capella.ExecutionPayload |
capella.ExecutionPayloadForSigning |
capella.ExecutionPayloadHeader |
capella.BeaconBlock |
capella.SignedBeaconBlock |
capella.TrustedBeaconBlock |
capella.SigVerifiedSignedBeaconBlock |
capella.MsgTrustedSignedBeaconBlock |
capella.TrustedSignedBeaconBlock](
t: type T): ConsensusFork =
ConsensusFork.Capella
template toFork*[T:
deneb.BeaconState |
deneb.HashedBeaconState |
deneb.ExecutionPayload |
deneb.ExecutionPayloadForSigning |
deneb.ExecutionPayloadHeader |
deneb.BeaconBlock |
deneb.SignedBeaconBlock |
deneb.TrustedBeaconBlock |
deneb.SigVerifiedSignedBeaconBlock |
deneb.MsgTrustedSignedBeaconBlock |
deneb.TrustedSignedBeaconBlock](
t: type T): ConsensusFork =
ConsensusFork.Deneb
template init*(T: type ForkedEpochInfo, info: phase0.EpochInfo): T =
T(kind: EpochInfoFork.Phase0, phase0Data: info)
template init*(T: type ForkedEpochInfo, info: altair.EpochInfo): T =
T(kind: EpochInfoFork.Altair, altairData: info)
template withState*(x: ForkedHashedBeaconState, body: untyped): untyped =
case x.kind
of ConsensusFork.Deneb:
const stateFork {.inject, used.} = ConsensusFork.Deneb
template forkyState: untyped {.inject, used.} = x.denebData
body
of ConsensusFork.Capella:
const stateFork {.inject, used.} = ConsensusFork.Capella
template forkyState: untyped {.inject, used.} = x.capellaData
body
of ConsensusFork.Bellatrix:
const stateFork {.inject, used.} = ConsensusFork.Bellatrix
template forkyState: untyped {.inject, used.} = x.bellatrixData
body
of ConsensusFork.Altair:
const stateFork {.inject, used.} = ConsensusFork.Altair
template forkyState: untyped {.inject, used.} = x.altairData
body
of ConsensusFork.Phase0:
const stateFork {.inject, used.} = ConsensusFork.Phase0
template forkyState: untyped {.inject, used.} = x.phase0Data
body
template withEpochInfo*(x: ForkedEpochInfo, body: untyped): untyped =
case x.kind
of EpochInfoFork.Phase0:
const infoFork {.inject.} = EpochInfoFork.Phase0
template info: untyped {.inject.} = x.phase0Data
body
of EpochInfoFork.Altair:
const infoFork {.inject.} = EpochInfoFork.Altair
template info: untyped {.inject.} = x.altairData
body
template withEpochInfo*(
state: phase0.BeaconState, x: var ForkedEpochInfo, body: untyped): untyped =
if x.kind != EpochInfoFork.Phase0:
# Rare, should never happen even, so efficiency a non-issue
x = ForkedEpochInfo(kind: EpochInfoFork.Phase0)
template info: untyped {.inject.} = x.phase0Data
body
template withEpochInfo*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
x: var ForkedEpochInfo, body: untyped): untyped =
if x.kind != EpochInfoFork.Altair:
# Rare, so efficiency not critical
x = ForkedEpochInfo(kind: EpochInfoFork.Altair)
template info: untyped {.inject.} = x.altairData
body
func assign*(tgt: var ForkedHashedBeaconState, src: ForkedHashedBeaconState) =
if tgt.kind == src.kind:
case tgt.kind
of ConsensusFork.Deneb:
assign(tgt.denebData, src.denebData):
of ConsensusFork.Capella:
assign(tgt.capellaData, src.capellaData):
of ConsensusFork.Bellatrix:
assign(tgt.bellatrixData, src.bellatrixData):
of ConsensusFork.Altair:
assign(tgt.altairData, src.altairData):
of ConsensusFork.Phase0:
assign(tgt.phase0Data, src.phase0Data):
else:
# Ensure case object and discriminator get updated simultaneously, even
# with nimOldCaseObjects. This is infrequent.
tgt = src
template getStateField*(x: ForkedHashedBeaconState, y: untyped): untyped =
# The use of `unsafeAddr` avoids excessive copying in certain situations, e.g.,
# ```
# for index, validator in getStateField(stateData.data, validators):
# ```
# Without `unsafeAddr`, the `validators` list would be copied to a temporary variable.
(case x.kind
of ConsensusFork.Deneb: unsafeAddr x.denebData.data.y
of ConsensusFork.Capella: unsafeAddr x.capellaData.data.y
of ConsensusFork.Bellatrix: unsafeAddr x.bellatrixData.data.y
of ConsensusFork.Altair: unsafeAddr x.altairData.data.y
of ConsensusFork.Phase0: unsafeAddr x.phase0Data.data.y)[]
func getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest =
withState(x): forkyState.root
func setStateRoot*(x: var ForkedHashedBeaconState, root: Eth2Digest) =
withState(x): forkyState.root = root
func consensusForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): ConsensusFork =
## Return the current fork for the given epoch.
static:
doAssert high(ConsensusFork) == ConsensusFork.Deneb
doAssert ConsensusFork.Deneb > ConsensusFork.Capella
doAssert ConsensusFork.Capella > ConsensusFork.Bellatrix
doAssert ConsensusFork.Bellatrix > ConsensusFork.Altair
doAssert ConsensusFork.Altair > ConsensusFork.Phase0
doAssert GENESIS_EPOCH == 0
if epoch >= cfg.DENEB_FORK_EPOCH: ConsensusFork.Deneb
elif epoch >= cfg.CAPELLA_FORK_EPOCH: ConsensusFork.Capella
elif epoch >= cfg.BELLATRIX_FORK_EPOCH: ConsensusFork.Bellatrix
elif epoch >= cfg.ALTAIR_FORK_EPOCH: ConsensusFork.Altair
else: ConsensusFork.Phase0
func stateForkForDigest*(
forkDigests: ForkDigests, forkDigest: ForkDigest): Opt[ConsensusFork] =
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
if forkDigest == forkDigests.eip4844:
ok ConsensusFork.Deneb
elif forkDigest == forkDigests.capella:
ok ConsensusFork.Capella
elif forkDigest == forkDigests.bellatrix:
ok ConsensusFork.Bellatrix
elif forkDigest == forkDigests.altair:
ok ConsensusFork.Altair
elif forkDigest == forkDigests.phase0:
ok ConsensusFork.Phase0
else:
err()
func atStateFork*(
forkDigests: ForkDigests, stateFork: ConsensusFork): ForkDigest =
case stateFork
of ConsensusFork.Deneb:
forkDigests.eip4844
of ConsensusFork.Capella:
forkDigests.capella
of ConsensusFork.Bellatrix:
forkDigests.bellatrix
of ConsensusFork.Altair:
forkDigests.altair
of ConsensusFork.Phase0:
forkDigests.phase0
template atEpoch*(
forkDigests: ForkDigests, epoch: Epoch, cfg: RuntimeConfig): ForkDigest =
forkDigests.atStateFork(cfg.consensusForkAtEpoch(epoch))
template asSigned*(
x: ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock
): ForkedSignedBeaconBlock =
isomorphicCast[ForkedSignedBeaconBlock](x)
template asSigned*(
x: ref ForkedMsgTrustedSignedBeaconBlock |
ref ForkedTrustedSignedBeaconBlock
): ref ForkedSignedBeaconBlock =
isomorphicCast[ref ForkedSignedBeaconBlock](x)
template asMsgTrusted*(
x: ForkedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock
): ForkedMsgTrustedSignedBeaconBlock =
isomorphicCast[ForkedMsgTrustedSignedBeaconBlock](x)
template asMsgTrusted*(
x: ref ForkedSignedBeaconBlock |
ref ForkedTrustedSignedBeaconBlock
): ref ForkedMsgTrustedSignedBeaconBlock =
isomorphicCast[ref ForkedMsgTrustedSignedBeaconBlock](x)
template asTrusted*(
x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock
): ForkedTrustedSignedBeaconBlock =
isomorphicCast[ForkedTrustedSignedBeaconBlock](x)
template asTrusted*(
x: ref ForkedSignedBeaconBlock |
ref ForkedMsgTrustedSignedBeaconBlock
): ref ForkedTrustedSignedBeaconBlock =
isomorphicCast[ref ForkedTrustedSignedBeaconBlock](x)
template withBlck*(
x: ForkedBeaconBlock | Web3SignerForkedBeaconBlock |
ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock | ForkedBlindedBeaconBlock |
ForkedSignedBlindedBeaconBlock,
body: untyped): untyped =
case x.kind
of ConsensusFork.Phase0:
const stateFork {.inject, used.} = ConsensusFork.Phase0
template blck: untyped {.inject.} = x.phase0Data
body
of ConsensusFork.Altair:
const stateFork {.inject, used.} = ConsensusFork.Altair
template blck: untyped {.inject.} = x.altairData
body
of ConsensusFork.Bellatrix:
const stateFork {.inject, used.} = ConsensusFork.Bellatrix
template blck: untyped {.inject.} = x.bellatrixData
body
of ConsensusFork.Capella:
const stateFork {.inject, used.} = ConsensusFork.Capella
template blck: untyped {.inject.} = x.capellaData
body
of ConsensusFork.Deneb:
const stateFork {.inject, used.} = ConsensusFork.Deneb
template blck: untyped {.inject.} = x.denebData
body
func proposer_index*(x: ForkedBeaconBlock): uint64 =
withBlck(x): blck.proposer_index
func hash_tree_root*(x: ForkedBeaconBlock | Web3SignerForkedBeaconBlock):
Eth2Digest =
withBlck(x): hash_tree_root(blck)
template getForkedBlockField*(
x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock,
y: untyped): untyped =
# unsafeAddr avoids a copy of the field in some cases
(case x.kind
of ConsensusFork.Phase0: unsafeAddr x.phase0Data.message.y
of ConsensusFork.Altair: unsafeAddr x.altairData.message.y
of ConsensusFork.Bellatrix: unsafeAddr x.bellatrixData.message.y
of ConsensusFork.Capella: unsafeAddr x.capellaData.message.y
of ConsensusFork.Deneb: unsafeAddr x.denebData.message.y)[]
template signature*(x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
ForkedSignedBlindedBeaconBlock): ValidatorSig =
withBlck(x): blck.signature
template signature*(x: ForkedTrustedSignedBeaconBlock): TrustedSig =
withBlck(x): blck.signature
template root*(x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock): Eth2Digest =
withBlck(x): blck.root
template slot*(x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock): Slot =
withBlck(x): blck.message.slot
template shortLog*(x: ForkedBeaconBlock | ForkedBlindedBeaconBlock): auto =
withBlck(x): shortLog(blck)
template shortLog*(x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock |
ForkedSignedBlindedBeaconBlock): auto =
withBlck(x): shortLog(blck)
chronicles.formatIt ForkedBeaconBlock: it.shortLog
chronicles.formatIt ForkedSignedBeaconBlock: it.shortLog
chronicles.formatIt ForkedMsgTrustedSignedBeaconBlock: it.shortLog
chronicles.formatIt ForkedTrustedSignedBeaconBlock: it.shortLog
template withStateAndBlck*(
s: ForkedHashedBeaconState,
b: ForkedBeaconBlock | ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock,
body: untyped): untyped =
case s.kind
of ConsensusFork.Deneb:
const stateFork {.inject.} = ConsensusFork.Deneb
template forkyState: untyped {.inject.} = s.denebData
template blck: untyped {.inject.} = b.denebData
body
of ConsensusFork.Capella:
const stateFork {.inject.} = ConsensusFork.Capella
template forkyState: untyped {.inject.} = s.capellaData
template blck: untyped {.inject.} = b.capellaData
body
of ConsensusFork.Bellatrix:
const stateFork {.inject.} = ConsensusFork.Bellatrix
template forkyState: untyped {.inject.} = s.bellatrixData
template blck: untyped {.inject.} = b.bellatrixData
body
of ConsensusFork.Altair:
const stateFork {.inject.} = ConsensusFork.Altair
template forkyState: untyped {.inject.} = s.altairData
template blck: untyped {.inject.} = b.altairData
body
of ConsensusFork.Phase0:
const stateFork {.inject.} = ConsensusFork.Phase0
template forkyState: untyped {.inject.} = s.phase0Data
template blck: untyped {.inject.} = b.phase0Data
body
func toBeaconBlockHeader*(
blck: SomeForkyBeaconBlock | bellatrix_mev.BlindedBeaconBlock |
capella_mev.BlindedBeaconBlock): BeaconBlockHeader =
## Reduce a given `BeaconBlock` to its `BeaconBlockHeader`.
BeaconBlockHeader(
slot: blck.slot,
proposer_index: blck.proposer_index,
parent_root: blck.parent_root,
state_root: blck.state_root,
body_root: blck.body.hash_tree_root())
template toBeaconBlockHeader*(
blck: SomeForkySignedBeaconBlock): BeaconBlockHeader =
## Reduce a given `SignedBeaconBlock` to its `BeaconBlockHeader`.
blck.message.toBeaconBlockHeader
template toBeaconBlockHeader*(
blckParam: ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock): BeaconBlockHeader =
## Reduce a given signed beacon block to its `BeaconBlockHeader`.
withBlck(blckParam): blck.toBeaconBlockHeader()
func genesisFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.GENESIS_FORK_VERSION,
current_version: cfg.GENESIS_FORK_VERSION,
epoch: GENESIS_EPOCH)
func altairFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.GENESIS_FORK_VERSION,
current_version: cfg.ALTAIR_FORK_VERSION,
epoch: cfg.ALTAIR_FORK_EPOCH)
func bellatrixFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.ALTAIR_FORK_VERSION,
current_version: cfg.BELLATRIX_FORK_VERSION,
epoch: cfg.BELLATRIX_FORK_EPOCH)
func capellaFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.BELLATRIX_FORK_VERSION,
current_version: cfg.CAPELLA_FORK_VERSION,
epoch: cfg.CAPELLA_FORK_EPOCH)
func denebFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.CAPELLA_FORK_VERSION,
current_version: cfg.DENEB_FORK_VERSION,
epoch: cfg.DENEB_FORK_EPOCH)
func forkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Fork =
case cfg.consensusForkAtEpoch(epoch)
of ConsensusFork.Deneb: cfg.denebFork
of ConsensusFork.Capella: cfg.capellaFork
of ConsensusFork.Bellatrix: cfg.bellatrixFork
of ConsensusFork.Altair: cfg.altairFork
of ConsensusFork.Phase0: cfg.genesisFork
func forkVersionAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Version =
case cfg.consensusForkAtEpoch(epoch)
of ConsensusFork.Deneb: cfg.DENEB_FORK_VERSION
of ConsensusFork.Capella: cfg.CAPELLA_FORK_VERSION
of ConsensusFork.Bellatrix: cfg.BELLATRIX_FORK_VERSION
of ConsensusFork.Altair: cfg.ALTAIR_FORK_VERSION
of ConsensusFork.Phase0: cfg.GENESIS_FORK_VERSION
func nextForkEpochAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Epoch =
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
case cfg.consensusForkAtEpoch(epoch)
of ConsensusFork.Deneb: FAR_FUTURE_EPOCH
of ConsensusFork.Capella: cfg.DENEB_FORK_EPOCH
of ConsensusFork.Bellatrix: cfg.CAPELLA_FORK_EPOCH
of ConsensusFork.Altair: cfg.BELLATRIX_FORK_EPOCH
of ConsensusFork.Phase0: cfg.ALTAIR_FORK_EPOCH
func forkVersion*(cfg: RuntimeConfig, consensusFork: ConsensusFork): Version =
case consensusFork
of ConsensusFork.Phase0: cfg.GENESIS_FORK_VERSION
of ConsensusFork.Altair: cfg.ALTAIR_FORK_VERSION
of ConsensusFork.Bellatrix: cfg.BELLATRIX_FORK_VERSION
of ConsensusFork.Capella: cfg.CAPELLA_FORK_VERSION
of ConsensusFork.Deneb: cfg.DENEB_FORK_VERSION
func lcDataForkAtStateFork*(stateFork: ConsensusFork): LightClientDataFork =
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
if stateFork >= ConsensusFork.Deneb:
LightClientDataFork.EIP4844
elif stateFork >= ConsensusFork.Capella:
LightClientDataFork.Capella
elif stateFork >= ConsensusFork.Altair:
LightClientDataFork.Altair
else:
LightClientDataFork.None
func getForkSchedule*(cfg: RuntimeConfig): array[5, Fork] =
## This procedure returns list of known and/or scheduled forks.
##
## This procedure is used by HTTP REST framework and validator client.
##
## NOTE: Update this procedure when new fork will be scheduled.
[cfg.genesisFork(), cfg.altairFork(), cfg.bellatrixFork(), cfg.capellaFork(),
cfg.denebFork()]
type
# The first few fields of a state, shared across all forks
BeaconStateHeader = object
genesis_time: uint64
genesis_validators_root: Eth2Digest
slot: Slot
func readSszForkedHashedBeaconState*(
cfg: RuntimeConfig, slot: Slot, data: openArray[byte]):
ForkedHashedBeaconState {.raises: [Defect, SszError].} =
# TODO https://github.com/nim-lang/Nim/issues/19357
result = ForkedHashedBeaconState(
kind: cfg.consensusForkAtEpoch(slot.epoch()))
withState(result):
readSszBytes(data, forkyState.data)
forkyState.root = hash_tree_root(forkyState.data)
func readSszForkedHashedBeaconState*(cfg: RuntimeConfig, data: openArray[byte]):
ForkedHashedBeaconState {.raises: [Defect, SszError].} =
## Read a state picking the right fork by first reading the slot from the byte
## source
if data.len() < sizeof(BeaconStateHeader):
raise (ref MalformedSszError)(msg: "Not enough data for BeaconState header")
let header = SSZ.decode(
data.toOpenArray(0, sizeof(BeaconStateHeader) - 1),
BeaconStateHeader)
# TODO https://github.com/nim-lang/Nim/issues/19357
result = readSszForkedHashedBeaconState(cfg, header.slot, data)
type
ForkedBeaconBlockHeader = object
message*: uint32 # message offset
signature*: ValidatorSig
slot: Slot # start of BeaconBlock
func readSszForkedSignedBeaconBlock*(
cfg: RuntimeConfig, data: openArray[byte]):
ForkedSignedBeaconBlock {.raises: [Defect, SszError].} =
## Helper to read a header from bytes when it's not certain what kind of block
## it is
if data.len() < sizeof(ForkedBeaconBlockHeader):
raise (ref MalformedSszError)(msg: "Not enough data for SignedBeaconBlock header")
let header = SSZ.decode(
data.toOpenArray(0, sizeof(ForkedBeaconBlockHeader) - 1),
ForkedBeaconBlockHeader)
# TODO https://github.com/nim-lang/Nim/issues/19357
result = ForkedSignedBeaconBlock(
kind: cfg.consensusForkAtEpoch(header.slot.epoch()))
withBlck(result):
readSszBytes(data, blck)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.3/specs/phase0/beacon-chain.md#compute_fork_data_root
func compute_fork_data_root*(current_version: Version,
genesis_validators_root: Eth2Digest): Eth2Digest =
## Return the 32-byte fork data root for the ``current_version`` and
## ``genesis_validators_root``.
## This is used primarily in signature domains to avoid collisions across
## forks/chains.
hash_tree_root(ForkData(
current_version: current_version,
genesis_validators_root: genesis_validators_root
))
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.3/specs/phase0/beacon-chain.md#compute_fork_digest
func compute_fork_digest*(current_version: Version,
genesis_validators_root: Eth2Digest): ForkDigest =
## Return the 4-byte fork digest for the ``current_version`` and
## ``genesis_validators_root``.
## This is a digest primarily used for domain separation on the p2p layer.
## 4-bytes suffices for practical separation of forks/chains.
array[4, byte](result)[0..3] =
compute_fork_data_root(
current_version, genesis_validators_root).data.toOpenArray(0, 3)
func init*(T: type ForkDigests,
cfg: RuntimeConfig,
genesis_validators_root: Eth2Digest): T =
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
T(
phase0:
compute_fork_digest(cfg.GENESIS_FORK_VERSION, genesis_validators_root),
altair:
compute_fork_digest(cfg.ALTAIR_FORK_VERSION, genesis_validators_root),
bellatrix:
compute_fork_digest(cfg.BELLATRIX_FORK_VERSION, genesis_validators_root),
capella:
compute_fork_digest(cfg.CAPELLA_FORK_VERSION, genesis_validators_root),
eip4844:
compute_fork_digest(cfg.DENEB_FORK_VERSION, genesis_validators_root)
)
func toBlockId*(header: BeaconBlockHeader): BlockId =
BlockId(root: header.hash_tree_root(), slot: header.slot)
func toBlockId*(blck: SomeForkySignedBeaconBlock): BlockId =
BlockId(root: blck.root, slot: blck.message.slot)
func toBlockId*(blck: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
ForkedTrustedSignedBeaconBlock): BlockId =
withBlck(blck): BlockId(root: blck.root, slot: blck.message.slot)