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
|
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] =
|
proc parseRoot(value: string): Result[Eth2Digest, cstring] =
|
||||||
try:
|
try:
|
||||||
ok(Eth2Digest(data: hexToByteArray[32](value)))
|
ok(Eth2Digest(data: hexToByteArray[32](value)))
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/json,
|
std/[json, tables],
|
||||||
stew/base10, web3/ethtypes,
|
stew/base10, web3/ethtypes,
|
||||||
".."/forks,
|
".."/forks,
|
||||||
".."/datatypes/[phase0, altair, bellatrix, deneb],
|
".."/datatypes/[phase0, altair, bellatrix, deneb],
|
||||||
|
@ -22,7 +22,8 @@ import
|
||||||
|
|
||||||
from ".."/datatypes/capella import BeaconBlockBody
|
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
|
const
|
||||||
# https://github.com/ethereum/eth2.0-APIs/blob/master/apis/beacon/states/validator_balances.yaml#L17
|
# 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
|
TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE*: uint64
|
||||||
SYNC_COMMITTEE_SUBNET_COUNT*: uint64
|
SYNC_COMMITTEE_SUBNET_COUNT*: uint64
|
||||||
|
|
||||||
# The `RestSpec` is a dynamic dictionary that includes version-specific spec
|
VCRuntimeConfig* = Table[string, string]
|
||||||
# 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
|
|
||||||
|
|
||||||
RestDepositContract* = object
|
RestDepositContract* = object
|
||||||
chain_id*: string
|
chain_id*: string
|
||||||
|
@ -692,7 +662,7 @@ type
|
||||||
GetPoolVoluntaryExitsResponse* = DataEnclosedObject[seq[SignedVoluntaryExit]]
|
GetPoolVoluntaryExitsResponse* = DataEnclosedObject[seq[SignedVoluntaryExit]]
|
||||||
GetProposerDutiesResponse* = DataRootEnclosedObject[seq[RestProposerDuty]]
|
GetProposerDutiesResponse* = DataRootEnclosedObject[seq[RestProposerDuty]]
|
||||||
GetSpecResponse* = DataEnclosedObject[RestSpec]
|
GetSpecResponse* = DataEnclosedObject[RestSpec]
|
||||||
GetSpecVCResponse* = DataEnclosedObject[RestSpecVC]
|
GetSpecVCResponse* = DataEnclosedObject[VCRuntimeConfig]
|
||||||
GetStateFinalityCheckpointsResponse* = DataEnclosedObject[RestBeaconStatesFinalityCheckpoints]
|
GetStateFinalityCheckpointsResponse* = DataEnclosedObject[RestBeaconStatesFinalityCheckpoints]
|
||||||
GetStateForkResponse* = DataEnclosedObject[Fork]
|
GetStateForkResponse* = DataEnclosedObject[Fork]
|
||||||
GetStateRootResponse* = DataOptimisticObject[RestRoot]
|
GetStateRootResponse* = DataOptimisticObject[RestRoot]
|
||||||
|
|
|
@ -119,7 +119,7 @@ type
|
||||||
BeaconNodeServer* = object
|
BeaconNodeServer* = object
|
||||||
client*: RestClientRef
|
client*: RestClientRef
|
||||||
endpoint*: string
|
endpoint*: string
|
||||||
config*: Opt[RestSpecVC]
|
config*: VCRuntimeConfig
|
||||||
ident*: Opt[string]
|
ident*: Opt[string]
|
||||||
genesis*: Opt[RestGenesis]
|
genesis*: Opt[RestGenesis]
|
||||||
syncInfo*: Opt[RestSyncInfo]
|
syncInfo*: Opt[RestSyncInfo]
|
||||||
|
@ -451,29 +451,62 @@ chronicles.expandIt(SyncCommitteeDuty):
|
||||||
validator_index = it.validator_index
|
validator_index = it.validator_index
|
||||||
validator_sync_committee_index = it.validator_sync_committee_index
|
validator_sync_committee_index = it.validator_sync_committee_index
|
||||||
|
|
||||||
proc checkConfig*(info: RestSpecVC): bool =
|
proc equals*(info: VCRuntimeConfig, name: string, check: uint64): bool =
|
||||||
# /!\ Keep in sync with `spec/eth2_apis/rest_types.nim` > `RestSpecVC`.
|
let numstr = info.getOrDefault(name, "missing")
|
||||||
info.MAX_VALIDATORS_PER_COMMITTEE == MAX_VALIDATORS_PER_COMMITTEE and
|
if numstr == "missing": return false
|
||||||
info.SLOTS_PER_EPOCH == SLOTS_PER_EPOCH and
|
let value = Base10.decode(uint64, numstr).valueOr:
|
||||||
info.SECONDS_PER_SLOT == SECONDS_PER_SLOT and
|
return false
|
||||||
info.EPOCHS_PER_ETH1_VOTING_PERIOD == EPOCHS_PER_ETH1_VOTING_PERIOD and
|
value == check
|
||||||
info.SLOTS_PER_HISTORICAL_ROOT == SLOTS_PER_HISTORICAL_ROOT and
|
|
||||||
info.EPOCHS_PER_HISTORICAL_VECTOR == EPOCHS_PER_HISTORICAL_VECTOR and
|
proc equals*(info: VCRuntimeConfig, name: string, check: DomainType): bool =
|
||||||
info.EPOCHS_PER_SLASHINGS_VECTOR == EPOCHS_PER_SLASHINGS_VECTOR and
|
let domstr = info.getOrDefault(name, "missing")
|
||||||
info.HISTORICAL_ROOTS_LIMIT == HISTORICAL_ROOTS_LIMIT and
|
if domstr == "missing": return false
|
||||||
info.VALIDATOR_REGISTRY_LIMIT == VALIDATOR_REGISTRY_LIMIT and
|
let value =
|
||||||
info.MAX_PROPOSER_SLASHINGS == MAX_PROPOSER_SLASHINGS and
|
try:
|
||||||
info.MAX_ATTESTER_SLASHINGS == MAX_ATTESTER_SLASHINGS and
|
var dres: DomainType
|
||||||
info.MAX_ATTESTATIONS == MAX_ATTESTATIONS and
|
hexToByteArray(domstr, distinctBase(dres))
|
||||||
info.MAX_DEPOSITS == MAX_DEPOSITS and
|
dres
|
||||||
info.MAX_VOLUNTARY_EXITS == MAX_VOLUNTARY_EXITS and
|
except ValueError:
|
||||||
info.DOMAIN_BEACON_PROPOSER == DOMAIN_BEACON_PROPOSER and
|
return false
|
||||||
info.DOMAIN_BEACON_ATTESTER == DOMAIN_BEACON_ATTESTER and
|
value == check
|
||||||
info.DOMAIN_RANDAO == DOMAIN_RANDAO and
|
|
||||||
info.DOMAIN_DEPOSIT == DOMAIN_DEPOSIT and
|
proc equals*(info: VCRuntimeConfig, name: string, check: Epoch): bool =
|
||||||
info.DOMAIN_VOLUNTARY_EXIT == DOMAIN_VOLUNTARY_EXIT and
|
info.equals(name, uint64(check))
|
||||||
info.DOMAIN_SELECTION_PROOF == DOMAIN_SELECTION_PROOF and
|
|
||||||
info.DOMAIN_AGGREGATE_AND_PROOF == DOMAIN_AGGREGATE_AND_PROOF
|
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,
|
proc updateStatus*(node: BeaconNodeServerRef,
|
||||||
status: RestBeaconNodeStatus,
|
status: RestBeaconNodeStatus,
|
||||||
|
|
|
@ -139,7 +139,7 @@ proc checkCompatible(
|
||||||
genesisFlag = (genesis != vc.beaconGenesis)
|
genesisFlag = (genesis != vc.beaconGenesis)
|
||||||
configFlag = not(checkConfig(info))
|
configFlag = not(checkConfig(info))
|
||||||
|
|
||||||
node.config = Opt.some(info)
|
node.config = info
|
||||||
node.genesis = Opt.some(genesis)
|
node.genesis = Opt.some(genesis)
|
||||||
let res =
|
let res =
|
||||||
if configFlag or genesisFlag:
|
if configFlag or genesisFlag:
|
||||||
|
|
Loading…
Reference in New Issue