VC: Fix forks management behavior. (#6698)
* Fix issue "ignore _VERSION configuration value if _EPOCH == FAR_FUTURE_EPOCH". Add `OptionalForks` constant which should provide default values for _VERSION/_EPOCH. Fix Fork schedule should update Fork's configuration with _EPOCH values. * Fix compilation error. * Add comment why and how `OptionalForks` should be maintained.
This commit is contained in:
parent
6cf388065d
commit
7726f39004
|
@ -48,7 +48,8 @@ func getOrDefault*(info: VCRuntimeConfig, name: string, default: Epoch): Epoch =
|
||||||
|
|
||||||
func getForkVersion(
|
func getForkVersion(
|
||||||
info: VCRuntimeConfig,
|
info: VCRuntimeConfig,
|
||||||
consensusFork: ConsensusFork
|
consensusFork: ConsensusFork,
|
||||||
|
optionalForks: set[ConsensusFork] = {}
|
||||||
): Result[Version, string] =
|
): Result[Version, string] =
|
||||||
let
|
let
|
||||||
key = consensusFork.forkVersionConfigKey()
|
key = consensusFork.forkVersionConfigKey()
|
||||||
|
@ -56,7 +57,10 @@ func getForkVersion(
|
||||||
try:
|
try:
|
||||||
info[key]
|
info[key]
|
||||||
except KeyError:
|
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
|
var value: Version
|
||||||
try:
|
try:
|
||||||
hexToByteArrayStrict(stringValue, distinctBase(value))
|
hexToByteArrayStrict(stringValue, distinctBase(value))
|
||||||
|
@ -64,8 +68,11 @@ func getForkVersion(
|
||||||
return err(key & " is invalid, reason " & exc.msg)
|
return err(key & " is invalid, reason " & exc.msg)
|
||||||
ok(value)
|
ok(value)
|
||||||
|
|
||||||
func getForkEpoch(info: VCRuntimeConfig,
|
func getForkEpoch(
|
||||||
consensusFork: ConsensusFork): Result[Epoch, string] =
|
info: VCRuntimeConfig,
|
||||||
|
consensusFork: ConsensusFork,
|
||||||
|
optionalForks: set[ConsensusFork] = {}
|
||||||
|
): Result[Epoch, string] =
|
||||||
if consensusFork > ConsensusFork.Phase0:
|
if consensusFork > ConsensusFork.Phase0:
|
||||||
let
|
let
|
||||||
key = consensusFork.forkEpochConfigKey()
|
key = consensusFork.forkEpochConfigKey()
|
||||||
|
@ -73,7 +80,10 @@ func getForkEpoch(info: VCRuntimeConfig,
|
||||||
try:
|
try:
|
||||||
info[key]
|
info[key]
|
||||||
except KeyError:
|
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:
|
numValue = Base10.decode(uint64, stringValue).valueOr:
|
||||||
return err(key & " is invalid, reason " & $error)
|
return err(key & " is invalid, reason " & $error)
|
||||||
ok(Epoch(numValue))
|
ok(Epoch(numValue))
|
||||||
|
@ -84,7 +94,8 @@ template toString(epoch: Epoch): string =
|
||||||
Base10.toString(uint64(epoch))
|
Base10.toString(uint64(epoch))
|
||||||
|
|
||||||
func getConsensusForkConfig*(
|
func getConsensusForkConfig*(
|
||||||
info: VCRuntimeConfig
|
info: VCRuntimeConfig,
|
||||||
|
optionalForks: set[ConsensusFork] = {}
|
||||||
): Result[VCForkConfig, string] =
|
): Result[VCForkConfig, string] =
|
||||||
## This extracts all `_FORK_VERSION` and `_FORK_EPOCH` constants
|
## This extracts all `_FORK_VERSION` and `_FORK_EPOCH` constants
|
||||||
var
|
var
|
||||||
|
@ -92,8 +103,8 @@ func getConsensusForkConfig*(
|
||||||
presence: set[ConsensusFork]
|
presence: set[ConsensusFork]
|
||||||
for fork in ConsensusFork:
|
for fork in ConsensusFork:
|
||||||
let
|
let
|
||||||
forkVersion = ? info.getForkVersion(fork)
|
forkVersion = ? info.getForkVersion(fork, optionalForks)
|
||||||
forkEpoch = ? info.getForkEpoch(fork)
|
forkEpoch = ? info.getForkEpoch(fork, optionalForks)
|
||||||
config[fork] = ForkConfigItem(version: forkVersion, epoch: forkEpoch)
|
config[fork] = ForkConfigItem(version: forkVersion, epoch: forkEpoch)
|
||||||
presence.incl(fork)
|
presence.incl(fork)
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,16 @@ const
|
||||||
|
|
||||||
ZeroTimeDiff* = TimeDiff(nanoseconds: 0'i64)
|
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
|
type
|
||||||
ServiceState* {.pure.} = enum
|
ServiceState* {.pure.} = enum
|
||||||
Initialized, Running, Error, Closing, Closed
|
Initialized, Running, Error, Closing, Closed
|
||||||
|
@ -1487,24 +1497,25 @@ proc validateForkCompatibility(
|
||||||
forkConfig: VCForkConfig
|
forkConfig: VCForkConfig
|
||||||
): Result[void, string] =
|
): Result[void, string] =
|
||||||
let
|
let
|
||||||
item =
|
storedConfig =
|
||||||
try:
|
try:
|
||||||
vc.forkConfig.get()[consensusFork]
|
vc.forkConfig.get()[consensusFork]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raiseAssert "Fork should be present in configuration"
|
raiseAssert "Fork should be present in configuration"
|
||||||
|
|
||||||
if forkVersion != item.version:
|
if forkEpoch != storedConfig.epoch:
|
||||||
return err("Beacon node has conflicting " &
|
|
||||||
consensusFork.forkVersionConfigKey() & " value")
|
|
||||||
|
|
||||||
if forkEpoch != item.epoch:
|
|
||||||
if forkEpoch == FAR_FUTURE_EPOCH:
|
if forkEpoch == FAR_FUTURE_EPOCH:
|
||||||
return err("Beacon node do not know about " &
|
return err("Beacon node do not know about " &
|
||||||
$consensusFork & " starting epoch")
|
$consensusFork & " starting epoch")
|
||||||
else:
|
else:
|
||||||
if item.epoch != FAR_FUTURE_EPOCH:
|
if storedConfig.epoch != FAR_FUTURE_EPOCH:
|
||||||
return err("Beacon node has conflicting " &
|
return err("Beacon node has conflicting " &
|
||||||
consensusFork.forkEpochConfigKey() & " value")
|
consensusFork.forkEpochConfigKey() & " value")
|
||||||
|
else:
|
||||||
|
if forkEpoch != FAR_FUTURE_EPOCH:
|
||||||
|
if forkVersion != storedConfig.version:
|
||||||
|
return err("Beacon node has conflicting " &
|
||||||
|
consensusFork.forkVersionConfigKey() & " value")
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc updateRuntimeConfig*(
|
proc updateRuntimeConfig*(
|
||||||
|
@ -1512,7 +1523,7 @@ proc updateRuntimeConfig*(
|
||||||
node: BeaconNodeServerRef,
|
node: BeaconNodeServerRef,
|
||||||
info: VCRuntimeConfig
|
info: VCRuntimeConfig
|
||||||
): Result[void, string] =
|
): Result[void, string] =
|
||||||
let forkConfig = ? info.getConsensusForkConfig()
|
let forkConfig = ? info.getConsensusForkConfig(OptionalForks)
|
||||||
|
|
||||||
if vc.forkConfig.isNone():
|
if vc.forkConfig.isNone():
|
||||||
vc.forkConfig = Opt.some(forkConfig)
|
vc.forkConfig = Opt.some(forkConfig)
|
||||||
|
@ -1526,11 +1537,32 @@ proc updateRuntimeConfig*(
|
||||||
# Save newly discovered forks.
|
# Save newly discovered forks.
|
||||||
if localForkConfig[fork].epoch == FAR_FUTURE_EPOCH:
|
if localForkConfig[fork].epoch == FAR_FUTURE_EPOCH:
|
||||||
localForkConfig[fork].epoch = item.epoch
|
localForkConfig[fork].epoch = item.epoch
|
||||||
|
localForkConfig[fork].version = item.version
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raiseAssert "All the forks should be present inside forks configuration"
|
raiseAssert "All the forks should be present inside forks configuration"
|
||||||
vc.forkConfig = Opt.some(localForkConfig)
|
vc.forkConfig = Opt.some(localForkConfig)
|
||||||
ok()
|
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 =
|
proc `+`*(slot: Slot, epochs: Epoch): Slot =
|
||||||
slot + uint64(epochs) * SLOTS_PER_EPOCH
|
slot + uint64(epochs) * SLOTS_PER_EPOCH
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ proc pollForFork(vc: ValidatorClientRef) {.async: (raises: [CancelledError]).} =
|
||||||
|
|
||||||
if (len(vc.forks) == 0) or (vc.forks != sortedForks):
|
if (len(vc.forks) == 0) or (vc.forks != sortedForks):
|
||||||
vc.forks = sortedForks
|
vc.forks = sortedForks
|
||||||
|
vc.updateForkConfig()
|
||||||
notice "Fork schedule updated", fork_schedule = sortedForks
|
notice "Fork schedule updated", fork_schedule = sortedForks
|
||||||
vc.forksAvailable.fire()
|
vc.forksAvailable.fire()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue