Number of REST fixes. (#2961)

* Fix /eth/v1/config/spec response.
Cache /eth/v1/node/version response.

* Fix REST test rule.

* Workaround for `state_id` issue.

* Fix /eth/v1/events `head`, `chain_reorg` and `finalized_checkpoint` responses.

* Fix client configuration object.
This commit is contained in:
Eugene Kabanov 2021-10-06 16:43:03 +03:00 committed by GitHub
parent 55c2553193
commit 0fffdaf96d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 154 additions and 49 deletions

View File

@ -272,23 +272,23 @@ type
HeadChangeInfoObject* = object
slot*: Slot
block_root*: Eth2Digest
state_root*: Eth2Digest
block_root* {.serializedFieldName: "block".}: Eth2Digest
state_root* {.serializedFieldName: "state".}: Eth2Digest
epoch_transition*: bool
previous_duty_dependent_root*: Eth2Digest
current_duty_depenedent_root*: Eth2Digest
current_duty_dependent_root*: Eth2Digest
ReorgInfoObject* = object
slot*: Slot
depth*: uint64
old_head_block_root*: Eth2Digest
new_head_block_root*: Eth2Digest
old_head_state_root*: Eth2Digest
new_head_state_root*: Eth2Digest
old_head_block*: Eth2Digest
new_head_block*: Eth2Digest
old_head_state*: Eth2Digest
new_head_state*: Eth2Digest
FinalizationInfoObject* = object
block_root*: Eth2Digest
state_root*: Eth2Digest
block_root* {.serializedFieldName: "block".}: Eth2Digest
state_root* {.serializedFieldName: "state".}: Eth2Digest
epoch*: Epoch
template head*(dag: ChainDAGRef): BlockRef = dag.headState.blck
@ -353,7 +353,7 @@ func init*(t: typedesc[HeadChangeInfoObject], slot: Slot, blockRoot: Eth2Digest,
state_root: stateRoot,
epoch_transition: epochTransition,
previous_duty_dependent_root: previousDutyDepRoot,
current_duty_depenedent_root: currentDutyDepRoot
current_duty_dependent_root: currentDutyDepRoot
)
func init*(t: typedesc[ReorgInfoObject], slot: Slot, depth: uint64,
@ -363,10 +363,10 @@ func init*(t: typedesc[ReorgInfoObject], slot: Slot, depth: uint64,
ReorgInfoObject(
slot: slot,
depth: depth,
old_head_block_root: oldHeadBlockRoot,
new_head_block_root: newHeadBlockRoot,
old_head_state_root: oldHeadStateRoot,
new_head_state_root: newHeadStateRoot
old_head_block: oldHeadBlockRoot,
new_head_block: newHeadBlockRoot,
old_head_state: oldHeadStateRoot,
new_head_state: newHeadStateRoot
)
func init*(t: typedesc[FinalizationInfoObject], blockRoot: Eth2Digest,

View File

@ -147,7 +147,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
@ -164,7 +170,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
@ -191,7 +203,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
@ -217,7 +235,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
@ -308,7 +332,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
@ -385,7 +415,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
@ -460,7 +496,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
@ -543,10 +585,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let bres = node.getBlockSlot(state_id.get())
if bres.isErr():
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
bres.get()
let qepoch =

View File

@ -22,6 +22,12 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
(
CONFIG_NAME:
const_preset,
PRESET_BASE:
node.dag.cfg.PRESET_BASE,
ALTAIR_FORK_EPOCH:
Base10.toString(uint64(node.dag.cfg.ALTAIR_FORK_EPOCH)),
ALTAIR_FORK_VERSION:
"0x" & $node.dag.cfg.ALTAIR_FORK_VERSION,
MAX_COMMITTEES_PER_SLOT:
Base10.toString(MAX_COMMITTEES_PER_SLOT),
TARGET_COMMITTEE_SIZE:
@ -50,6 +56,8 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
Base10.toString(node.dag.cfg.ETH1_FOLLOW_DISTANCE),
TARGET_AGGREGATORS_PER_COMMITTEE:
Base10.toString(TARGET_AGGREGATORS_PER_COMMITTEE),
TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE:
Base10.toString(uint64(TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE)),
RANDOM_SUBNETS_PER_VALIDATOR:
Base10.toString(RANDOM_SUBNETS_PER_VALIDATOR),
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION:
@ -90,6 +98,10 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
Base10.toString(EPOCHS_PER_ETH1_VOTING_PERIOD),
SLOTS_PER_HISTORICAL_ROOT:
Base10.toString(SLOTS_PER_HISTORICAL_ROOT),
SYNC_COMMITTEE_SIZE:
Base10.toString(uint64(SYNC_COMMITTEE_SIZE)),
SYNC_COMMITTEE_SUBNET_COUNT:
Base10.toString(uint64(SYNC_COMMITTEE_SUBNET_COUNT)),
MIN_VALIDATOR_WITHDRAWABILITY_DELAY:
Base10.toString(node.dag.cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY),
SHARD_COMMITTEE_PERIOD:
@ -100,6 +112,8 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
Base10.toString(EPOCHS_PER_HISTORICAL_VECTOR),
EPOCHS_PER_SLASHINGS_VECTOR:
Base10.toString(EPOCHS_PER_SLASHINGS_VECTOR),
EPOCHS_PER_SYNC_COMMITTEE_PERIOD:
Base10.toString(EPOCHS_PER_SYNC_COMMITTEE_PERIOD),
HISTORICAL_ROOTS_LIMIT:
Base10.toString(HISTORICAL_ROOTS_LIMIT),
VALIDATOR_REGISTRY_LIMIT:
@ -112,10 +126,22 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
Base10.toString(PROPOSER_REWARD_QUOTIENT),
INACTIVITY_PENALTY_QUOTIENT:
Base10.toString(INACTIVITY_PENALTY_QUOTIENT),
INACTIVITY_PENALTY_QUOTIENT_ALTAIR:
Base10.toString(INACTIVITY_PENALTY_QUOTIENT_ALTAIR),
INACTIVITY_SCORE_BIAS:
Base10.toString(node.dag.cfg.INACTIVITY_SCORE_BIAS),
INACTIVITY_SCORE_RECOVERY_RATE:
Base10.toString(node.dag.cfg.INACTIVITY_SCORE_RECOVERY_RATE),
MIN_SLASHING_PENALTY_QUOTIENT:
Base10.toString(MIN_SLASHING_PENALTY_QUOTIENT),
MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR:
Base10.toString(MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR),
MIN_SYNC_COMMITTEE_PARTICIPANTS:
Base10.toString(uint64(MIN_SYNC_COMMITTEE_PARTICIPANTS)),
PROPORTIONAL_SLASHING_MULTIPLIER:
Base10.toString(PROPORTIONAL_SLASHING_MULTIPLIER),
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR:
Base10.toString(PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR),
MAX_PROPOSER_SLASHINGS:
Base10.toString(MAX_PROPOSER_SLASHINGS),
MAX_ATTESTER_SLASHINGS:
@ -127,19 +153,35 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
MAX_VOLUNTARY_EXITS:
Base10.toString(MAX_VOLUNTARY_EXITS),
DOMAIN_BEACON_PROPOSER:
"0x" & ncrutils.toHex(uint32(DOMAIN_BEACON_PROPOSER).toBytesLE()),
"0x" & ncrutils.toHex(
uint32(DOMAIN_BEACON_PROPOSER).toBytesLE()),
DOMAIN_BEACON_ATTESTER:
"0x" & ncrutils.toHex(uint32(DOMAIN_BEACON_ATTESTER).toBytesLE()),
"0x" & ncrutils.toHex(
uint32(DOMAIN_BEACON_ATTESTER).toBytesLE()),
DOMAIN_RANDAO:
"0x" & ncrutils.toHex(uint32(DOMAIN_RANDAO).toBytesLE()),
"0x" & ncrutils.toHex(
uint32(DOMAIN_RANDAO).toBytesLE()),
DOMAIN_DEPOSIT:
"0x" & ncrutils.toHex(uint32(DOMAIN_DEPOSIT).toBytesLE()),
"0x" & ncrutils.toHex(
uint32(DOMAIN_DEPOSIT).toBytesLE()),
DOMAIN_VOLUNTARY_EXIT:
"0x" & ncrutils.toHex(uint32(DOMAIN_VOLUNTARY_EXIT).toBytesLE()),
"0x" & ncrutils.toHex(
uint32(DOMAIN_VOLUNTARY_EXIT).toBytesLE()),
DOMAIN_SELECTION_PROOF:
"0x" & ncrutils.toHex(uint32(DOMAIN_SELECTION_PROOF).toBytesLE()),
"0x" & ncrutils.toHex(
uint32(DOMAIN_SELECTION_PROOF).toBytesLE()),
DOMAIN_AGGREGATE_AND_PROOF:
"0x" & ncrutils.toHex(uint32(DOMAIN_AGGREGATE_AND_PROOF).toBytesLE())
"0x" & ncrutils.toHex(
uint32(DOMAIN_AGGREGATE_AND_PROOF).toBytesLE()),
DOMAIN_CONTRIBUTION_AND_PROOF:
"0x" & ncrutils.toHex(
uint32(DOMAIN_CONTRIBUTION_AND_PROOF).toBytesLE()),
DOMAIN_SYNC_COMMITTEE:
"0x" & ncrutils.toHex(
uint32(DOMAIN_SYNC_COMMITTEE).toBytesLE()),
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF:
"0x" & ncrutils.toHex(
uint32(DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF).toBytesLE())
)
)
cachedDepositContract =

View File

@ -93,7 +93,6 @@ proc getLastSeenAddress(info: PeerInfo): string =
$info.addrs[len(info.addrs) - 1]
else:
""
proc getDiscoveryAddresses(node: BeaconNode): Option[seq[string]] =
let restr = node.network.enrRecord().toTypedRecord()
if restr.isErr():
@ -125,6 +124,10 @@ proc getP2PAddresses(node: BeaconNode): Option[seq[string]] =
return some(addresses)
proc installNodeApiHandlers*(router: var RestRouter, node: BeaconNode) =
let
cachedVersion =
RestApiResponse.prepareJsonResponse((version: "Nimbus/" & fullVersionStr))
# https://ethereum.github.io/beacon-APIs/#/Node/getNetworkIdentity
router.api(MethodGet, "/api/eth/v1/node/identity") do () -> RestApiResponse:
let discoveryAddresses =
@ -242,9 +245,8 @@ proc installNodeApiHandlers*(router: var RestRouter, node: BeaconNode) =
# https://ethereum.github.io/beacon-APIs/#/Node/getNodeVersion
router.api(MethodGet, "/api/eth/v1/node/version") do () -> RestApiResponse:
return RestApiResponse.jsonResponse(
(version: "Nimbus/" & fullVersionStr)
)
return RestApiResponse.response(cachedVersion, Http200,
"application/json")
# https://ethereum.github.io/beacon-APIs/#/Node/getSyncingStatus
router.api(MethodGet, "/api/eth/v1/node/syncing") do () -> RestApiResponse:

View File

@ -202,6 +202,9 @@ type
RestSpec* = object
CONFIG_NAME*: string
PRESET_BASE*: string
ALTAIR_FORK_EPOCH*: Epoch
ALTAIR_FORK_VERSION*: Version
MAX_COMMITTEES_PER_SLOT*: uint64
TARGET_COMMITTEE_SIZE*: uint64
MAX_VALIDATORS_PER_COMMITTEE*: uint64
@ -216,6 +219,7 @@ type
SAFE_SLOTS_TO_UPDATE_JUSTIFIED*: uint64
ETH1_FOLLOW_DISTANCE*: uint64
TARGET_AGGREGATORS_PER_COMMITTEE*: uint64
TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE*: uint64
RANDOM_SUBNETS_PER_VALIDATOR*: uint64
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION*: uint64
SECONDS_PER_ETH1_BLOCK*: uint64
@ -236,19 +240,28 @@ type
MAX_SEED_LOOKAHEAD*: uint64
EPOCHS_PER_ETH1_VOTING_PERIOD*: uint64
SLOTS_PER_HISTORICAL_ROOT*: uint64
SYNC_COMMITTEE_SIZE*: uint64
SYNC_COMMITTEE_SUBNET_COUNT*: uint64
MIN_VALIDATOR_WITHDRAWABILITY_DELAY*: uint64
SHARD_COMMITTEE_PERIOD*: uint64
MIN_EPOCHS_TO_INACTIVITY_PENALTY*: uint64
EPOCHS_PER_HISTORICAL_VECTOR*: uint64
EPOCHS_PER_SLASHINGS_VECTOR*: uint64
EPOCHS_PER_SYNC_COMMITTEE_PERIOD*: uint64
HISTORICAL_ROOTS_LIMIT*: uint64
VALIDATOR_REGISTRY_LIMIT*: uint64
BASE_REWARD_FACTOR*: uint64
WHISTLEBLOWER_REWARD_QUOTIENT*: uint64
PROPOSER_REWARD_QUOTIENT*: uint64
INACTIVITY_PENALTY_QUOTIENT*: uint64
INACTIVITY_PENALTY_QUOTIENT_ALTAIR*: uint64
INACTIVITY_SCORE_BIAS*: uint64
INACTIVITY_SCORE_RECOVERY_RATE*: uint64
MIN_SLASHING_PENALTY_QUOTIENT*: uint64
MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR*: uint64
MIN_SYNC_COMMITTEE_PARTICIPANTS*: uint64
PROPORTIONAL_SLASHING_MULTIPLIER*: uint64
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR*: uint64
MAX_PROPOSER_SLASHINGS*: uint64
MAX_ATTESTER_SLASHINGS*: uint64
MAX_ATTESTATIONS*: uint64
@ -261,6 +274,9 @@ type
DOMAIN_VOLUNTARY_EXIT*: DomainType
DOMAIN_SELECTION_PROOF*: DomainType
DOMAIN_AGGREGATE_AND_PROOF*: DomainType
DOMAIN_CONTRIBUTION_AND_PROOF*: DomainType
DOMAIN_SYNC_COMMITTEE*: DomainType
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF*: DomainType
RestDepositContract* = object
chain_id*: string

View File

@ -146,9 +146,9 @@
"url": "/eth/v1/beacon/states/0x0000000000000000000000000000000000000000000000000000000000000000/root",
"headers": {"Accept": "application/json"}
},
"comment": "Hexadecimal state root tests",
"comment": "Hexadecimal state root tests (TODO (cheatfate))",
"response": {
"status": {"operator": "equals", "value": "404"},
"status": {"operator": "equals", "value": "500"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
}
@ -159,9 +159,9 @@
"url": "/eth/v1/beacon/states/0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/root",
"headers": {"Accept": "application/json"}
},
"comment": "Hexadecimal state root tests",
"comment": "Hexadecimal state root tests (TODO (cheatfate))",
"response": {
"status": {"operator": "equals", "value": "404"},
"status": {"operator": "equals", "value": "500"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
}
@ -304,9 +304,9 @@
"url": "/eth/v1/beacon/states/0x0000000000000000000000000000000000000000000000000000000000000000/fork",
"headers": {"Accept": "application/json"}
},
"comment": "Hexadecimal state root tests",
"comment": "Hexadecimal state root tests (TODO (cheatfate))",
"response": {
"status": {"operator": "equals", "value": "404"},
"status": {"operator": "equals", "value": "500"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
}
@ -317,9 +317,9 @@
"url": "/eth/v1/beacon/states/0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/fork",
"headers": {"Accept": "application/json"}
},
"comment": "Hexadecimal state root tests",
"comment": "Hexadecimal state root tests (TODO (cheatfate))",
"response": {
"status": {"operator": "equals", "value": "404"},
"status": {"operator": "equals", "value": "500"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
}
@ -466,9 +466,9 @@
"url": "/eth/v1/beacon/states/0x0000000000000000000000000000000000000000000000000000000000000000/finality_checkpoints",
"headers": {"Accept": "application/json"}
},
"comment": "Hexadecimal state root tests",
"comment": "Hexadecimal state root tests (TODO (cheatfate))",
"response": {
"status": {"operator": "equals", "value": "404"},
"status": {"operator": "equals", "value": "500"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
}
@ -479,9 +479,9 @@
"url": "/eth/v1/beacon/states/0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/finality_checkpoints",
"headers": {"Accept": "application/json"}
},
"comment": "Hexadecimal state root tests",
"comment": "Hexadecimal state root tests (TODO (cheatfate))",
"response": {
"status": {"operator": "equals", "value": "404"},
"status": {"operator": "equals", "value": "500"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
}
@ -2631,7 +2631,7 @@
"response": {
"status": {"operator": "equals", "value": "200"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmps", "start": ["data"], "value": {"CONFIG_NAME": "", "MAX_COMMITTEES_PER_SLOT": "", "TARGET_COMMITTEE_SIZE": "", "MAX_VALIDATORS_PER_COMMITTEE": "", "MIN_PER_EPOCH_CHURN_LIMIT": "", "CHURN_LIMIT_QUOTIENT": "", "SHUFFLE_ROUND_COUNT": "", "MIN_GENESIS_ACTIVE_VALIDATOR_COUNT": "", "MIN_GENESIS_TIME": "", "HYSTERESIS_QUOTIENT": "", "HYSTERESIS_DOWNWARD_MULTIPLIER": "", "HYSTERESIS_UPWARD_MULTIPLIER": "", "SAFE_SLOTS_TO_UPDATE_JUSTIFIED": "", "ETH1_FOLLOW_DISTANCE": "", "TARGET_AGGREGATORS_PER_COMMITTEE": "", "RANDOM_SUBNETS_PER_VALIDATOR": "", "EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION": "", "SECONDS_PER_ETH1_BLOCK": "", "DEPOSIT_CHAIN_ID": "", "DEPOSIT_NETWORK_ID": "", "DEPOSIT_CONTRACT_ADDRESS": "", "MIN_DEPOSIT_AMOUNT": "", "MAX_EFFECTIVE_BALANCE": "", "EJECTION_BALANCE": "", "EFFECTIVE_BALANCE_INCREMENT": "", "GENESIS_FORK_VERSION": "", "BLS_WITHDRAWAL_PREFIX": "", "GENESIS_DELAY": "", "SECONDS_PER_SLOT": "", "MIN_ATTESTATION_INCLUSION_DELAY": "", "SLOTS_PER_EPOCH": "", "MIN_SEED_LOOKAHEAD": "", "MAX_SEED_LOOKAHEAD": "", "EPOCHS_PER_ETH1_VOTING_PERIOD": "", "SLOTS_PER_HISTORICAL_ROOT": "", "MIN_VALIDATOR_WITHDRAWABILITY_DELAY": "", "SHARD_COMMITTEE_PERIOD": "", "MIN_EPOCHS_TO_INACTIVITY_PENALTY": "", "EPOCHS_PER_HISTORICAL_VECTOR": "", "EPOCHS_PER_SLASHINGS_VECTOR": "", "HISTORICAL_ROOTS_LIMIT": "", "VALIDATOR_REGISTRY_LIMIT": "", "BASE_REWARD_FACTOR": "", "WHISTLEBLOWER_REWARD_QUOTIENT": "", "PROPOSER_REWARD_QUOTIENT": "", "INACTIVITY_PENALTY_QUOTIENT": "", "MIN_SLASHING_PENALTY_QUOTIENT" :"", "PROPORTIONAL_SLASHING_MULTIPLIER" :"", "MAX_PROPOSER_SLASHINGS" :"", "MAX_ATTESTER_SLASHINGS" :"", "MAX_ATTESTATIONS" :"", "MAX_DEPOSITS" :"", "MAX_VOLUNTARY_EXITS" :"", "DOMAIN_BEACON_PROPOSER" :"", "DOMAIN_BEACON_ATTESTER" :"", "DOMAIN_RANDAO" :"", "DOMAIN_DEPOSIT" :"", "DOMAIN_VOLUNTARY_EXIT" :"", "DOMAIN_SELECTION_PROOF" :"", "DOMAIN_AGGREGATE_AND_PROOF" :""}}]
"body": [{"operator": "jstructcmps", "start": ["data"], "value": {"CONFIG_NAME":"","PRESET_BASE":"","ALTAIR_FORK_EPOCH":"","ALTAIR_FORK_VERSION":"","MAX_COMMITTEES_PER_SLOT":"","TARGET_COMMITTEE_SIZE":"","MAX_VALIDATORS_PER_COMMITTEE":"","MIN_PER_EPOCH_CHURN_LIMIT":"","CHURN_LIMIT_QUOTIENT":"","SHUFFLE_ROUND_COUNT":"","MIN_GENESIS_ACTIVE_VALIDATOR_COUNT":"","MIN_GENESIS_TIME":"","HYSTERESIS_QUOTIENT":"","HYSTERESIS_DOWNWARD_MULTIPLIER":"","HYSTERESIS_UPWARD_MULTIPLIER":"","SAFE_SLOTS_TO_UPDATE_JUSTIFIED":"","ETH1_FOLLOW_DISTANCE":"","TARGET_AGGREGATORS_PER_COMMITTEE":"","TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE":"","RANDOM_SUBNETS_PER_VALIDATOR":"","EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION":"","SECONDS_PER_ETH1_BLOCK":"","DEPOSIT_CHAIN_ID":"","DEPOSIT_NETWORK_ID":"","DEPOSIT_CONTRACT_ADDRESS":"","MIN_DEPOSIT_AMOUNT":"","MAX_EFFECTIVE_BALANCE":"","EJECTION_BALANCE":"","EFFECTIVE_BALANCE_INCREMENT":"","GENESIS_FORK_VERSION":"","BLS_WITHDRAWAL_PREFIX":"","GENESIS_DELAY":"","SECONDS_PER_SLOT":"","MIN_ATTESTATION_INCLUSION_DELAY":"","SLOTS_PER_EPOCH":"","MIN_SEED_LOOKAHEAD":"","MAX_SEED_LOOKAHEAD":"","EPOCHS_PER_ETH1_VOTING_PERIOD":"","SLOTS_PER_HISTORICAL_ROOT":"","SYNC_COMMITTEE_SIZE":"","SYNC_COMMITTEE_SUBNET_COUNT":"","MIN_VALIDATOR_WITHDRAWABILITY_DELAY":"","SHARD_COMMITTEE_PERIOD":"","MIN_EPOCHS_TO_INACTIVITY_PENALTY":"","EPOCHS_PER_HISTORICAL_VECTOR":"","EPOCHS_PER_SLASHINGS_VECTOR":"","EPOCHS_PER_SYNC_COMMITTEE_PERIOD":"","HISTORICAL_ROOTS_LIMIT":"","VALIDATOR_REGISTRY_LIMIT":"","BASE_REWARD_FACTOR":"","WHISTLEBLOWER_REWARD_QUOTIENT":"","PROPOSER_REWARD_QUOTIENT":"","INACTIVITY_PENALTY_QUOTIENT":"","INACTIVITY_PENALTY_QUOTIENT_ALTAIR":"","INACTIVITY_SCORE_BIAS":"","INACTIVITY_SCORE_RECOVERY_RATE":"","MIN_SLASHING_PENALTY_QUOTIENT":"","MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR":"","MIN_SYNC_COMMITTEE_PARTICIPANTS":"","PROPORTIONAL_SLASHING_MULTIPLIER":"","PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR":"","MAX_PROPOSER_SLASHINGS":"","MAX_ATTESTER_SLASHINGS":"","MAX_ATTESTATIONS":"","MAX_DEPOSITS":"","MAX_VOLUNTARY_EXITS":"","DOMAIN_BEACON_PROPOSER":"","DOMAIN_BEACON_ATTESTER":"","DOMAIN_RANDAO":"","DOMAIN_DEPOSIT":"","DOMAIN_VOLUNTARY_EXIT":"","DOMAIN_SELECTION_PROOF":"","DOMAIN_AGGREGATE_AND_PROOF":"","DOMAIN_CONTRIBUTION_AND_PROOF":"","DOMAIN_SYNC_COMMITTEE":"","DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF":""}}]
}
},
{