# beacon_chain # Copyright (c) 2021-2024 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, results, stew/assign2, chronicles, ../extras, "."/[ block_id, eth2_merkleization, eth2_ssz_serialization, forks_light_client, presets], ./datatypes/[phase0, altair, bellatrix, capella, deneb, electra], ./mev/[bellatrix_mev, capella_mev, deneb_mev, electra_mev] export extras, block_id, phase0, altair, bellatrix, capella, deneb, electra, eth2_merkleization, eth2_ssz_serialization, forks_light_client, presets, deneb_mev, electra_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, Electra ForkyBeaconState* = phase0.BeaconState | altair.BeaconState | bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState | electra.BeaconState ForkyHashedBeaconState* = phase0.HashedBeaconState | altair.HashedBeaconState | bellatrix.HashedBeaconState | capella.HashedBeaconState | deneb.HashedBeaconState | electra.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 of ConsensusFork.Electra: electraData*: electra.HashedBeaconState ForkyExecutionPayload* = bellatrix.ExecutionPayload | capella.ExecutionPayload | deneb.ExecutionPayload | electra.ExecutionPayload ForkyExecutionPayloadHeader* = bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader | deneb.ExecutionPayloadHeader ForkyBeaconBlockBody* = phase0.BeaconBlockBody | altair.BeaconBlockBody | bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody | electra.BeaconBlockBody ForkySigVerifiedBeaconBlockBody* = phase0.SigVerifiedBeaconBlockBody | altair.SigVerifiedBeaconBlockBody | bellatrix.SigVerifiedBeaconBlockBody | capella.SigVerifiedBeaconBlockBody | deneb.SigVerifiedBeaconBlockBody | electra.SigVerifiedBeaconBlockBody ForkyTrustedBeaconBlockBody* = phase0.TrustedBeaconBlockBody | altair.TrustedBeaconBlockBody | bellatrix.TrustedBeaconBlockBody | capella.TrustedBeaconBlockBody | deneb.TrustedBeaconBlockBody | electra.TrustedBeaconBlockBody SomeForkyBeaconBlockBody* = ForkyBeaconBlockBody | ForkySigVerifiedBeaconBlockBody | ForkyTrustedBeaconBlockBody ForkyBeaconBlock* = phase0.BeaconBlock | altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock | electra.BeaconBlock ForkySigVerifiedBeaconBlock* = phase0.SigVerifiedBeaconBlock | altair.SigVerifiedBeaconBlock | bellatrix.SigVerifiedBeaconBlock | capella.SigVerifiedBeaconBlock | deneb.SigVerifiedBeaconBlock | electra.SigVerifiedBeaconBlock ForkyTrustedBeaconBlock* = phase0.TrustedBeaconBlock | altair.TrustedBeaconBlock | bellatrix.TrustedBeaconBlock | capella.TrustedBeaconBlock | deneb.TrustedBeaconBlock | electra.TrustedBeaconBlock SomeForkyBeaconBlock* = ForkyBeaconBlock | ForkySigVerifiedBeaconBlock | ForkyTrustedBeaconBlock ForkyExecutionPayloadForSigning* = bellatrix.ExecutionPayloadForSigning | capella.ExecutionPayloadForSigning | deneb.ExecutionPayloadForSigning | electra.ExecutionPayloadForSigning ForkyBlindedBeaconBlock* = deneb_mev.BlindedBeaconBlock | electra_mev.BlindedBeaconBlock 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 of ConsensusFork.Electra: electraData*: electra.BeaconBlock ForkedMaybeBlindedBeaconBlock* = 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_mev.MaybeBlindedBeaconBlock of ConsensusFork.Electra: electraData*: electra_mev.MaybeBlindedBeaconBlock consensusValue*: Opt[UInt256] executionValue*: Opt[UInt256] Web3SignerForkedBeaconBlock* = object kind*: ConsensusFork data*: 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*: deneb_mev.BlindedBeaconBlock of ConsensusFork.Electra: electraData*: electra_mev.BlindedBeaconBlock ForkySignedBeaconBlock* = phase0.SignedBeaconBlock | altair.SignedBeaconBlock | bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock | deneb.SignedBeaconBlock | electra.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 of ConsensusFork.Electra: electraData*: electra.SignedBeaconBlock ForkySignedBlindedBeaconBlock* = phase0.SignedBeaconBlock | altair.SignedBeaconBlock | bellatrix_mev.SignedBlindedBeaconBlock | capella_mev.SignedBlindedBeaconBlock | deneb_mev.SignedBlindedBeaconBlock | electra_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*: deneb_mev.SignedBlindedBeaconBlock of ConsensusFork.Electra: electraData*: electra_mev.SignedBlindedBeaconBlock ForkySigVerifiedSignedBeaconBlock* = phase0.SigVerifiedSignedBeaconBlock | altair.SigVerifiedSignedBeaconBlock | bellatrix.SigVerifiedSignedBeaconBlock | capella.SigVerifiedSignedBeaconBlock | deneb.SigVerifiedSignedBeaconBlock | electra.SigVerifiedSignedBeaconBlock ForkyMsgTrustedSignedBeaconBlock* = phase0.MsgTrustedSignedBeaconBlock | altair.MsgTrustedSignedBeaconBlock | bellatrix.MsgTrustedSignedBeaconBlock | capella.MsgTrustedSignedBeaconBlock | deneb.MsgTrustedSignedBeaconBlock | electra.MsgTrustedSignedBeaconBlock ForkyTrustedSignedBeaconBlock* = phase0.TrustedSignedBeaconBlock | altair.TrustedSignedBeaconBlock | bellatrix.TrustedSignedBeaconBlock | capella.TrustedSignedBeaconBlock | deneb.TrustedSignedBeaconBlock | electra.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 of ConsensusFork.Electra: electraData*: electra.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 of ConsensusFork.Electra: electraData*: electra.TrustedSignedBeaconBlock SomeForkySignedBeaconBlock* = ForkySignedBeaconBlock | ForkySigVerifiedSignedBeaconBlock | ForkyMsgTrustedSignedBeaconBlock | ForkyTrustedSignedBeaconBlock BlobFork* {.pure.} = enum Deneb ForkyBlobSidecar* = deneb.BlobSidecar ForkyBlobSidecars* = deneb.BlobSidecars OptForkyBlobSidecars* = Opt[deneb.BlobSidecars] ForkedBlobSidecar* = object case kind*: BlobFork of BlobFork.Deneb: denebData*: ref deneb.BlobSidecar ForkedBlobSidecars* = seq[ForkedBlobSidecar] 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 deneb*: ForkDigest electra*: ForkDigest template kind*( x: typedesc[ phase0.BeaconState | phase0.HashedBeaconState | phase0.BeaconBlock | phase0.SignedBeaconBlock | phase0.TrustedBeaconBlock | phase0.BeaconBlockBody | phase0.SigVerifiedBeaconBlockBody | phase0.TrustedBeaconBlockBody | phase0.SigVerifiedSignedBeaconBlock | phase0.MsgTrustedSignedBeaconBlock | phase0.TrustedSignedBeaconBlock]): ConsensusFork = ConsensusFork.Phase0 template kind*( x: typedesc[ altair.BeaconState | altair.HashedBeaconState | altair.BeaconBlock | altair.SignedBeaconBlock | altair.TrustedBeaconBlock | altair.BeaconBlockBody | altair.SigVerifiedBeaconBlockBody | altair.TrustedBeaconBlockBody | altair.SigVerifiedSignedBeaconBlock | altair.MsgTrustedSignedBeaconBlock | altair.TrustedSignedBeaconBlock]): ConsensusFork = ConsensusFork.Altair template kind*( x: typedesc[ bellatrix.BeaconState | bellatrix.HashedBeaconState | bellatrix.ExecutionPayload | bellatrix.ExecutionPayloadForSigning | bellatrix.ExecutionPayloadHeader | bellatrix.BeaconBlock | bellatrix.SignedBeaconBlock | bellatrix.TrustedBeaconBlock | bellatrix.BeaconBlockBody | bellatrix.SigVerifiedBeaconBlockBody | bellatrix.TrustedBeaconBlockBody | bellatrix.SigVerifiedSignedBeaconBlock | bellatrix.MsgTrustedSignedBeaconBlock | bellatrix.TrustedSignedBeaconBlock] | bellatrix_mev.SignedBlindedBeaconBlock): ConsensusFork = ConsensusFork.Bellatrix template kind*( x: typedesc[ capella.BeaconState | capella.HashedBeaconState | capella.ExecutionPayload | capella.ExecutionPayloadForSigning | capella.ExecutionPayloadHeader | capella.BeaconBlock | capella.SignedBeaconBlock | capella.TrustedBeaconBlock | capella.BeaconBlockBody | capella.SigVerifiedBeaconBlockBody | capella.TrustedBeaconBlockBody | capella.SigVerifiedSignedBeaconBlock | capella.MsgTrustedSignedBeaconBlock | capella.TrustedSignedBeaconBlock | capella_mev.SignedBlindedBeaconBlock]): ConsensusFork = ConsensusFork.Capella template kind*( x: typedesc[ deneb.BeaconState | deneb.HashedBeaconState | deneb.ExecutionPayload | deneb.ExecutionPayloadForSigning | deneb.ExecutionPayloadHeader | deneb.BeaconBlock | deneb.SignedBeaconBlock | deneb.TrustedBeaconBlock | deneb.BeaconBlockBody | deneb.SigVerifiedBeaconBlockBody | deneb.TrustedBeaconBlockBody | deneb.SigVerifiedSignedBeaconBlock | deneb.MsgTrustedSignedBeaconBlock | deneb.TrustedSignedBeaconBlock | deneb_mev.SignedBlindedBeaconBlock]): ConsensusFork = ConsensusFork.Deneb template kind*( x: typedesc[ electra.BeaconState | electra.HashedBeaconState | electra.ExecutionPayload | electra.ExecutionPayloadForSigning | electra.ExecutionPayloadHeader | electra.BeaconBlock | electra.SignedBeaconBlock | electra.TrustedBeaconBlock | electra.BeaconBlockBody | electra.SigVerifiedBeaconBlockBody | electra.TrustedBeaconBlockBody | electra.SigVerifiedSignedBeaconBlock | electra.MsgTrustedSignedBeaconBlock | electra.TrustedSignedBeaconBlock | electra_mev.SignedBlindedBeaconBlock]): ConsensusFork = ConsensusFork.Electra template BeaconState*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra.BeaconState] elif kind == ConsensusFork.Deneb: typedesc[deneb.BeaconState] elif kind == ConsensusFork.Capella: typedesc[capella.BeaconState] elif kind == ConsensusFork.Bellatrix: typedesc[bellatrix.BeaconState] elif kind == ConsensusFork.Altair: typedesc[altair.BeaconState] elif kind == ConsensusFork.Phase0: typedesc[phase0.BeaconState] else: static: raiseAssert "Unreachable" template BeaconBlock*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra.BeaconBlock] elif kind == ConsensusFork.Deneb: typedesc[deneb.BeaconBlock] elif kind == ConsensusFork.Capella: typedesc[capella.BeaconBlock] elif kind == ConsensusFork.Bellatrix: typedesc[bellatrix.BeaconBlock] elif kind == ConsensusFork.Altair: typedesc[altair.BeaconBlock] elif kind == ConsensusFork.Phase0: typedesc[phase0.BeaconBlock] else: static: raiseAssert "Unreachable" template BeaconBlockBody*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra.BeaconBlockBody] elif kind == ConsensusFork.Deneb: typedesc[deneb.BeaconBlockBody] elif kind == ConsensusFork.Capella: typedesc[capella.BeaconBlockBody] elif kind == ConsensusFork.Bellatrix: typedesc[bellatrix.BeaconBlockBody] elif kind == ConsensusFork.Altair: typedesc[altair.BeaconBlockBody] elif kind == ConsensusFork.Phase0: typedesc[phase0.BeaconBlockBody] else: static: raiseAssert "Unreachable" template SignedBeaconBlock*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra.SignedBeaconBlock] elif kind == ConsensusFork.Deneb: typedesc[deneb.SignedBeaconBlock] elif kind == ConsensusFork.Capella: typedesc[capella.SignedBeaconBlock] elif kind == ConsensusFork.Bellatrix: typedesc[bellatrix.SignedBeaconBlock] elif kind == ConsensusFork.Altair: typedesc[altair.SignedBeaconBlock] elif kind == ConsensusFork.Phase0: typedesc[phase0.SignedBeaconBlock] else: static: raiseAssert "Unreachable" template TrustedSignedBeaconBlock*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra.TrustedSignedBeaconBlock] elif kind == ConsensusFork.Deneb: typedesc[deneb.TrustedSignedBeaconBlock] elif kind == ConsensusFork.Capella: typedesc[capella.TrustedSignedBeaconBlock] elif kind == ConsensusFork.Bellatrix: typedesc[bellatrix.TrustedSignedBeaconBlock] elif kind == ConsensusFork.Altair: typedesc[altair.TrustedSignedBeaconBlock] elif kind == ConsensusFork.Phase0: typedesc[phase0.TrustedSignedBeaconBlock] else: static: raiseAssert "Unreachable" template ExecutionPayloadForSigning*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra.ExecutionPayloadForSigning] elif kind == ConsensusFork.Deneb: typedesc[deneb.ExecutionPayloadForSigning] elif kind == ConsensusFork.Capella: typedesc[capella.ExecutionPayloadForSigning] elif kind == ConsensusFork.Bellatrix: typedesc[bellatrix.ExecutionPayloadForSigning] else: static: raiseAssert "Unreachable" template BlindedBeaconBlock*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra_mev.BlindedBeaconBlock] elif kind == ConsensusFork.Deneb: typedesc[deneb_mev.BlindedBeaconBlock] elif kind == ConsensusFork.Capella or kind == ConsensusFork.Bellatrix: static: raiseAssert "Unsupported" else: static: raiseAssert "Unreachable" template MaybeBlindedBeaconBlock*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra_mev.MaybeBlindedBeaconBlock] elif kind == ConsensusFork.Deneb: typedesc[deneb_mev.MaybeBlindedBeaconBlock] elif kind == ConsensusFork.Capella or kind == ConsensusFork.Bellatrix: static: raiseAssert "Unsupported" else: static: raiseAssert "Unreachable" template SignedBlindedBeaconBlock*(kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra_mev.SignedBlindedBeaconBlock] elif kind == ConsensusFork.Deneb: typedesc[deneb_mev.SignedBlindedBeaconBlock] elif kind == ConsensusFork.Capella or kind == ConsensusFork.Bellatrix: static: raiseAssert "Unsupported" else: static: raiseAssert "Unreachable" template Forky*( x: typedesc[ForkedSignedBeaconBlock], kind: static ConsensusFork): auto = kind.SignedBeaconBlock template withAll*( x: typedesc[ConsensusFork], body: untyped): untyped = static: doAssert ConsensusFork.high == ConsensusFork.Electra block: const consensusFork {.inject, used.} = ConsensusFork.Electra body block: const consensusFork {.inject, used.} = ConsensusFork.Deneb body block: const consensusFork {.inject, used.} = ConsensusFork.Capella body block: const consensusFork {.inject, used.} = ConsensusFork.Bellatrix body block: const consensusFork {.inject, used.} = ConsensusFork.Altair body block: const consensusFork {.inject, used.} = ConsensusFork.Phase0 body template withConsensusFork*( x: ConsensusFork, body: untyped): untyped = case x of ConsensusFork.Electra: const consensusFork {.inject, used.} = ConsensusFork.Electra body of ConsensusFork.Deneb: const consensusFork {.inject, used.} = ConsensusFork.Deneb body of ConsensusFork.Capella: const consensusFork {.inject, used.} = ConsensusFork.Capella body of ConsensusFork.Bellatrix: const consensusFork {.inject, used.} = ConsensusFork.Bellatrix body of ConsensusFork.Altair: const consensusFork {.inject, used.} = ConsensusFork.Altair body of ConsensusFork.Phase0: const consensusFork {.inject, used.} = ConsensusFork.Phase0 body template BlockContents*( kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra.BlockContents] elif kind == ConsensusFork.Deneb: typedesc[deneb.BlockContents] elif kind == ConsensusFork.Capella: typedesc[capella.BeaconBlock] elif kind == ConsensusFork.Bellatrix: typedesc[bellatrix.BeaconBlock] elif kind == ConsensusFork.Altair: typedesc[altair.BeaconBlock] elif kind == ConsensusFork.Phase0: typedesc[phase0.BeaconBlock] else: {.error: "BlockContents does not support " & $kind.} template BlindedBlockContents*( kind: static ConsensusFork): auto = when kind == ConsensusFork.Electra: typedesc[electra_mev.BlindedBeaconBlock] elif kind == ConsensusFork.Deneb: typedesc[deneb_mev.BlindedBeaconBlock] else: {.error: "BlindedBlockContents does not support " & $kind.} template PayloadAttributes*( kind: static ConsensusFork): auto = # This also determines what `engine_forkchoiceUpdated` version will be used. when kind >= ConsensusFork.Deneb: typedesc[PayloadAttributesV3] elif kind >= ConsensusFork.Capella: # https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md#specification-1 # Consensus layer client MUST call this method instead of # `engine_forkchoiceUpdatedV1` under any of the following conditions: # `headBlockHash` references a block which `timestamp` is greater or # equal to the Shanghai timestamp typedesc[PayloadAttributesV2] elif kind >= ConsensusFork.Bellatrix: typedesc[PayloadAttributesV1] else: {.error: "PayloadAttributes does not support " & $kind.} # `eth2_merkleization` cannot import `forks` (circular), so the check is here static: doAssert ConsensusFork.high == ConsensusFork.Electra, "eth2_merkleization has been checked and `hash_tree_root` is up to date" # 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))) func new*(T: type ForkedHashedBeaconState, data: electra.BeaconState): ref ForkedHashedBeaconState = (ref T)(kind: ConsensusFork.Electra, electraData: electra.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 ForkedBeaconBlock, blck: electra.BeaconBlock): T = T(kind: ConsensusFork.Electra, electraData: 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) template init*(T: type ForkedSignedBeaconBlock, blck: electra.SignedBeaconBlock): T = T(kind: ConsensusFork.Electra, electraData: 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)) of ConsensusFork.Electra: T(kind: ConsensusFork.Electra, electraData: electra.SignedBeaconBlock(message: forked.electraData, 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: default(bellatrix_mev.SignedBlindedBeaconBlock)) of ConsensusFork.Capella: T(kind: ConsensusFork.Capella, capellaData: capella_mev.SignedBlindedBeaconBlock(message: forked.capellaData, signature: signature)) of ConsensusFork.Deneb: T(kind: ConsensusFork.Deneb, denebData: deneb_mev.SignedBlindedBeaconBlock(message: forked.denebData, signature: signature)) of ConsensusFork.Electra: T(kind: ConsensusFork.Electra, electraData: electra_mev.SignedBlindedBeaconBlock(message: forked.electraData, signature: signature)) template init*(T: type ForkedSignedBlindedBeaconBlock, blck: capella_mev.BlindedBeaconBlock, blockRoot: Eth2Digest, signature: ValidatorSig): T = T(kind: ConsensusFork.Capella, capellaData: capella_mev.SignedBlindedBeaconBlock( message: blck, signature: signature)) template init*(T: type ForkedSignedBlindedBeaconBlock, blck: deneb_mev.BlindedBeaconBlock, blockRoot: Eth2Digest, signature: ValidatorSig): T = T(kind: ConsensusFork.Deneb, denebData: deneb_mev.SignedBlindedBeaconBlock( message: blck, signature: signature)) template init*(T: type ForkedSignedBlindedBeaconBlock, blck: electra_mev.BlindedBeaconBlock, blockRoot: Eth2Digest, signature: ValidatorSig): T = T(kind: ConsensusFork.Electra, electraData: electra_mev.SignedBlindedBeaconBlock( message: blck, 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, denebData: 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 init*(T: type ForkedTrustedSignedBeaconBlock, blck: electra.TrustedSignedBeaconBlock): T = T(kind: ConsensusFork.Electra, electraData: 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" of ConsensusFork.Electra: "electra" template init*(T: typedesc[ConsensusFork], value: string): Opt[ConsensusFork] = case value of "electra": Opt.some ConsensusFork.Electra of "deneb": Opt.some ConsensusFork.Deneb of "capella": Opt.some ConsensusFork.Capella of "bellatrix": Opt.some ConsensusFork.Bellatrix of "altair": Opt.some ConsensusFork.Altair of "phase0": Opt.some ConsensusFork.Phase0 else: Opt.none(ConsensusFork) static: for fork in ConsensusFork: doAssert ConsensusFork.init(fork.toString()).expect("init defined") == fork template kind*(x: typedesc[deneb.BlobSidecar]): BlobFork = BlobFork.Deneb template kzg_commitment_inclusion_proof_gindex*( kind: static BlobFork, index: BlobIndex): GeneralizedIndex = when kind == BlobFork.Deneb: deneb.kzg_commitment_inclusion_proof_gindex(index) else: {.error: "kzg_commitment_inclusion_proof_gindex does not support " & $kind.} template BlobSidecar*(kind: static BlobFork): auto = when kind == BlobFork.Deneb: typedesc[deneb.BlobSidecar] else: {.error: "BlobSidecar does not support " & $kind.} template BlobSidecars*(kind: static BlobFork): auto = when kind == BlobFork.Deneb: typedesc[deneb.BlobSidecars] else: {.error: "BlobSidecars does not support " & $kind.} template withAll*(x: typedesc[BlobFork], body: untyped): untyped = static: doAssert BlobFork.high == BlobFork.Deneb block: const blobFork {.inject, used.} = BlobFork.Deneb body template withBlobFork*(x: BlobFork, body: untyped): untyped = case x of BlobFork.Deneb: const blobFork {.inject, used.} = BlobFork.Deneb body template withForkyBlob*(x: ForkedBlobSidecar, body: untyped): untyped = case x.kind of BlobFork.Deneb: const blobFork {.inject, used.} = BlobFork.Deneb template forkyBlob: untyped {.inject, used.} = x.denebData body func init*( x: typedesc[ForkedBlobSidecar], forkyData: ref ForkyBlobSidecar): ForkedBlobSidecar = const kind = typeof(forkyData[]).kind when kind == BlobFork.Deneb: ForkedBlobSidecar(kind: kind, denebData: forkyData) else: {.error: "ForkedBlobSidecar.init does not support " & $kind.} template forky*(x: ForkedBlobSidecar, kind: static BlobFork): untyped = when kind == BlobFork.Deneb: x.denebData else: {.error: "ForkedBlobSidecar.forky does not support " & $kind.} func shortLog*[T: ForkedBlobSidecar](x: T): auto = type ResultType = object case kind: BlobFork of BlobFork.Deneb: denebData: typeof(x.denebData.shortLog()) let xKind = x.kind # https://github.com/nim-lang/Nim/issues/23762 case xKind of BlobFork.Deneb: ResultType(kind: xKind, denebData: x.denebData.shortLog()) chronicles.formatIt ForkedBlobSidecar: it.shortLog 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.Electra: const consensusFork {.inject, used.} = ConsensusFork.Electra template forkyState: untyped {.inject, used.} = x.electraData body of ConsensusFork.Deneb: const consensusFork {.inject, used.} = ConsensusFork.Deneb template forkyState: untyped {.inject, used.} = x.denebData body of ConsensusFork.Capella: const consensusFork {.inject, used.} = ConsensusFork.Capella template forkyState: untyped {.inject, used.} = x.capellaData body of ConsensusFork.Bellatrix: const consensusFork {.inject, used.} = ConsensusFork.Bellatrix template forkyState: untyped {.inject, used.} = x.bellatrixData body of ConsensusFork.Altair: const consensusFork {.inject, used.} = ConsensusFork.Altair template forkyState: untyped {.inject, used.} = x.altairData body of ConsensusFork.Phase0: const consensusFork {.inject, used.} = ConsensusFork.Phase0 template forkyState: untyped {.inject, used.} = x.phase0Data body template forky*( x: ForkedBeaconBlock | ForkedHashedBeaconState, kind: static ConsensusFork): untyped = when kind == ConsensusFork.Electra: x.electraData elif kind == ConsensusFork.Deneb: x.denebData elif kind == ConsensusFork.Capella: x.capellaData elif kind == ConsensusFork.Bellatrix: x.bellatrixData elif kind == ConsensusFork.Altair: x.altairData elif kind == ConsensusFork.Phase0: x.phase0Data else: static: raiseAssert "Unreachable" template withEpochInfo*(x: ForkedEpochInfo, body: untyped): untyped = case x.kind of EpochInfoFork.Phase0: const infoFork {.inject, used.} = EpochInfoFork.Phase0 template info: untyped {.inject.} = x.phase0Data body of EpochInfoFork.Altair: const infoFork {.inject, used.} = 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 | electra.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: # Avoid temporary with ref tgt = (ref ForkedHashedBeaconState)(kind: src.kind)[] withState(tgt): template forkyTgt: untyped = forkyState template forkySrc: untyped = src.forky(consensusFork) assign(forkyTgt, forkySrc) 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. (block: withState(x): unsafeAddr forkyState.data.y)[] func getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest = withState(x): forkyState.root {.push warning[ProveField]:off.} # https://github.com/nim-lang/Nim/issues/22060 func setStateRoot*(x: var ForkedHashedBeaconState, root: Eth2Digest) = withState(x): forkyState.root = root {.pop.} func consensusForkEpoch*( cfg: RuntimeConfig, consensusFork: ConsensusFork): Epoch = case consensusFork of ConsensusFork.Electra: cfg.ELECTRA_FORK_EPOCH of ConsensusFork.Deneb: cfg.DENEB_FORK_EPOCH of ConsensusFork.Capella: cfg.CAPELLA_FORK_EPOCH of ConsensusFork.Bellatrix: cfg.BELLATRIX_FORK_EPOCH of ConsensusFork.Altair: cfg.ALTAIR_FORK_EPOCH of ConsensusFork.Phase0: GENESIS_EPOCH func consensusForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): ConsensusFork = ## Return the current fork for the given epoch. static: doAssert high(ConsensusFork) == ConsensusFork.Electra doAssert ConsensusFork.Electra > 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.ELECTRA_FORK_EPOCH: ConsensusFork.Electra elif 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 consensusForkForDigest*( forkDigests: ForkDigests, forkDigest: ForkDigest): Opt[ConsensusFork] = static: doAssert high(ConsensusFork) == ConsensusFork.Electra if forkDigest == forkDigests.electra: ok ConsensusFork.Electra elif forkDigest == forkDigests.deneb: 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 atConsensusFork*( forkDigests: ForkDigests, consensusFork: ConsensusFork): ForkDigest = case consensusFork of ConsensusFork.Electra: forkDigests.electra of ConsensusFork.Deneb: forkDigests.deneb 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.atConsensusFork(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 | ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock | ForkedBlindedBeaconBlock | ForkedSignedBlindedBeaconBlock, body: untyped): untyped = case x.kind of ConsensusFork.Phase0: const consensusFork {.inject, used.} = ConsensusFork.Phase0 template forkyBlck: untyped {.inject, used.} = x.phase0Data body of ConsensusFork.Altair: const consensusFork {.inject, used.} = ConsensusFork.Altair template forkyBlck: untyped {.inject, used.} = x.altairData body of ConsensusFork.Bellatrix: const consensusFork {.inject, used.} = ConsensusFork.Bellatrix template forkyBlck: untyped {.inject, used.} = x.bellatrixData body of ConsensusFork.Capella: const consensusFork {.inject, used.} = ConsensusFork.Capella template forkyBlck: untyped {.inject, used.} = x.capellaData body of ConsensusFork.Deneb: const consensusFork {.inject, used.} = ConsensusFork.Deneb template forkyBlck: untyped {.inject, used.} = x.denebData body of ConsensusFork.Electra: const consensusFork {.inject, used.} = ConsensusFork.Electra template forkyBlck: untyped {.inject, used.} = x.electraData body func proposer_index*(x: ForkedBeaconBlock): uint64 = withBlck(x): forkyBlck.proposer_index func hash_tree_root*(x: ForkedBeaconBlock): Eth2Digest = withBlck(x): hash_tree_root(forkyBlck) func hash_tree_root*(x: Web3SignerForkedBeaconBlock): Eth2Digest = hash_tree_root(x.data) func hash_tree_root*(_: Opt[auto]) {.error.} 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 of ConsensusFork.Electra: unsafeAddr x.electraData.message.y)[] template signature*(x: ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock | ForkedSignedBlindedBeaconBlock): ValidatorSig = withBlck(x): forkyBlck.signature template signature*(x: ForkedTrustedSignedBeaconBlock): TrustedSig = withBlck(x): forkyBlck.signature template root*(x: ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock): Eth2Digest = withBlck(x): forkyBlck.root template slot*(x: ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock): Slot = withBlck(x): forkyBlck.message.slot template shortLog*(x: ForkedBeaconBlock | ForkedBlindedBeaconBlock): auto = withBlck(x): shortLog(forkyBlck) template shortLog*(x: ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock | ForkedSignedBlindedBeaconBlock): auto = withBlck(x): shortLog(forkyBlck) chronicles.formatIt ForkedBeaconBlock: it.shortLog chronicles.formatIt ForkedSignedBeaconBlock: it.shortLog chronicles.formatIt ForkedMsgTrustedSignedBeaconBlock: it.shortLog chronicles.formatIt ForkedTrustedSignedBeaconBlock: it.shortLog template withForkyMaybeBlindedBlck*( b: ForkedMaybeBlindedBeaconBlock, body: untyped): untyped = case b.kind of ConsensusFork.Electra: const consensusFork {.inject, used.} = ConsensusFork.Electra template d: untyped = b.electraData case d.isBlinded: of true: const isBlinded {.inject, used.} = true template forkyMaybeBlindedBlck: untyped {.inject, used.} = d.blindedData body of false: const isBlinded {.inject, used.} = false template forkyMaybeBlindedBlck: untyped {.inject, used.} = d.data body of ConsensusFork.Deneb: const consensusFork {.inject, used.} = ConsensusFork.Deneb template d: untyped = b.denebData case d.isBlinded: of true: const isBlinded {.inject, used.} = true template forkyMaybeBlindedBlck: untyped {.inject, used.} = d.blindedData body of false: const isBlinded {.inject, used.} = false template forkyMaybeBlindedBlck: untyped {.inject, used.} = d.data body of ConsensusFork.Capella: const consensusFork {.inject, used.} = ConsensusFork.Capella isBlinded {.inject, used.} = false template forkyMaybeBlindedBlck: untyped {.inject, used.} = b.capellaData body of ConsensusFork.Bellatrix: const consensusFork {.inject, used.} = ConsensusFork.Bellatrix isBlinded {.inject, used.} = false template forkyMaybeBlindedBlck: untyped {.inject, used.} = b.bellatrixData body of ConsensusFork.Altair: const consensusFork {.inject, used.} = ConsensusFork.Altair isBlinded {.inject, used.} = false template forkyMaybeBlindedBlck: untyped {.inject, used.} = b.altairData body of ConsensusFork.Phase0: const consensusFork {.inject, used.} = ConsensusFork.Phase0 isBlinded {.inject, used.} = false template forkyMaybeBlindedBlck: untyped {.inject, used.} = b.phase0Data body template shortLog*(x: ForkedMaybeBlindedBeaconBlock): auto = withForkyMaybeBlindedBlck(x): when consensusFork >= ConsensusFork.Deneb: when isBlinded == true: shortLog(forkyMaybeBlindedBlck) else: shortLog(forkyMaybeBlindedBlck.`block`) else: shortLog(forkyMaybeBlindedBlck) template withStateAndBlck*( s: ForkedHashedBeaconState, b: ForkedBeaconBlock | ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock, body: untyped): untyped = case s.kind of ConsensusFork.Electra: const consensusFork {.inject, used.} = ConsensusFork.Electra template forkyState: untyped {.inject.} = s.electraData template forkyBlck: untyped {.inject.} = b.electraData body of ConsensusFork.Deneb: const consensusFork {.inject, used.} = ConsensusFork.Deneb template forkyState: untyped {.inject.} = s.denebData template forkyBlck: untyped {.inject.} = b.denebData body of ConsensusFork.Capella: const consensusFork {.inject, used.} = ConsensusFork.Capella template forkyState: untyped {.inject.} = s.capellaData template forkyBlck: untyped {.inject.} = b.capellaData body of ConsensusFork.Bellatrix: const consensusFork {.inject, used.} = ConsensusFork.Bellatrix template forkyState: untyped {.inject.} = s.bellatrixData template forkyBlck: untyped {.inject.} = b.bellatrixData body of ConsensusFork.Altair: const consensusFork {.inject, used.} = ConsensusFork.Altair template forkyState: untyped {.inject.} = s.altairData template forkyBlck: untyped {.inject.} = b.altairData body of ConsensusFork.Phase0: const consensusFork {.inject, used.} = ConsensusFork.Phase0 template forkyState: untyped {.inject, used.} = s.phase0Data template forkyBlck: untyped {.inject, used.} = b.phase0Data body func toBeaconBlockHeader*( blck: SomeForkyBeaconBlock | deneb_mev.BlindedBeaconBlock | electra_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): forkyBlck.toBeaconBlockHeader() func toSignedBeaconBlockHeader*( signedBlock: SomeForkySignedBeaconBlock | deneb_mev.SignedBlindedBeaconBlock): SignedBeaconBlockHeader = ## Reduce a given `SignedBeaconBlock` to its `SignedBeaconBlockHeader`. SignedBeaconBlockHeader( message: signedBlock.message.toBeaconBlockHeader(), signature: signedBlock.signature) 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 electraFork*(cfg: RuntimeConfig): Fork = Fork( previous_version: cfg.DENEB_FORK_VERSION, current_version: cfg.ELECTRA_FORK_VERSION, epoch: cfg.ELECTRA_FORK_EPOCH) func forkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Fork = case cfg.consensusForkAtEpoch(epoch) of ConsensusFork.Electra: cfg.electraFork 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.Electra: cfg.ELECTRA_FORK_VERSION 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 = case cfg.consensusForkAtEpoch(epoch) of ConsensusFork.Electra: FAR_FUTURE_EPOCH of ConsensusFork.Deneb: cfg.ELECTRA_FORK_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 of ConsensusFork.Electra: cfg.ELECTRA_FORK_VERSION func blobForkAtConsensusFork*(consensusFork: ConsensusFork): Opt[BlobFork] = static: doAssert BlobFork.high == BlobFork.Deneb if consensusFork >= ConsensusFork.Deneb: Opt.some BlobFork.Deneb else: Opt.none BlobFork func lcDataForkAtConsensusFork*( consensusFork: ConsensusFork): LightClientDataFork = static: doAssert LightClientDataFork.high == LightClientDataFork.Electra if consensusFork >= ConsensusFork.Electra: LightClientDataFork.Electra elif consensusFork >= ConsensusFork.Deneb: LightClientDataFork.Deneb elif consensusFork >= ConsensusFork.Capella: LightClientDataFork.Capella elif consensusFork >= 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*( consensusFork: ConsensusFork, data: openArray[byte]): ForkedHashedBeaconState {.raises: [SszError].} = # TODO https://github.com/nim-lang/Nim/issues/19357 result = ForkedHashedBeaconState(kind: consensusFork) withState(result): readSszBytes(data, forkyState.data) forkyState.root = hash_tree_root(forkyState.data) template readSszForkedHashedBeaconState*( cfg: RuntimeConfig, slot: Slot, data: openArray[byte]): ForkedHashedBeaconState = cfg.consensusForkAtEpoch(slot.epoch()).readSszForkedHashedBeaconState(data) func readSszForkedHashedBeaconState*(cfg: RuntimeConfig, data: openArray[byte]): ForkedHashedBeaconState {.raises: [SerializationError].} = ## Read a state picking the right fork by first reading the slot from the byte ## source const numHeaderBytes = fixedPortionSize(BeaconStateHeader) if data.len() < numHeaderBytes: raise (ref MalformedSszError)(msg: "Incomplete BeaconState header") let header = SSZ.decode( data.toOpenArray(0, numHeaderBytes - 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: [SerializationError].} = ## Helper to read a header from bytes when it's not certain what kind of block ## it is const numHeaderBytes = fixedPortionSize(ForkedBeaconBlockHeader) if data.len() < numHeaderBytes: raise (ref MalformedSszError)(msg: "Incomplete SignedBeaconBlock header") let header = SSZ.decode( data.toOpenArray(0, numHeaderBytes - 1), ForkedBeaconBlockHeader) # TODO https://github.com/nim-lang/Nim/issues/19357 result = ForkedSignedBeaconBlock( kind: cfg.consensusForkAtEpoch(header.slot.epoch())) withBlck(result): readSszBytes(data, forkyBlck) func readSszForkedBlobSidecar*( cfg: RuntimeConfig, data: openArray[byte] ): ForkedBlobSidecar {.raises: [SerializationError].} = ## Helper to read `BlobSidecar` from bytes when it's not certain what ## `BlobFork` it is type ForkedBlobSidecarHeader = object index: BlobIndex blob: Blob kzg_commitment: KzgCommitment kzg_proof: KzgProof signed_block_header*: SignedBeaconBlockHeader const numHeaderBytes = fixedPortionSize(ForkedBlobSidecarHeader) if data.len() < numHeaderBytes: raise (ref MalformedSszError)(msg: "Incomplete BlobSidecar header") let header = SSZ.decode( data.toOpenArray(0, numHeaderBytes - 1), ForkedBlobSidecarHeader) consensusFork = cfg.consensusForkAtEpoch( header.signed_block_header.message.slot.epoch) blobFork = blobForkAtConsensusFork(consensusFork).valueOr: raise (ref MalformedSszError)(msg: "BlobSidecar slot is pre-Deneb") # TODO https://github.com/nim-lang/Nim/issues/19357 result = ForkedBlobSidecar(kind: blobFork) withForkyBlob(result): forkyBlob = new blobFork.BlobSidecar() readSszBytes(data, forkyBlob[]) # https://github.com/ethereum/consensus-specs/blob/v1.4.0/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.4.0-beta.6/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.Electra 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), deneb: compute_fork_digest(cfg.DENEB_FORK_VERSION, genesis_validators_root), electra: compute_fork_digest(cfg.ELECTRA_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: forkyBlck.root, slot: forkyBlck.message.slot) func historical_summaries*(state: ForkedHashedBeaconState): HashList[HistoricalSummary, Limit HISTORICAL_ROOTS_LIMIT] = withState(state): when consensusFork >= ConsensusFork.Capella: forkyState.data.historical_summaries else: HashList[HistoricalSummary, Limit HISTORICAL_ROOTS_LIMIT]() template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: phase0.BeaconBlock): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Phase0, phase0Data: blck) template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: altair.BeaconBlock): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Altair, altairData: blck) template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: bellatrix.BeaconBlock, evalue: Opt[UInt256], cvalue: Opt[UInt256]): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Bellatrix, bellatrixData: blck, consensusValue: cvalue, executionValue: evalue) template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: capella.BeaconBlock, evalue: Opt[UInt256], cvalue: Opt[UInt256]): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Capella, capellaData: blck, consensusValue: cvalue, executionValue: evalue) template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: deneb.BlockContents, evalue: Opt[UInt256], cvalue: Opt[UInt256]): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Deneb, denebData: deneb_mev.MaybeBlindedBeaconBlock( isBlinded: false, data: blck), consensusValue: cvalue, executionValue: evalue) template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: deneb_mev.BlindedBeaconBlock, evalue: Opt[UInt256], cvalue: Opt[UInt256]): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Deneb, denebData: deneb_mev.MaybeBlindedBeaconBlock( isBlinded: true, blindedData: blck), consensusValue: cvalue, executionValue: evalue) template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: electra.BlockContents, evalue: Opt[UInt256], cvalue: Opt[UInt256]): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Electra, electraData: electra_mev.MaybeBlindedBeaconBlock( isBlinded: false, data: blck), consensusValue: cvalue, executionValue: evalue) template init*(T: type ForkedMaybeBlindedBeaconBlock, blck: electra_mev.BlindedBeaconBlock, evalue: Opt[UInt256], cvalue: Opt[UInt256]): T = ForkedMaybeBlindedBeaconBlock( kind: ConsensusFork.Electra, electraData: electra_mev.MaybeBlindedBeaconBlock( isBlinded: true, blindedData: blck), consensusValue: cvalue, executionValue: evalue) func committee_index*( v: phase0.Attestation, on_chain: static bool = false): uint64 = v.data.index func committee_index*(v: electra.Attestation, on_chain: static bool): uint64 = when on_chain: {.error: "cannot get single committee_index for on_chain attestation".} else: uint64 v.committee_bits.get_committee_index_one().expect("network attestation")