add EIP-7044 support to keymanager API (#5959)
* add EIP-7044 support to keymanager API When trying to sign `VoluntaryExit` via keymanager API, the logic is not yet aware of EIP-7044 (part of Deneb). This patch adds missing EIP-7044 support to the keymanager API as well. As part of this, the VC needs to become aware about: - `CAPELLA_FORK_VERSION`: To correctly form the EIP-7044 signing domain. The fork schedule does not indicate which of the results, if any, corresponds to Capella. - `CAPELLA_FORK_EPOCH`: To detect whether Capella was scheduled. If a BN does not have it in its config while other BNs have it, this leads to a log if Capella has not activated yet, or marks the BN as incompatible if Capella already activated. - `DENEB_FORK_EPOCH`: To check whether EIP-7044 logic should be used. Related PRs: - #5120 added support for processing EIP-7044 `VoluntaryExit` messages as part of the state transition functions (tested by EF spec tests). - #5953 synced the support from #5120 to gossip validation. - #5954 added support to the `nimbus_beacon_node deposits exit` command. - #5956 contains an alternative generic version of `VCForkConfig`. * address reviewer feedback: letter case, module location, double lookup --------- Co-authored-by: cheatfate <eugene.kabanov@status.im> * Update beacon_chain/rpc/rest_constants.nim * move `VCRuntimeConfig` back to `rest_types` --------- Co-authored-by: cheatfate <eugene.kabanov@status.im> * fix `getForkVersion` helper --------- Co-authored-by: cheatfate <eugene.kabanov@status.im>
This commit is contained in:
parent
00510a9d2f
commit
4e9bc7f570
|
@ -220,33 +220,19 @@ proc restValidatorExit(config: BeaconNodeConf) {.async.} =
|
|||
reason = exc.msg
|
||||
quit 1
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#voluntary-exits
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/beacon-chain.md#modified-process_voluntary_exit
|
||||
let signingFork = try:
|
||||
let response = await client.getSpecVC()
|
||||
if response.status == 200:
|
||||
let
|
||||
spec = response.data.data
|
||||
denebForkEpoch =
|
||||
block:
|
||||
let s = spec.getOrDefault("DENEB_FORK_EPOCH", $FAR_FUTURE_EPOCH)
|
||||
Epoch(Base10.decode(uint64, s).get(uint64(FAR_FUTURE_EPOCH)))
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#voluntary-exits
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/beacon-chain.md#modified-process_voluntary_exit
|
||||
if currentEpoch >= denebForkEpoch:
|
||||
let capellaForkVersion =
|
||||
block:
|
||||
var res: Version
|
||||
# CAPELLA_FOR_VERSION has specific format - "0x01000000", so
|
||||
# default empty string is invalid, so `hexToByteArrayStrict`
|
||||
# will raise exception on empty string.
|
||||
let s = spec.getOrDefault("CAPELLA_FORK_VERSION", "")
|
||||
hexToByteArrayStrict(s, distinctBase(res))
|
||||
res
|
||||
Fork(
|
||||
current_version: capellaForkVersion,
|
||||
previous_version: capellaForkVersion,
|
||||
epoch: GENESIS_EPOCH) # irrelevant when current/previous identical
|
||||
else:
|
||||
fork
|
||||
let forkConfig = response.data.data.getConsensusForkConfig()
|
||||
if forkConfig.isErr:
|
||||
raise newException(RestError, "Invalid config: " & forkConfig.error)
|
||||
let capellaForkVersion = forkConfig.get.capellaVersion.valueOr:
|
||||
raise newException(RestError,
|
||||
ConsensusFork.Capella.forkVersionConfigKey() & " missing")
|
||||
voluntary_exit_signature_fork(
|
||||
fork, capellaForkVersion, currentEpoch, forkConfig.get.denebEpoch)
|
||||
else:
|
||||
raise newException(RestError, "Error response (" & $response.status & ")")
|
||||
except CatchableError as exc:
|
||||
|
|
|
@ -755,6 +755,12 @@ proc init*(T: type BeaconNode,
|
|||
withState(dag.headState):
|
||||
getValidator(forkyState().data.validators.asSeq(), pubkey)
|
||||
|
||||
func getCapellaForkVersion(): Opt[Version] =
|
||||
Opt.some(cfg.CAPELLA_FORK_VERSION)
|
||||
|
||||
func getDenebForkEpoch(): Opt[Epoch] =
|
||||
Opt.some(cfg.DENEB_FORK_EPOCH)
|
||||
|
||||
proc getForkForEpoch(epoch: Epoch): Opt[Fork] =
|
||||
Opt.some(dag.forkAtEpoch(epoch))
|
||||
|
||||
|
@ -784,6 +790,8 @@ proc init*(T: type BeaconNode,
|
|||
config.getPayloadBuilderAddress,
|
||||
getValidatorAndIdx,
|
||||
getBeaconTime,
|
||||
getCapellaForkVersion,
|
||||
getDenebForkEpoch,
|
||||
getForkForEpoch,
|
||||
getGenesisRoot)
|
||||
else: nil
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
# * 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
|
||||
stew/io2, presto, metrics, metrics/chronos_httpserver,
|
||||
./rpc/rest_key_management_api,
|
||||
|
@ -348,6 +351,18 @@ proc asyncInit(vc: ValidatorClientRef): Future[ValidatorClientRef] {.async.} =
|
|||
let
|
||||
keymanagerInitResult = initKeymanagerServer(vc.config, nil)
|
||||
|
||||
func getCapellaForkVersion(): Opt[Version] =
|
||||
if vc.runtimeConfig.forkConfig.isSome():
|
||||
vc.runtimeConfig.forkConfig.get().capellaVersion
|
||||
else:
|
||||
Opt.none(Version)
|
||||
|
||||
func getDenebForkEpoch(): Opt[Epoch] =
|
||||
if vc.runtimeConfig.forkConfig.isSome():
|
||||
Opt.some(vc.runtimeConfig.forkConfig.get().denebEpoch)
|
||||
else:
|
||||
Opt.none(Epoch)
|
||||
|
||||
proc getForkForEpoch(epoch: Epoch): Opt[Fork] =
|
||||
if len(vc.forks) > 0:
|
||||
Opt.some(vc.forkAtEpoch(epoch))
|
||||
|
@ -379,6 +394,8 @@ proc asyncInit(vc: ValidatorClientRef): Future[ValidatorClientRef] {.async.} =
|
|||
Opt.none(string),
|
||||
nil,
|
||||
vc.beaconClock.getBeaconTimeFn,
|
||||
getCapellaForkVersion,
|
||||
getDenebForkEpoch,
|
||||
getForkForEpoch,
|
||||
getGenesisRoot
|
||||
)
|
||||
|
|
|
@ -241,6 +241,10 @@ const
|
|||
"The given Merkle proof is invalid"
|
||||
InvalidMerkleProofIndexError* =
|
||||
"The given Merkle proof index is invalid"
|
||||
FailedToObtainForkVersionError* =
|
||||
"Failed to obtain fork version"
|
||||
FailedToObtainConsensusForkError* =
|
||||
"Failed to obtain consensus fork information"
|
||||
FailedToObtainForkError* =
|
||||
"Failed to obtain fork information"
|
||||
InvalidTimestampValue* =
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
# 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: [].}
|
||||
|
||||
# NOTE: This module has been used in both `beacon_node` and `validator_client`,
|
||||
# please keep imports clear of `rest_utils` or any other module which imports
|
||||
# beacon node's specific networking code.
|
||||
|
@ -561,6 +564,7 @@ proc installKeymanagerHandlers*(router: var RestRouter, host: KeymanagerHost) =
|
|||
let
|
||||
qpubkey = pubkey.valueOr:
|
||||
return keymanagerApiError(Http400, InvalidValidatorPublicKey)
|
||||
currentEpoch = host.getBeaconTimeFn().slotOrZero().epoch()
|
||||
qepoch =
|
||||
if epoch.isSome():
|
||||
let res = epoch.get()
|
||||
|
@ -568,7 +572,7 @@ proc installKeymanagerHandlers*(router: var RestRouter, host: KeymanagerHost) =
|
|||
return keymanagerApiError(Http400, InvalidEpochValueError)
|
||||
res.get()
|
||||
else:
|
||||
host.getBeaconTimeFn().slotOrZero().epoch()
|
||||
currentEpoch
|
||||
validator =
|
||||
block:
|
||||
let res = host.validatorPool[].getValidator(qpubkey).valueOr:
|
||||
|
@ -581,10 +585,16 @@ proc installKeymanagerHandlers*(router: var RestRouter, host: KeymanagerHost) =
|
|||
validator_index: uint64(validator.index.get()))
|
||||
fork = host.getForkFn(qepoch).valueOr:
|
||||
return keymanagerApiError(Http500, FailedToObtainForkError)
|
||||
capellaForkVersion = host.getCapellaForkVersionFn().valueOr:
|
||||
return keymanagerApiError(Http500, FailedToObtainForkVersionError)
|
||||
denebForkEpoch = host.getDenebForkEpochFn().valueOr:
|
||||
return keymanagerApiError(Http500, FailedToObtainConsensusForkError)
|
||||
signingFork = voluntary_exit_signature_fork(
|
||||
fork, capellaForkVersion, currentEpoch, denebForkEpoch)
|
||||
signature =
|
||||
try:
|
||||
let res = await validator.getValidatorExitSignature(
|
||||
fork, host.getGenesisFn(), voluntaryExit)
|
||||
signingFork, host.getGenesisFn(), voluntaryExit)
|
||||
if res.isErr():
|
||||
return keymanagerApiError(Http500, res.error())
|
||||
res.get()
|
||||
|
|
|
@ -13,7 +13,8 @@ import
|
|||
rest_beacon_calls, rest_builder_calls, rest_config_calls, rest_debug_calls,
|
||||
rest_keymanager_calls, rest_light_client_calls,
|
||||
rest_node_calls, rest_validator_calls,
|
||||
rest_nimbus_calls, rest_event_calls, rest_common
|
||||
rest_nimbus_calls, rest_event_calls, rest_common,
|
||||
rest_fork_config
|
||||
]
|
||||
|
||||
export
|
||||
|
@ -21,4 +22,5 @@ export
|
|||
rest_beacon_calls, rest_builder_calls, rest_config_calls, rest_debug_calls,
|
||||
rest_keymanager_calls, rest_light_client_calls,
|
||||
rest_node_calls, rest_validator_calls,
|
||||
rest_nimbus_calls, rest_event_calls, rest_common
|
||||
rest_nimbus_calls, rest_event_calls, rest_common,
|
||||
rest_fork_config
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018-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/strutils,
|
||||
stew/[base10, byteutils],
|
||||
../forks
|
||||
|
||||
from ./rest_types import VCRuntimeConfig
|
||||
|
||||
export forks, rest_types
|
||||
|
||||
type VCForkConfig* = object
|
||||
altairEpoch*: Epoch
|
||||
capellaVersion*: Opt[Version]
|
||||
capellaEpoch*: Epoch
|
||||
denebEpoch*: Epoch
|
||||
|
||||
func forkVersionConfigKey*(consensusFork: ConsensusFork): string =
|
||||
if consensusFork > ConsensusFork.Phase0:
|
||||
($consensusFork).toUpperAscii() & "_FORK_VERSION"
|
||||
else:
|
||||
"GENESIS_FORK_VERSION"
|
||||
|
||||
func forkEpochConfigKey*(consensusFork: ConsensusFork): string =
|
||||
doAssert consensusFork > ConsensusFork.Phase0
|
||||
($consensusFork).toUpperAscii() & "_FORK_EPOCH"
|
||||
|
||||
proc getOrDefault*(info: VCRuntimeConfig, name: string,
|
||||
default: uint64): uint64 =
|
||||
let numstr = info.getOrDefault(name, "missing")
|
||||
if numstr == "missing": return default
|
||||
Base10.decode(uint64, numstr).valueOr:
|
||||
return default
|
||||
|
||||
proc getOrDefault*(info: VCRuntimeConfig, name: string, default: Epoch): Epoch =
|
||||
Epoch(info.getOrDefault(name, uint64(default)))
|
||||
|
||||
func getForkVersion(
|
||||
info: VCRuntimeConfig,
|
||||
consensusFork: Consensusfork): Result[Opt[Version], string] =
|
||||
let key = consensusFork.forkVersionConfigKey()
|
||||
let stringValue = info.getOrDefault(key, "missing")
|
||||
if stringValue == "missing": return ok Opt.none(Version)
|
||||
var value: Version
|
||||
try:
|
||||
hexToByteArrayStrict(stringValue, distinctBase(value))
|
||||
except ValueError as exc:
|
||||
return err(key & " is invalid: " & exc.msg)
|
||||
ok Opt.some value
|
||||
|
||||
func getForkEpoch(info: VCRuntimeConfig, consensusFork: ConsensusFork): Epoch =
|
||||
if consensusFork > ConsensusFork.Phase0:
|
||||
let key = consensusFork.forkEpochConfigKey()
|
||||
info.getOrDefault(key, FAR_FUTURE_EPOCH)
|
||||
else:
|
||||
GENESIS_EPOCH
|
||||
|
||||
func getConsensusForkConfig*(
|
||||
info: VCRuntimeConfig): Result[VCForkConfig, string] =
|
||||
## This extracts all `_FORK_VERSION` and `_FORK_EPOCH` constants
|
||||
## that are relevant for Validator Client operation.
|
||||
##
|
||||
## Note that the fork schedule (`/eth/v1/config/fork_schedule`) cannot be used
|
||||
## because it does not indicate whether the forks refer to `ConsensusFork` or
|
||||
## to a different fork sequence from an incompatible network (e.g., devnet)
|
||||
let
|
||||
res = VCForkConfig(
|
||||
altairEpoch: info.getForkEpoch(ConsensusFork.Altair),
|
||||
capellaVersion: ? info.getForkVersion(ConsensusFork.Capella),
|
||||
capellaEpoch: info.getForkEpoch(ConsensusFork.Capella),
|
||||
denebEpoch: info.getForkEpoch(ConsensusFork.Deneb))
|
||||
|
||||
if res.capellaEpoch < res.altairEpoch:
|
||||
return err(
|
||||
"Fork epochs are inconsistent, " & $ConsensusFork.Capella &
|
||||
" is scheduled at epoch " & $res.capellaEpoch &
|
||||
" which is before prior fork epoch " & $res.altairEpoch)
|
||||
if res.denebEpoch < res.capellaEpoch:
|
||||
return err(
|
||||
"Fork epochs are inconsistent, " & $ConsensusFork.Deneb &
|
||||
" is scheduled at epoch " & $res.denebEpoch &
|
||||
" which is before prior fork epoch " & $res.capellaEpoch)
|
||||
|
||||
if res.capellaEpoch != FAR_FUTURE_EPOCH and res.capellaVersion.isNone:
|
||||
return err(
|
||||
"Beacon node has scheduled " &
|
||||
ConsensusFork.Capella.forkEpochConfigKey() &
|
||||
" but does not report " &
|
||||
ConsensusFork.Capella.forkVersionConfigKey())
|
||||
ok res
|
|
@ -216,11 +216,11 @@ func compute_voluntary_exit_signing_root*(
|
|||
fork, DOMAIN_VOLUNTARY_EXIT, epoch, genesis_validators_root)
|
||||
compute_signing_root(voluntary_exit, domain)
|
||||
|
||||
func voluntary_exit_signature_fork*(
|
||||
consensusFork: static ConsensusFork,
|
||||
func voluntary_exit_signature_fork(
|
||||
is_post_deneb: static bool,
|
||||
state_fork: Fork,
|
||||
capella_fork_version: Version): Fork =
|
||||
when consensusFork >= ConsensusFork.Deneb:
|
||||
when is_post_deneb:
|
||||
# Always use Capella fork version, disregarding `VoluntaryExit` epoch
|
||||
# [Modified in Deneb:EIP7044]
|
||||
Fork(
|
||||
|
@ -230,6 +230,27 @@ func voluntary_exit_signature_fork*(
|
|||
else:
|
||||
state_fork
|
||||
|
||||
func voluntary_exit_signature_fork*(
|
||||
consensusFork: static ConsensusFork,
|
||||
state_fork: Fork,
|
||||
capella_fork_version: Version): Fork =
|
||||
const is_post_deneb = (consensusFork >= ConsensusFork.Deneb)
|
||||
voluntary_exit_signature_fork(is_post_deneb, state_fork, capella_fork_version)
|
||||
|
||||
func voluntary_exit_signature_fork*(
|
||||
state_fork: Fork,
|
||||
capella_fork_version: Version,
|
||||
current_epoch: Epoch,
|
||||
deneb_fork_epoch: Epoch): Fork =
|
||||
if current_epoch >= deneb_fork_epoch:
|
||||
const is_post_deneb = true
|
||||
voluntary_exit_signature_fork(
|
||||
is_post_deneb, state_fork, capella_fork_version)
|
||||
else:
|
||||
const is_post_deneb = false
|
||||
voluntary_exit_signature_fork(
|
||||
is_post_deneb, state_fork, capella_fork_version)
|
||||
|
||||
func get_voluntary_exit_signature*(
|
||||
fork: Fork, genesis_validators_root: Eth2Digest,
|
||||
voluntary_exit: VoluntaryExit,
|
||||
|
|
|
@ -192,7 +192,7 @@ type
|
|||
waiters*: seq[BlockWaiter]
|
||||
|
||||
ValidatorRuntimeConfig* = object
|
||||
altairEpoch*: Opt[Epoch]
|
||||
forkConfig*: Opt[VCForkConfig]
|
||||
|
||||
ValidatorClient* = object
|
||||
config*: ValidatorClientConf
|
||||
|
@ -518,16 +518,6 @@ proc equals*(info: VCRuntimeConfig, name: string, check: DomainType): bool =
|
|||
proc equals*(info: VCRuntimeConfig, name: string, check: Epoch): bool =
|
||||
info.equals(name, uint64(check))
|
||||
|
||||
proc getOrDefault*(info: VCRuntimeConfig, name: string,
|
||||
default: uint64): uint64 =
|
||||
let numstr = info.getOrDefault(name, "missing")
|
||||
if numstr == "missing": return default
|
||||
Base10.decode(uint64, numstr).valueOr:
|
||||
return default
|
||||
|
||||
proc getOrDefault*(info: VCRuntimeConfig, name: string, default: Epoch): Epoch =
|
||||
Epoch(info.getOrDefault(name, uint64(default)))
|
||||
|
||||
proc checkConfig*(c: VCRuntimeConfig): bool =
|
||||
c.equals("MAX_VALIDATORS_PER_COMMITTEE", MAX_VALIDATORS_PER_COMMITTEE) and
|
||||
c.equals("SLOTS_PER_EPOCH", SLOTS_PER_EPOCH) and
|
||||
|
@ -1436,33 +1426,84 @@ func `==`*(a, b: SyncCommitteeDuty): bool =
|
|||
proc updateRuntimeConfig*(vc: ValidatorClientRef,
|
||||
node: BeaconNodeServerRef,
|
||||
info: VCRuntimeConfig): Result[void, string] =
|
||||
if not(info.hasKey("ALTAIR_FORK_EPOCH")):
|
||||
debug "Beacon node's configuration missing ALTAIR_FORK_EPOCH value",
|
||||
node = node
|
||||
var forkConfig = ? info.getConsensusForkConfig()
|
||||
|
||||
let
|
||||
res = info.getOrDefault("ALTAIR_FORK_EPOCH", FAR_FUTURE_EPOCH)
|
||||
wallEpoch = vc.beaconClock.now().slotOrZero().epoch()
|
||||
if vc.runtimeConfig.forkConfig.isNone():
|
||||
vc.runtimeConfig.forkConfig = Opt.some(forkConfig)
|
||||
else:
|
||||
template localForkConfig: untyped = vc.runtimeConfig.forkConfig.get()
|
||||
let wallEpoch = vc.beaconClock.now().slotOrZero().epoch()
|
||||
|
||||
return
|
||||
if vc.runtimeConfig.altairEpoch.get(FAR_FUTURE_EPOCH) == FAR_FUTURE_EPOCH:
|
||||
vc.runtimeConfig.altairEpoch = Opt.some(res)
|
||||
ok()
|
||||
else:
|
||||
if res == vc.runtimeConfig.altairEpoch.get():
|
||||
ok()
|
||||
proc validateForkVersionCompatibility(
|
||||
consensusFork: ConsensusFork,
|
||||
localForkVersion: Opt[Version],
|
||||
localForkEpoch: Epoch,
|
||||
forkVersion: Opt[Version]): Result[void, string] =
|
||||
if localForkVersion.isNone():
|
||||
discard # Potentially discovered new fork, save it at end of function
|
||||
else:
|
||||
if res == FAR_FUTURE_EPOCH:
|
||||
if wallEpoch < vc.runtimeConfig.altairEpoch.get():
|
||||
debug "Beacon node must be updated before Altair activates",
|
||||
node = node,
|
||||
altairForkEpoch = vc.runtimeConfig.altairEpoch.get()
|
||||
ok()
|
||||
if forkVersion.isSome():
|
||||
if forkVersion.get() == localForkVersion.get():
|
||||
discard # Already known
|
||||
else:
|
||||
err("Beacon node must be updated and report correct " &
|
||||
"ALTAIR_FORK_EPOCH value")
|
||||
return err("Beacon node has conflicting " &
|
||||
consensusFork.forkVersionConfigKey() & " value")
|
||||
else:
|
||||
err("Beacon node has conflicting ALTAIR_FORK_EPOCH value")
|
||||
if wallEpoch < localForkEpoch:
|
||||
debug "Beacon node must be updated before fork activates",
|
||||
node = node,
|
||||
consensusFork,
|
||||
forkEpoch = localForkEpoch
|
||||
else:
|
||||
return err("Beacon node must be updated and report correct " &
|
||||
$consensusFork & " config value")
|
||||
|
||||
? ConsensusFork.Capella.validateForkVersionCompatibility(
|
||||
localForkConfig.capellaVersion,
|
||||
localForkConfig.capellaEpoch,
|
||||
forkConfig.capellaVersion)
|
||||
|
||||
proc validateForkEpochCompatibility(
|
||||
consensusFork: ConsensusFork,
|
||||
localForkEpoch: Epoch,
|
||||
forkEpoch: Epoch): Result[void, string] =
|
||||
if localForkEpoch == FAR_FUTURE_EPOCH:
|
||||
discard # Potentially discovered new fork, save it at end of function
|
||||
else:
|
||||
if forkEpoch != FAR_FUTURE_EPOCH:
|
||||
if forkEpoch == localForkEpoch:
|
||||
discard # Already known
|
||||
else:
|
||||
return err("Beacon node has conflicting " &
|
||||
consensusFork.forkEpochConfigKey() & " value")
|
||||
else:
|
||||
if wallEpoch < localForkEpoch:
|
||||
debug "Beacon node must be updated before fork activates",
|
||||
node = node,
|
||||
consensusFork,
|
||||
forkEpoch = localForkEpoch
|
||||
else:
|
||||
return err("Beacon node must be updated and report correct " &
|
||||
$consensusFork & " config value")
|
||||
|
||||
? ConsensusFork.Altair.validateForkEpochCompatibility(
|
||||
localForkConfig.altairEpoch, forkConfig.altairEpoch)
|
||||
? ConsensusFork.Capella.validateForkEpochCompatibility(
|
||||
localForkConfig.capellaEpoch, forkConfig.capellaEpoch)
|
||||
? ConsensusFork.Deneb.validateForkEpochCompatibility(
|
||||
localForkConfig.denebEpoch, forkConfig.denebEpoch)
|
||||
|
||||
# Save newly discovered forks.
|
||||
if localForkConfig.altairEpoch == FAR_FUTURE_EPOCH:
|
||||
localForkConfig.altairEpoch = forkConfig.altairEpoch
|
||||
if localForkConfig.capellaVersion.isNone():
|
||||
localForkConfig.capellaVersion = forkConfig.capellaVersion
|
||||
if localForkConfig.capellaEpoch == FAR_FUTURE_EPOCH:
|
||||
localForkConfig.capellaEpoch = forkConfig.capellaEpoch
|
||||
if localForkConfig.denebEpoch == FAR_FUTURE_EPOCH:
|
||||
localForkConfig.denebEpoch = forkConfig.denebEpoch
|
||||
|
||||
ok()
|
||||
|
||||
proc `+`*(slot: Slot, epochs: Epoch): Slot =
|
||||
slot + uint64(epochs) * SLOTS_PER_EPOCH
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
# * 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/[sets, sequtils]
|
||||
import chronicles, metrics
|
||||
import "."/[common, api, block_service, selection_proofs]
|
||||
|
@ -210,7 +212,8 @@ proc pollForSyncCommitteeDuties*(
|
|||
let
|
||||
vc = service.client
|
||||
indices = toSeq(vc.attachedValidators[].indices())
|
||||
epoch = max(period.start_epoch(), vc.runtimeConfig.altairEpoch.get())
|
||||
altairEpoch = vc.runtimeConfig.forkConfig.get().altairEpoch
|
||||
epoch = max(period.start_epoch(), altairEpoch)
|
||||
relevantDuties =
|
||||
block:
|
||||
var duties: seq[RestSyncCommitteeDuty]
|
||||
|
@ -369,8 +372,11 @@ proc pollForSyncCommitteeDuties*(service: DutiesServiceRef) {.async.} =
|
|||
let
|
||||
currentSlot = vc.getCurrentSlot().get(Slot(0))
|
||||
currentEpoch = currentSlot.epoch()
|
||||
altairEpoch = vc.runtimeConfig.altairEpoch.valueOr:
|
||||
return
|
||||
altairEpoch =
|
||||
if vc.runtimeConfig.forkConfig.isSome():
|
||||
vc.runtimeConfig.forkConfig.get().altairEpoch
|
||||
else:
|
||||
return
|
||||
|
||||
if currentEpoch < altairEpoch:
|
||||
# We are not going to poll for sync committee duties until `altairEpoch`.
|
||||
|
|
|
@ -73,6 +73,10 @@ type
|
|||
proc (pubkey: ValidatorPubKey): Opt[ValidatorAndIndex]
|
||||
{.raises: [], gcsafe.}
|
||||
|
||||
GetCapellaForkVersionFn* =
|
||||
proc (): Opt[Version] {.raises: [], gcsafe.}
|
||||
GetDenebForkEpochFn* =
|
||||
proc (): Opt[Epoch] {.raises: [], gcsafe.}
|
||||
GetForkFn* =
|
||||
proc (epoch: Epoch): Opt[Fork] {.raises: [], gcsafe.}
|
||||
GetGenesisFn* =
|
||||
|
@ -90,6 +94,8 @@ type
|
|||
defaultBuilderAddress*: Opt[string]
|
||||
getValidatorAndIdxFn*: ValidatorPubKeyToDataFn
|
||||
getBeaconTimeFn*: GetBeaconTimeFn
|
||||
getCapellaForkVersionFn*: GetCapellaForkVersionFn
|
||||
getDenebForkEpochFn*: GetDenebForkEpochFn
|
||||
getForkFn*: GetForkFn
|
||||
getGenesisFn*: GetGenesisFn
|
||||
|
||||
|
@ -122,6 +128,8 @@ func init*(T: type KeymanagerHost,
|
|||
defaultBuilderAddress: Opt[string],
|
||||
getValidatorAndIdxFn: ValidatorPubKeyToDataFn,
|
||||
getBeaconTimeFn: GetBeaconTimeFn,
|
||||
getCapellaForkVersionFn: GetCapellaForkVersionFn,
|
||||
getDenebForkEpochFn: GetDenebForkEpochFn,
|
||||
getForkFn: GetForkFn,
|
||||
getGenesisFn: GetGenesisFn): T =
|
||||
T(validatorPool: validatorPool,
|
||||
|
@ -135,6 +143,8 @@ func init*(T: type KeymanagerHost,
|
|||
defaultBuilderAddress: defaultBuilderAddress,
|
||||
getValidatorAndIdxFn: getValidatorAndIdxFn,
|
||||
getBeaconTimeFn: getBeaconTimeFn,
|
||||
getCapellaForkVersionFn: getCapellaForkVersionFn,
|
||||
getDenebForkEpochFn: getDenebForkEpochFn,
|
||||
getForkFn: getForkFn,
|
||||
getGenesisFn: getGenesisFn)
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import
|
|||
|
||||
export
|
||||
streams, keystore, phase0, altair, tables, uri, crypto,
|
||||
signatures.voluntary_exit_signature_fork,
|
||||
rest_types, eth2_rest_serialization, rest_remote_signer_calls,
|
||||
slashing_protection
|
||||
|
||||
|
|
Loading…
Reference in New Issue