587 lines
22 KiB
Nim
587 lines
22 KiB
Nim
# beacon_chain
|
|
# Copyright (c) 2021-2022 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: [Defect].}
|
|
|
|
import
|
|
stew/assign2,
|
|
chronicles,
|
|
../extras,
|
|
"."/[block_id, eth2_merkleization, eth2_ssz_serialization, presets],
|
|
./datatypes/[phase0, altair, bellatrix]
|
|
|
|
export
|
|
extras, block_id, phase0, altair, bellatrix, eth2_merkleization,
|
|
eth2_ssz_serialization, presets
|
|
|
|
# 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
|
|
BeaconStateFork* {.pure.} = enum
|
|
Phase0,
|
|
Altair,
|
|
Bellatrix
|
|
|
|
ForkyBeaconState* =
|
|
phase0.BeaconState |
|
|
altair.BeaconState |
|
|
bellatrix.BeaconState
|
|
|
|
ForkyHashedBeaconState* =
|
|
phase0.HashedBeaconState |
|
|
altair.HashedBeaconState |
|
|
bellatrix.HashedBeaconState
|
|
|
|
ForkedHashedBeaconState* = object
|
|
case kind*: BeaconStateFork
|
|
of BeaconStateFork.Phase0: phase0Data*: phase0.HashedBeaconState
|
|
of BeaconStateFork.Altair: altairData*: altair.HashedBeaconState
|
|
of BeaconStateFork.Bellatrix: bellatrixData*: bellatrix.HashedBeaconState
|
|
|
|
BeaconBlockFork* {.pure.} = enum
|
|
Phase0
|
|
Altair
|
|
Bellatrix
|
|
|
|
ForkyBeaconBlockBody* =
|
|
phase0.BeaconBlockBody |
|
|
altair.BeaconBlockBody |
|
|
bellatrix.BeaconBlockBody
|
|
|
|
ForkySigVerifiedBeaconBlockBody* =
|
|
phase0.SigVerifiedBeaconBlockBody |
|
|
altair.SigVerifiedBeaconBlockBody |
|
|
bellatrix.SigVerifiedBeaconBlockBody
|
|
|
|
ForkyTrustedBeaconBlockBody* =
|
|
phase0.TrustedBeaconBlockBody |
|
|
altair.TrustedBeaconBlockBody |
|
|
bellatrix.TrustedBeaconBlockBody
|
|
|
|
SomeForkyBeaconBlockBody* =
|
|
ForkyBeaconBlockBody |
|
|
ForkySigVerifiedBeaconBlockBody |
|
|
ForkyTrustedBeaconBlockBody
|
|
|
|
ForkyBeaconBlock* =
|
|
phase0.BeaconBlock |
|
|
altair.BeaconBlock |
|
|
bellatrix.BeaconBlock
|
|
|
|
ForkySigVerifiedBeaconBlock* =
|
|
phase0.SigVerifiedBeaconBlock |
|
|
altair.SigVerifiedBeaconBlock |
|
|
bellatrix.SigVerifiedBeaconBlock
|
|
|
|
ForkyTrustedBeaconBlock* =
|
|
phase0.TrustedBeaconBlock |
|
|
altair.TrustedBeaconBlock |
|
|
bellatrix.TrustedBeaconBlock
|
|
|
|
SomeForkyBeaconBlock* =
|
|
ForkyBeaconBlock |
|
|
ForkySigVerifiedBeaconBlock |
|
|
ForkyTrustedBeaconBlock
|
|
|
|
ForkedBeaconBlock* = object
|
|
case kind*: BeaconBlockFork
|
|
of BeaconBlockFork.Phase0: phase0Data*: phase0.BeaconBlock
|
|
of BeaconBlockFork.Altair: altairData*: altair.BeaconBlock
|
|
of BeaconBlockFork.Bellatrix: bellatrixData*: bellatrix.BeaconBlock
|
|
|
|
ForkedTrustedBeaconBlock* = object
|
|
case kind*: BeaconBlockFork
|
|
of BeaconBlockFork.Phase0: phase0Data*: phase0.TrustedBeaconBlock
|
|
of BeaconBlockFork.Altair: altairData*: altair.TrustedBeaconBlock
|
|
of BeaconBlockFork.Bellatrix: bellatrixData*: bellatrix.TrustedBeaconBlock
|
|
|
|
ForkySignedBeaconBlock* =
|
|
phase0.SignedBeaconBlock |
|
|
altair.SignedBeaconBlock |
|
|
bellatrix.SignedBeaconBlock
|
|
|
|
ForkedSignedBeaconBlock* = object
|
|
case kind*: BeaconBlockFork
|
|
of BeaconBlockFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
|
|
of BeaconBlockFork.Altair: altairData*: altair.SignedBeaconBlock
|
|
of BeaconBlockFork.Bellatrix: bellatrixData*: bellatrix.SignedBeaconBlock
|
|
|
|
ForkySigVerifiedSignedBeaconBlock* =
|
|
phase0.SigVerifiedSignedBeaconBlock |
|
|
altair.SigVerifiedSignedBeaconBlock |
|
|
bellatrix.SigVerifiedSignedBeaconBlock
|
|
|
|
ForkyTrustedSignedBeaconBlock* =
|
|
phase0.TrustedSignedBeaconBlock |
|
|
altair.TrustedSignedBeaconBlock |
|
|
bellatrix.TrustedSignedBeaconBlock
|
|
|
|
ForkedTrustedSignedBeaconBlock* = object
|
|
case kind*: BeaconBlockFork
|
|
of BeaconBlockFork.Phase0: phase0Data*: phase0.TrustedSignedBeaconBlock
|
|
of BeaconBlockFork.Altair: altairData*: altair.TrustedSignedBeaconBlock
|
|
of BeaconBlockFork.Bellatrix: bellatrixData*: bellatrix.TrustedSignedBeaconBlock
|
|
|
|
SomeForkySignedBeaconBlock* =
|
|
ForkySignedBeaconBlock |
|
|
ForkySigVerifiedSignedBeaconBlock |
|
|
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
|
|
sharding*: ForkDigest
|
|
|
|
template toFork*[T: phase0.BeaconState | phase0.HashedBeaconState](
|
|
t: type T): BeaconStateFork =
|
|
BeaconStateFork.Phase0
|
|
template toFork*[T: altair.BeaconState | altair.HashedBeaconState](
|
|
t: type T): BeaconStateFork =
|
|
BeaconStateFork.Altair
|
|
template toFork*[T: bellatrix.BeaconState | bellatrix.HashedBeaconState](
|
|
t: type T): BeaconStateFork =
|
|
BeaconStateFork.Bellatrix
|
|
|
|
# TODO these cause stack overflows due to large temporaries getting allocated
|
|
# template init*(T: type ForkedHashedBeaconState, data: phase0.HashedBeaconState): T =
|
|
# T(kind: BeaconStateFork.Phase0, phase0Data: data)
|
|
# template init*(T: type ForkedHashedBeaconState, data: altair.HashedBeaconState): T =
|
|
# T(kind: BeaconStateFork.Altair, altairData: data)
|
|
# template init*(T: type ForkedHashedBeaconState, data: bellatrix.HashedBeaconState): T =
|
|
# T(kind: BeaconStateFork.Bellatrix, bellatrixData: data)
|
|
|
|
template init*(T: type ForkedBeaconBlock, blck: phase0.BeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
|
|
template init*(T: type ForkedBeaconBlock, blck: altair.BeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Altair, altairData: blck)
|
|
template init*(T: type ForkedBeaconBlock, blck: bellatrix.BeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Bellatrix, bellatrixData: blck)
|
|
|
|
template init*(T: type ForkedTrustedBeaconBlock, blck: phase0.TrustedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
|
|
template init*(T: type ForkedTrustedBeaconBlock, blck: altair.TrustedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Altair, altairData: blck)
|
|
template init*(T: type ForkedTrustedBeaconBlock, blck: bellatrix.TrustedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Bellatrix, bellatrixData: blck)
|
|
|
|
template init*(T: type ForkedSignedBeaconBlock, blck: phase0.SignedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
|
|
template init*(T: type ForkedSignedBeaconBlock, blck: altair.SignedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Altair, altairData: blck)
|
|
template init*(T: type ForkedSignedBeaconBlock, blck: bellatrix.SignedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Bellatrix, bellatrixData: blck)
|
|
|
|
template init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
|
|
blockRoot: Eth2Digest, signature: ValidatorSig): T =
|
|
case forked.kind
|
|
of BeaconBlockFork.Phase0:
|
|
T(kind: BeaconBlockFork.Phase0,
|
|
phase0Data: phase0.SignedBeaconBlock(message: forked.phase0Data,
|
|
root: blockRoot,
|
|
signature: signature))
|
|
of BeaconBlockFork.Altair:
|
|
T(kind: BeaconBlockFork.Altair,
|
|
altairData: altair.SignedBeaconBlock(message: forked.altairData,
|
|
root: blockRoot,
|
|
signature: signature))
|
|
of BeaconBlockFork.Bellatrix:
|
|
T(kind: BeaconBlockFork.Bellatrix,
|
|
bellatrixData: bellatrix.SignedBeaconBlock(message: forked.bellatrixData,
|
|
root: blockRoot,
|
|
signature: signature))
|
|
|
|
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: phase0.TrustedSignedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
|
|
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: altair.TrustedSignedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Altair, altairData: blck)
|
|
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: bellatrix.TrustedSignedBeaconBlock): T =
|
|
T(kind: BeaconBlockFork.Bellatrix, bellatrixData: blck)
|
|
|
|
template toFork*[T:
|
|
phase0.SignedBeaconBlock |
|
|
phase0.SigVerifiedSignedBeaconBlock |
|
|
phase0.TrustedSignedBeaconBlock](
|
|
t: type T): BeaconBlockFork =
|
|
BeaconBlockFork.Phase0
|
|
template toFork*[T:
|
|
altair.SignedBeaconBlock |
|
|
altair.SigVerifiedSignedBeaconBlock |
|
|
altair.TrustedSignedBeaconBlock](
|
|
t: type T): BeaconBlockFork =
|
|
BeaconBlockFork.Altair
|
|
template toFork*[T:
|
|
bellatrix.SignedBeaconBlock |
|
|
bellatrix.SigVerifiedSignedBeaconBlock |
|
|
bellatrix.TrustedSignedBeaconBlock](
|
|
t: type T): BeaconBlockFork =
|
|
BeaconBlockFork.Bellatrix
|
|
|
|
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 BeaconStateFork.Bellatrix:
|
|
const stateFork {.inject, used.} = BeaconStateFork.Bellatrix
|
|
template state: untyped {.inject, used.} = x.bellatrixData
|
|
body
|
|
of BeaconStateFork.Altair:
|
|
const stateFork {.inject, used.} = BeaconStateFork.Altair
|
|
template state: untyped {.inject, used.} = x.altairData
|
|
body
|
|
of BeaconStateFork.Phase0:
|
|
const stateFork {.inject, used.} = BeaconStateFork.Phase0
|
|
template state: 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 =
|
|
x.kind = EpochInfoFork.Phase0
|
|
template info: untyped {.inject.} = x.phase0Data
|
|
body
|
|
|
|
template withEpochInfo*(
|
|
state: altair.BeaconState | bellatrix.BeaconState, x: var ForkedEpochInfo,
|
|
body: untyped): untyped =
|
|
x.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 BeaconStateFork.Bellatrix:
|
|
assign(tgt.bellatrixData, src.bellatrixData):
|
|
of BeaconStateFork.Altair:
|
|
assign(tgt.altairData, src.altairData):
|
|
of BeaconStateFork.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).pairs():
|
|
# ```
|
|
# Without `unsafeAddr`, the `validators` list would be copied to a temporary variable.
|
|
(case x.kind
|
|
of BeaconStateFork.Bellatrix: unsafeAddr x.bellatrixData.data.y
|
|
of BeaconStateFork.Altair: unsafeAddr x.altairData.data.y
|
|
of BeaconStateFork.Phase0: unsafeAddr x.phase0Data.data.y)[]
|
|
|
|
func getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest =
|
|
withState(x): state.root
|
|
|
|
func setStateRoot*(x: var ForkedHashedBeaconState, root: Eth2Digest) =
|
|
withState(x): state.root = root
|
|
|
|
func stateForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): BeaconStateFork =
|
|
## Return the current fork for the given epoch.
|
|
static:
|
|
doAssert BeaconStateFork.Bellatrix > BeaconStateFork.Altair
|
|
doAssert BeaconStateFork.Altair > BeaconStateFork.Phase0
|
|
doAssert GENESIS_EPOCH == 0
|
|
|
|
if epoch >= cfg.BELLATRIX_FORK_EPOCH: BeaconStateFork.Bellatrix
|
|
elif epoch >= cfg.ALTAIR_FORK_EPOCH: BeaconStateFork.Altair
|
|
else: BeaconStateFork.Phase0
|
|
|
|
func blockForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): BeaconBlockFork =
|
|
## Return the current fork for the given epoch.
|
|
if epoch >= cfg.BELLATRIX_FORK_EPOCH: BeaconBlockFork.Bellatrix
|
|
elif epoch >= cfg.ALTAIR_FORK_EPOCH: BeaconBlockFork.Altair
|
|
else: BeaconBlockFork.Phase0
|
|
|
|
template asSigned*(x: ForkedTrustedSignedBeaconBlock): ForkedSignedBeaconBlock =
|
|
isomorphicCast[ForkedSignedBeaconBlock](x)
|
|
|
|
template asTrusted*(x: ForkedSignedBeaconBlock): ForkedTrustedSignedBeaconBlock =
|
|
isomorphicCast[ForkedTrustedSignedBeaconBlock](x)
|
|
|
|
template withBlck*(
|
|
x: ForkedBeaconBlock | ForkedSignedBeaconBlock |
|
|
ForkedTrustedSignedBeaconBlock,
|
|
body: untyped): untyped =
|
|
case x.kind
|
|
of BeaconBlockFork.Phase0:
|
|
const stateFork {.inject, used.} = BeaconStateFork.Phase0
|
|
template blck: untyped {.inject.} = x.phase0Data
|
|
body
|
|
of BeaconBlockFork.Altair:
|
|
const stateFork {.inject, used.} = BeaconStateFork.Altair
|
|
template blck: untyped {.inject.} = x.altairData
|
|
body
|
|
of BeaconBlockFork.Bellatrix:
|
|
const stateFork {.inject, used.} = BeaconStateFork.Bellatrix
|
|
template blck: untyped {.inject.} = x.bellatrixData
|
|
body
|
|
|
|
func proposer_index*(x: ForkedBeaconBlock): uint64 =
|
|
withBlck(x): blck.proposer_index
|
|
|
|
func hash_tree_root*(x: ForkedBeaconBlock): Eth2Digest =
|
|
withBlck(x): hash_tree_root(blck)
|
|
|
|
template getForkedBlockField*(x: ForkedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock, y: untyped): untyped =
|
|
# unsafeAddr avoids a copy of the field in some cases
|
|
(case x.kind
|
|
of BeaconBlockFork.Phase0: unsafeAddr x.phase0Data.message.y
|
|
of BeaconBlockFork.Altair: unsafeAddr x.altairData.message.y
|
|
of BeaconBlockFork.Bellatrix: unsafeAddr x.bellatrixData.message.y)[]
|
|
|
|
template signature*(x: ForkedSignedBeaconBlock): ValidatorSig =
|
|
withBlck(x): blck.signature
|
|
|
|
template signature*(x: ForkedTrustedSignedBeaconBlock): TrustedSig =
|
|
withBlck(x): blck.signature
|
|
|
|
template root*(x: ForkedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock): Eth2Digest =
|
|
withBlck(x): blck.root
|
|
|
|
template slot*(x: ForkedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock): Slot =
|
|
withBlck(x): blck.message.slot
|
|
|
|
template shortLog*(x: ForkedBeaconBlock): auto =
|
|
withBlck(x): shortLog(blck)
|
|
|
|
template shortLog*(x: ForkedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock): auto =
|
|
withBlck(x): shortLog(blck)
|
|
|
|
chronicles.formatIt ForkedBeaconBlock: it.shortLog
|
|
chronicles.formatIt ForkedSignedBeaconBlock: it.shortLog
|
|
chronicles.formatIt ForkedTrustedSignedBeaconBlock: it.shortLog
|
|
|
|
template withStateAndBlck*(
|
|
s: ForkedHashedBeaconState,
|
|
b: ForkedBeaconBlock | ForkedSignedBeaconBlock |
|
|
ForkedTrustedSignedBeaconBlock,
|
|
body: untyped): untyped =
|
|
case s.kind
|
|
of BeaconStateFork.Bellatrix:
|
|
const stateFork {.inject.} = BeaconStateFork.Bellatrix
|
|
template state: untyped {.inject.} = s.bellatrixData
|
|
template blck: untyped {.inject.} = b.bellatrixData
|
|
body
|
|
of BeaconStateFork.Altair:
|
|
const stateFork {.inject.} = BeaconStateFork.Altair
|
|
template state: untyped {.inject.} = s.altairData
|
|
template blck: untyped {.inject.} = b.altairData
|
|
body
|
|
of BeaconStateFork.Phase0:
|
|
const stateFork {.inject.} = BeaconStateFork.Phase0
|
|
template state: untyped {.inject.} = s.phase0Data
|
|
template blck: untyped {.inject.} = b.phase0Data
|
|
body
|
|
|
|
func toBeaconBlockHeader*(
|
|
blck: SomeForkyBeaconBlock): 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: ForkedTrustedSignedBeaconBlock): BeaconBlockHeader =
|
|
## Reduce a given `ForkedTrustedSignedBeaconBlock` 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 =
|
|
# TODO in theory, the altair + merge forks could be in same epoch, so the
|
|
# previous fork version would be the GENESIS_FORK_VERSION
|
|
Fork(
|
|
previous_version: cfg.ALTAIR_FORK_VERSION,
|
|
current_version: cfg.BELLATRIX_FORK_VERSION,
|
|
epoch: cfg.BELLATRIX_FORK_EPOCH)
|
|
|
|
func forkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Fork =
|
|
case cfg.stateForkAtEpoch(epoch)
|
|
of BeaconStateFork.Bellatrix: cfg.bellatrixFork
|
|
of BeaconStateFork.Altair: cfg.altairFork
|
|
of BeaconStateFork.Phase0: cfg.genesisFork
|
|
|
|
func forkVersionAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Version =
|
|
case cfg.stateForkAtEpoch(epoch)
|
|
of BeaconStateFork.Bellatrix: cfg.BELLATRIX_FORK_VERSION
|
|
of BeaconStateFork.Altair: cfg.ALTAIR_FORK_VERSION
|
|
of BeaconStateFork.Phase0: cfg.GENESIS_FORK_VERSION
|
|
|
|
func nextForkEpochAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Epoch =
|
|
case cfg.stateForkAtEpoch(epoch)
|
|
of BeaconStateFork.Bellatrix: FAR_FUTURE_EPOCH
|
|
of BeaconStateFork.Altair: cfg.BELLATRIX_FORK_EPOCH
|
|
of BeaconStateFork.Phase0: cfg.ALTAIR_FORK_EPOCH
|
|
|
|
func getForkSchedule*(cfg: RuntimeConfig): array[3, 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()]
|
|
|
|
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, data: openArray[byte]):
|
|
ForkedHashedBeaconState {.raises: [Defect, SszError].} =
|
|
## Helper to read a header from bytes when it's not certain what kind of state
|
|
## it is - this happens for example when loading an SSZ state from command
|
|
## line
|
|
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 = ForkedHashedBeaconState(
|
|
kind: cfg.stateForkAtEpoch(header.slot.epoch()))
|
|
|
|
withState(result):
|
|
readSszBytes(data, state.data)
|
|
state.root = hash_tree_root(state.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.blockForkAtEpoch(header.slot.epoch()))
|
|
|
|
withBlck(result):
|
|
readSszBytes(data, blck)
|
|
|
|
func toBeaconBlockFork*(fork: BeaconStateFork): BeaconBlockFork =
|
|
case fork
|
|
of BeaconStateFork.Phase0: BeaconBlockFork.Phase0
|
|
of BeaconStateFork.Altair: BeaconBlockFork.Altair
|
|
of BeaconStateFork.Bellatrix: BeaconBlockFork.Bellatrix
|
|
|
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/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.1.10/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 =
|
|
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),
|
|
sharding:
|
|
compute_fork_digest(cfg.SHARDING_FORK_VERSION, genesis_validators_root),
|
|
)
|
|
|
|
func toBlockId*(blck: SomeForkySignedBeaconBlock): BlockId =
|
|
BlockId(root: blck.root, slot: blck.message.slot)
|
|
|
|
func toBlockId*(blck: ForkedSignedBeaconBlock | ForkedTrustedSignedBeaconBlock): BlockId =
|
|
withBlck(blck): BlockId(root: blck.root, slot: blck.message.slot)
|