VC: Runtime config (#5130)
* Make VC able to understand any type of `/eth/v1/config/spec` response without any changes in source code. Update compatibility checking. Now VC is able to obtain any constant from `spec` call. * Remove RestSpecVC declaration.
This commit is contained in:
parent
c534a285b9
commit
5e1a0eac85
|
@ -2996,6 +2996,16 @@ proc readValue*(reader: var JsonReader[RestJson],
|
|||
stacktraces: stacktraces
|
||||
)
|
||||
|
||||
## VCRuntimeConfig
|
||||
proc readValue*(reader: var JsonReader[RestJson],
|
||||
value: var VCRuntimeConfig) {.
|
||||
raises: [SerializationError, IOError, Defect].} =
|
||||
for fieldName in readObjectFields(reader):
|
||||
let fieldValue = reader.readValue(string)
|
||||
if value.hasKeyOrPut(toUpperAscii(fieldName), fieldValue):
|
||||
let msg = "Multiple `" & fieldName & "` fields found"
|
||||
reader.raiseUnexpectedField(msg, "VCRuntimeConfig")
|
||||
|
||||
proc parseRoot(value: string): Result[Eth2Digest, cstring] =
|
||||
try:
|
||||
ok(Eth2Digest(data: hexToByteArray[32](value)))
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
{.push raises: [].}
|
||||
|
||||
import
|
||||
std/json,
|
||||
std/[json, tables],
|
||||
stew/base10, web3/ethtypes,
|
||||
".."/forks,
|
||||
".."/datatypes/[phase0, altair, bellatrix, deneb],
|
||||
|
@ -22,7 +22,8 @@ import
|
|||
|
||||
from ".."/datatypes/capella import BeaconBlockBody
|
||||
|
||||
export forks, phase0, altair, bellatrix, capella, bellatrix_mev, capella_mev
|
||||
export forks, phase0, altair, bellatrix, capella, bellatrix_mev, capella_mev,
|
||||
tables
|
||||
|
||||
const
|
||||
# https://github.com/ethereum/eth2.0-APIs/blob/master/apis/beacon/states/validator_balances.yaml#L17
|
||||
|
@ -478,38 +479,7 @@ type
|
|||
TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE*: uint64
|
||||
SYNC_COMMITTEE_SUBNET_COUNT*: uint64
|
||||
|
||||
# The `RestSpec` is a dynamic dictionary that includes version-specific spec
|
||||
# constants. New versions may introduce new constants, and remove old ones.
|
||||
# The Nimbus validator client fetches the remote spec to determine whether it
|
||||
# is connected to a compatible beacon node. For this purpose, it only needs to
|
||||
# verify a small set of relevant spec constants. To avoid rejecting a remote
|
||||
# spec that includes all of those relevant spec constants, but that does not
|
||||
# include all of the locally known spec constants, a separate type is defined
|
||||
# that includes just the spec constants relevant for the validator client.
|
||||
# Extra spec constants are silently ignored.
|
||||
RestSpecVC* = object
|
||||
# /!\ Keep in sync with `validator_client/api.nim` > `checkCompatible`.
|
||||
MAX_VALIDATORS_PER_COMMITTEE*: uint64
|
||||
SLOTS_PER_EPOCH*: uint64
|
||||
SECONDS_PER_SLOT*: uint64
|
||||
EPOCHS_PER_ETH1_VOTING_PERIOD*: uint64
|
||||
SLOTS_PER_HISTORICAL_ROOT*: uint64
|
||||
EPOCHS_PER_HISTORICAL_VECTOR*: uint64
|
||||
EPOCHS_PER_SLASHINGS_VECTOR*: uint64
|
||||
HISTORICAL_ROOTS_LIMIT*: uint64
|
||||
VALIDATOR_REGISTRY_LIMIT*: uint64
|
||||
MAX_PROPOSER_SLASHINGS*: uint64
|
||||
MAX_ATTESTER_SLASHINGS*: uint64
|
||||
MAX_ATTESTATIONS*: uint64
|
||||
MAX_DEPOSITS*: uint64
|
||||
MAX_VOLUNTARY_EXITS*: uint64
|
||||
DOMAIN_BEACON_PROPOSER*: DomainType
|
||||
DOMAIN_BEACON_ATTESTER*: DomainType
|
||||
DOMAIN_RANDAO*: DomainType
|
||||
DOMAIN_DEPOSIT*: DomainType
|
||||
DOMAIN_VOLUNTARY_EXIT*: DomainType
|
||||
DOMAIN_SELECTION_PROOF*: DomainType
|
||||
DOMAIN_AGGREGATE_AND_PROOF*: DomainType
|
||||
VCRuntimeConfig* = Table[string, string]
|
||||
|
||||
RestDepositContract* = object
|
||||
chain_id*: string
|
||||
|
@ -692,7 +662,7 @@ type
|
|||
GetPoolVoluntaryExitsResponse* = DataEnclosedObject[seq[SignedVoluntaryExit]]
|
||||
GetProposerDutiesResponse* = DataRootEnclosedObject[seq[RestProposerDuty]]
|
||||
GetSpecResponse* = DataEnclosedObject[RestSpec]
|
||||
GetSpecVCResponse* = DataEnclosedObject[RestSpecVC]
|
||||
GetSpecVCResponse* = DataEnclosedObject[VCRuntimeConfig]
|
||||
GetStateFinalityCheckpointsResponse* = DataEnclosedObject[RestBeaconStatesFinalityCheckpoints]
|
||||
GetStateForkResponse* = DataEnclosedObject[Fork]
|
||||
GetStateRootResponse* = DataOptimisticObject[RestRoot]
|
||||
|
|
|
@ -119,7 +119,7 @@ type
|
|||
BeaconNodeServer* = object
|
||||
client*: RestClientRef
|
||||
endpoint*: string
|
||||
config*: Opt[RestSpecVC]
|
||||
config*: VCRuntimeConfig
|
||||
ident*: Opt[string]
|
||||
genesis*: Opt[RestGenesis]
|
||||
syncInfo*: Opt[RestSyncInfo]
|
||||
|
@ -451,29 +451,62 @@ chronicles.expandIt(SyncCommitteeDuty):
|
|||
validator_index = it.validator_index
|
||||
validator_sync_committee_index = it.validator_sync_committee_index
|
||||
|
||||
proc checkConfig*(info: RestSpecVC): bool =
|
||||
# /!\ Keep in sync with `spec/eth2_apis/rest_types.nim` > `RestSpecVC`.
|
||||
info.MAX_VALIDATORS_PER_COMMITTEE == MAX_VALIDATORS_PER_COMMITTEE and
|
||||
info.SLOTS_PER_EPOCH == SLOTS_PER_EPOCH and
|
||||
info.SECONDS_PER_SLOT == SECONDS_PER_SLOT and
|
||||
info.EPOCHS_PER_ETH1_VOTING_PERIOD == EPOCHS_PER_ETH1_VOTING_PERIOD and
|
||||
info.SLOTS_PER_HISTORICAL_ROOT == SLOTS_PER_HISTORICAL_ROOT and
|
||||
info.EPOCHS_PER_HISTORICAL_VECTOR == EPOCHS_PER_HISTORICAL_VECTOR and
|
||||
info.EPOCHS_PER_SLASHINGS_VECTOR == EPOCHS_PER_SLASHINGS_VECTOR and
|
||||
info.HISTORICAL_ROOTS_LIMIT == HISTORICAL_ROOTS_LIMIT and
|
||||
info.VALIDATOR_REGISTRY_LIMIT == VALIDATOR_REGISTRY_LIMIT and
|
||||
info.MAX_PROPOSER_SLASHINGS == MAX_PROPOSER_SLASHINGS and
|
||||
info.MAX_ATTESTER_SLASHINGS == MAX_ATTESTER_SLASHINGS and
|
||||
info.MAX_ATTESTATIONS == MAX_ATTESTATIONS and
|
||||
info.MAX_DEPOSITS == MAX_DEPOSITS and
|
||||
info.MAX_VOLUNTARY_EXITS == MAX_VOLUNTARY_EXITS and
|
||||
info.DOMAIN_BEACON_PROPOSER == DOMAIN_BEACON_PROPOSER and
|
||||
info.DOMAIN_BEACON_ATTESTER == DOMAIN_BEACON_ATTESTER and
|
||||
info.DOMAIN_RANDAO == DOMAIN_RANDAO and
|
||||
info.DOMAIN_DEPOSIT == DOMAIN_DEPOSIT and
|
||||
info.DOMAIN_VOLUNTARY_EXIT == DOMAIN_VOLUNTARY_EXIT and
|
||||
info.DOMAIN_SELECTION_PROOF == DOMAIN_SELECTION_PROOF and
|
||||
info.DOMAIN_AGGREGATE_AND_PROOF == DOMAIN_AGGREGATE_AND_PROOF
|
||||
proc equals*(info: VCRuntimeConfig, name: string, check: uint64): bool =
|
||||
let numstr = info.getOrDefault(name, "missing")
|
||||
if numstr == "missing": return false
|
||||
let value = Base10.decode(uint64, numstr).valueOr:
|
||||
return false
|
||||
value == check
|
||||
|
||||
proc equals*(info: VCRuntimeConfig, name: string, check: DomainType): bool =
|
||||
let domstr = info.getOrDefault(name, "missing")
|
||||
if domstr == "missing": return false
|
||||
let value =
|
||||
try:
|
||||
var dres: DomainType
|
||||
hexToByteArray(domstr, distinctBase(dres))
|
||||
dres
|
||||
except ValueError:
|
||||
return false
|
||||
value == check
|
||||
|
||||
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
|
||||
c.equals("SECONDS_PER_SLOT", SECONDS_PER_SLOT) and
|
||||
c.equals("EPOCHS_PER_ETH1_VOTING_PERIOD", EPOCHS_PER_ETH1_VOTING_PERIOD) and
|
||||
c.equals("SLOTS_PER_HISTORICAL_ROOT", SLOTS_PER_HISTORICAL_ROOT) and
|
||||
c.equals("EPOCHS_PER_HISTORICAL_VECTOR", EPOCHS_PER_HISTORICAL_VECTOR) and
|
||||
c.equals("EPOCHS_PER_SLASHINGS_VECTOR", EPOCHS_PER_SLASHINGS_VECTOR) and
|
||||
c.equals("HISTORICAL_ROOTS_LIMIT", HISTORICAL_ROOTS_LIMIT) and
|
||||
c.equals("VALIDATOR_REGISTRY_LIMIT", VALIDATOR_REGISTRY_LIMIT) and
|
||||
c.equals("MAX_PROPOSER_SLASHINGS", MAX_PROPOSER_SLASHINGS) and
|
||||
c.equals("MAX_ATTESTER_SLASHINGS", MAX_ATTESTER_SLASHINGS) and
|
||||
c.equals("MAX_ATTESTATIONS", MAX_ATTESTATIONS) and
|
||||
c.equals("MAX_DEPOSITS", MAX_DEPOSITS) and
|
||||
c.equals("MAX_VOLUNTARY_EXITS", MAX_VOLUNTARY_EXITS) and
|
||||
c.equals("DOMAIN_BEACON_PROPOSER", DOMAIN_BEACON_PROPOSER) and
|
||||
c.equals("DOMAIN_BEACON_ATTESTER", DOMAIN_BEACON_ATTESTER) and
|
||||
c.equals("DOMAIN_RANDAO", DOMAIN_RANDAO) and
|
||||
c.equals("DOMAIN_DEPOSIT", DOMAIN_DEPOSIT) and
|
||||
c.equals("DOMAIN_VOLUNTARY_EXIT", DOMAIN_VOLUNTARY_EXIT) and
|
||||
c.equals("DOMAIN_SELECTION_PROOF", DOMAIN_SELECTION_PROOF) and
|
||||
c.equals("DOMAIN_AGGREGATE_AND_PROOF", DOMAIN_AGGREGATE_AND_PROOF) and
|
||||
c.hasKey("ALTAIR_FORK_VERSION") and c.hasKey("ALTAIR_FORK_EPOCH") and
|
||||
not(c.equals("ALTAIR_FORK_EPOCH", FAR_FUTURE_EPOCH))
|
||||
|
||||
proc updateStatus*(node: BeaconNodeServerRef,
|
||||
status: RestBeaconNodeStatus,
|
||||
|
|
|
@ -139,7 +139,7 @@ proc checkCompatible(
|
|||
genesisFlag = (genesis != vc.beaconGenesis)
|
||||
configFlag = not(checkConfig(info))
|
||||
|
||||
node.config = Opt.some(info)
|
||||
node.config = info
|
||||
node.genesis = Opt.some(genesis)
|
||||
let res =
|
||||
if configFlag or genesisFlag:
|
||||
|
|
Loading…
Reference in New Issue