Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VC: Fix forks management behavior. #6698

Merged
merged 3 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions beacon_chain/spec/eth2_apis/rest_fork_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -48,32 +48,42 @@ func getOrDefault*(info: VCRuntimeConfig, name: string, default: Epoch): Epoch =

func getForkVersion(
info: VCRuntimeConfig,
consensusFork: ConsensusFork
consensusFork: ConsensusFork,
optionalForks: set[ConsensusFork] = {}
): Result[Version, string] =
let
key = consensusFork.forkVersionConfigKey()
stringValue =
try:
info[key]
except KeyError:
return err("Forks configuration missing value " & $consensusFork)
if consensusFork in optionalForks:
"0xFFFFFFFF"
else:
return err("Forks configuration missing value " & $consensusFork)
var value: Version
try:
hexToByteArrayStrict(stringValue, distinctBase(value))
except ValueError as exc:
return err(key & " is invalid, reason " & exc.msg)
ok(value)

func getForkEpoch(info: VCRuntimeConfig,
consensusFork: ConsensusFork): Result[Epoch, string] =
func getForkEpoch(
info: VCRuntimeConfig,
consensusFork: ConsensusFork,
optionalForks: set[ConsensusFork] = {}
): Result[Epoch, string] =
if consensusFork > ConsensusFork.Phase0:
let
key = consensusFork.forkEpochConfigKey()
stringValue =
try:
info[key]
except KeyError:
return err("Forks configuration missing value " & $consensusFork)
if consensusFork in optionalForks:
"18446744073709551615"
else:
return err("Forks configuration missing value " & $consensusFork)
numValue = Base10.decode(uint64, stringValue).valueOr:
return err(key & " is invalid, reason " & $error)
ok(Epoch(numValue))
Expand All @@ -84,16 +94,17 @@ template toString(epoch: Epoch): string =
Base10.toString(uint64(epoch))

func getConsensusForkConfig*(
info: VCRuntimeConfig
info: VCRuntimeConfig,
optionalForks: set[ConsensusFork] = {}
): Result[VCForkConfig, string] =
## This extracts all `_FORK_VERSION` and `_FORK_EPOCH` constants
var
config: VCForkConfig
presence: set[ConsensusFork]
for fork in ConsensusFork:
let
forkVersion = ? info.getForkVersion(fork)
forkEpoch = ? info.getForkEpoch(fork)
forkVersion = ? info.getForkVersion(fork, optionalForks)
forkEpoch = ? info.getForkEpoch(fork, optionalForks)
config[fork] = ForkConfigItem(version: forkVersion, epoch: forkEpoch)
presence.incl(fork)

Expand Down
48 changes: 40 additions & 8 deletions beacon_chain/validator_client/common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ const

ZeroTimeDiff* = TimeDiff(nanoseconds: 0'i64)

static: doAssert(high(ConsensusFork) == ConsensusFork.Electra,
"Update OptionalForks constant!")
const
OptionalForks* = {ConsensusFork.Electra}
## When a new ConsensusFork is added and before this fork is activated on
## `mainnet`, it should be part of `OptionalForks`.
## In this case, the client will ignore missing <FORKNAME>_VERSION
## and <FORKNAME>_EPOCH constants from the data reported by BN via
## `/eth/v1/config/spec` API call.

type
ServiceState* {.pure.} = enum
Initialized, Running, Error, Closing, Closed
Expand Down Expand Up @@ -1487,32 +1497,33 @@ proc validateForkCompatibility(
forkConfig: VCForkConfig
): Result[void, string] =
let
item =
storedConfig =
try:
vc.forkConfig.get()[consensusFork]
except KeyError:
raiseAssert "Fork should be present in configuration"

if forkVersion != item.version:
return err("Beacon node has conflicting " &
consensusFork.forkVersionConfigKey() & " value")

if forkEpoch != item.epoch:
if forkEpoch != storedConfig.epoch:
if forkEpoch == FAR_FUTURE_EPOCH:
return err("Beacon node do not know about " &
$consensusFork & " starting epoch")
else:
if item.epoch != FAR_FUTURE_EPOCH:
if storedConfig.epoch != FAR_FUTURE_EPOCH:
return err("Beacon node has conflicting " &
consensusFork.forkEpochConfigKey() & " value")
else:
if forkEpoch != FAR_FUTURE_EPOCH:
if forkVersion != storedConfig.version:
return err("Beacon node has conflicting " &
consensusFork.forkVersionConfigKey() & " value")
ok()

proc updateRuntimeConfig*(
vc: ValidatorClientRef,
node: BeaconNodeServerRef,
info: VCRuntimeConfig
): Result[void, string] =
let forkConfig = ? info.getConsensusForkConfig()
let forkConfig = ? info.getConsensusForkConfig(OptionalForks)

if vc.forkConfig.isNone():
vc.forkConfig = Opt.some(forkConfig)
Expand All @@ -1526,11 +1537,32 @@ proc updateRuntimeConfig*(
# Save newly discovered forks.
if localForkConfig[fork].epoch == FAR_FUTURE_EPOCH:
localForkConfig[fork].epoch = item.epoch
localForkConfig[fork].version = item.version
except KeyError:
raiseAssert "All the forks should be present inside forks configuration"
vc.forkConfig = Opt.some(localForkConfig)
ok()

proc updateForkConfig*(vc: ValidatorClientRef) =
if vc.forkConfig.isNone():
return

var config = vc.forkConfig.get()
for fork in ConsensusFork:
let configItem =
try:
config[fork]
except KeyError:
raiseAssert "All the forks should be present inside forks configuration"
for scheduleItem in vc.forks:
if scheduleItem.current_version == configItem.version:
if configItem.epoch == FAR_FUTURE_EPOCH:
# Fork schedule knows about Fork's epoch.
config[fork] = ForkConfigItem(version: scheduleItem.current_version,
epoch: scheduleItem.epoch)
break
vc.forkConfig = Opt.some(config)

proc `+`*(slot: Slot, epochs: Epoch): Slot =
slot + uint64(epochs) * SLOTS_PER_EPOCH

Expand Down
1 change: 1 addition & 0 deletions beacon_chain/validator_client/fork_service.nim
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ proc pollForFork(vc: ValidatorClientRef) {.async: (raises: [CancelledError]).} =

if (len(vc.forks) == 0) or (vc.forks != sortedForks):
vc.forks = sortedForks
vc.updateForkConfig()
notice "Fork schedule updated", fork_schedule = sortedForks
vc.forksAvailable.fire()

Expand Down
Loading