Correct implementation of the /validator/duties/sync/{epoch} API
According to the spec, this call should return the positions of the specified validators within the sync committee. The existing code was instead returning the indices of the sync sub-committees where the validator is a member.
This commit is contained in:
parent
48eba59971
commit
ba42b2b316
|
@ -3,7 +3,7 @@
|
|||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
import std/[typetraits, strutils, sets, sequtils]
|
||||
import std/[typetraits, strutils, sets]
|
||||
import stew/[results, base10], chronicles,
|
||||
nimcrypto/utils as ncrutils
|
||||
import ".."/[beacon_chain_db, beacon_node],
|
||||
|
@ -11,7 +11,7 @@ import ".."/[beacon_chain_db, beacon_node],
|
|||
".."/consensus_object_pools/[blockchain_dag, spec_cache,
|
||||
attestation_pool, sync_committee_msg_pool],
|
||||
".."/validators/validator_duties,
|
||||
".."/spec/[forks, network],
|
||||
".."/spec/[beaconstate, forks, network],
|
||||
".."/spec/datatypes/[phase0, altair],
|
||||
"."/rest_utils
|
||||
|
||||
|
@ -190,8 +190,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
let bslot = node.dag.head.atSlot(qepoch.compute_start_slot_at_epoch())
|
||||
|
||||
node.withStateForBlockSlot(bslot):
|
||||
let validatorsCount = lenu64(getStateField(stateData.data, validators))
|
||||
let participants =
|
||||
let syncCommittee =
|
||||
block:
|
||||
let res = syncCommitteeParticipants(stateData().data, qepoch)
|
||||
if res.isErr():
|
||||
|
@ -203,52 +202,20 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
"List of sync committee participants is empty")
|
||||
kres
|
||||
|
||||
# TODO: We doing this because `participants` are stored as array of
|
||||
# validator keys, so we need to convert it to indices, and if any of
|
||||
# public keys are missing, it means some unexpected error.
|
||||
let participantIndices =
|
||||
block:
|
||||
var res: seq[ValidatorIndex]
|
||||
let optIndices = keysToIndices(node.restKeysCache, stateData().data,
|
||||
participants)
|
||||
for item in optIndices:
|
||||
if item.isNone():
|
||||
return RestApiResponse.jsonError(Http500, InternalServerError,
|
||||
"Could not get validator indices")
|
||||
res.add(item.get())
|
||||
res
|
||||
|
||||
let validatorsSet =
|
||||
block:
|
||||
var res: Table[ValidatorIndex, int]
|
||||
for listIndex, validatorIndex in indexList.pairs():
|
||||
# We ignore indices which could not fit in current list of
|
||||
# validators.
|
||||
if uint64(validatorIndex) < validatorsCount:
|
||||
res[validatorIndex] = listIndex
|
||||
res
|
||||
|
||||
template isEmpty(duty: RestSyncCommitteeDuty): bool =
|
||||
len(duty.validator_sync_committee_indices) == 0
|
||||
|
||||
var duties =
|
||||
block:
|
||||
withState(stateData().data):
|
||||
var res = newSeq[RestSyncCommitteeDuty](len(indexList))
|
||||
for committeeIdx in allSyncSubcommittees():
|
||||
for valIndex, arrIndex in syncSubcommitteePairs(participantIndices,
|
||||
committeeIdx):
|
||||
let listIndex = validatorsSet.getOrDefault(valIndex, -1)
|
||||
if listIndex >= 0:
|
||||
if res[listIndex].isEmpty():
|
||||
let key =
|
||||
getStateField(stateData().data, validators)[valIndex].pubkey
|
||||
res[listIndex] = RestSyncCommitteeDuty(
|
||||
validator_index: valIndex,
|
||||
pubkey: key
|
||||
)
|
||||
res[listIndex].validator_sync_committee_indices.add(
|
||||
committeeIdx)
|
||||
res.keepItIf(not(isEmpty(it)))
|
||||
for resIdx, validatorIdx in indexList:
|
||||
if not validatorIdx.isValidInState(state.data):
|
||||
return RestApiResponse.jsonError(Http400, "Invalid index: " & $validatorIdx)
|
||||
|
||||
res[resIdx].pubkey = state.data.validators[validatorIdx].pubkey
|
||||
res[resIdx].validator_index = validatorIdx
|
||||
|
||||
for idx, pubkey in syncCommittee:
|
||||
if pubkey == res[resIdx].pubkey:
|
||||
res[resIdx].validator_sync_committee_indices.add(
|
||||
ValidatorIndexInSyncCommittee idx)
|
||||
res
|
||||
|
||||
return RestApiResponse.jsonResponse(duties)
|
||||
|
|
|
@ -19,6 +19,9 @@ import
|
|||
|
||||
export extras, forks, validator
|
||||
|
||||
type
|
||||
SomeBeaconState* = phase0.BeaconState | altair.BeaconState | merge.BeaconState
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/phase0/beacon-chain.md#increase_balance
|
||||
func increase_balance*(balance: var Gwei, delta: Gwei) =
|
||||
balance += delta
|
||||
|
@ -860,3 +863,7 @@ func upgrade_to_merge*(cfg: RuntimeConfig, pre: altair.BeaconState):
|
|||
# Execution-layer
|
||||
latest_execution_payload_header: ExecutionPayloadHeader()
|
||||
)
|
||||
|
||||
template isValidInState*(idx: ValidatorIndex, state: SomeBeaconState): bool =
|
||||
idx.int < state.validators.len
|
||||
|
||||
|
|
|
@ -432,6 +432,7 @@ type
|
|||
SomeBeaconBlockBody* = BeaconBlockBody | SigVerifiedBeaconBlockBody | TrustedBeaconBlockBody
|
||||
|
||||
SyncSubcommitteeIndex* = distinct uint8
|
||||
ValidatorIndexInSyncCommittee* = distinct uint16
|
||||
|
||||
chronicles.formatIt BeaconBlock: it.shortLog
|
||||
chronicles.formatIt SyncSubcommitteeIndex: uint8(it)
|
||||
|
@ -440,7 +441,12 @@ template asInt*(x: SyncSubcommitteeIndex): int = int(x)
|
|||
template asUInt8*(x: SyncSubcommitteeIndex): uint8 = uint8(x)
|
||||
template asUInt64*(x: SyncSubcommitteeIndex): uint64 = uint64(x)
|
||||
|
||||
template `[]`*(a: auto; i: SyncSubcommitteeIndex): auto = a[i.asInt]
|
||||
template `[]`*(a: auto; i: SyncSubcommitteeIndex): auto =
|
||||
a[i.asInt]
|
||||
|
||||
template `[]`*(arr: array[SYNC_COMMITTEE_SIZE, any] | seq;
|
||||
idx: ValidatorIndexInSyncCommittee): auto =
|
||||
arr[int idx]
|
||||
|
||||
template `==`*(x, y: SyncSubcommitteeIndex): bool =
|
||||
distinctBase(x) == distinctBase(y)
|
||||
|
|
|
@ -412,12 +412,12 @@ proc readValue*(reader: var JsonReader[RestJson], value: var Epoch) {.
|
|||
reader.raiseUnexpectedValue($res.error())
|
||||
|
||||
## ValidatorIndex
|
||||
proc writeValue*(writer: var JsonWriter[RestJson], value: ValidatorIndex) {.
|
||||
raises: [IOError, Defect].} =
|
||||
proc writeValue*(writer: var JsonWriter[RestJson], value: ValidatorIndex)
|
||||
{.raises: [IOError, Defect].} =
|
||||
writeValue(writer, Base10.toString(uint64(value)))
|
||||
|
||||
proc readValue*(reader: var JsonReader[RestJson], value: var ValidatorIndex) {.
|
||||
raises: [IOError, SerializationError, Defect].} =
|
||||
proc readValue*(reader: var JsonReader[RestJson], value: var ValidatorIndex)
|
||||
{.raises: [IOError, SerializationError, Defect].} =
|
||||
let svalue = reader.readValue(string)
|
||||
let res = Base10.decode(uint64, svalue)
|
||||
if res.isOk():
|
||||
|
@ -430,6 +430,24 @@ proc readValue*(reader: var JsonReader[RestJson], value: var ValidatorIndex) {.
|
|||
else:
|
||||
reader.raiseUnexpectedValue($res.error())
|
||||
|
||||
proc writeValue*(writer: var JsonWriter[RestJson], value: ValidatorIndexInSyncCommittee)
|
||||
{.raises: [IOError, Defect].} =
|
||||
writeValue(writer, Base10.toString(distinctBase(value)))
|
||||
|
||||
proc readValue*(reader: var JsonReader[RestJson], value: var ValidatorIndexInSyncCommittee)
|
||||
{.raises: [IOError, SerializationError, Defect].} =
|
||||
let svalue = reader.readValue(string)
|
||||
let res = Base10.decode(uint64, svalue)
|
||||
if res.isOk():
|
||||
let v = res.get()
|
||||
if v < SYNC_COMMITTEE_SIZE:
|
||||
value = ValidatorIndexInSyncCommittee(v)
|
||||
else:
|
||||
reader.raiseUnexpectedValue(
|
||||
"Validator index is bigger then SYNC_COMMITTEE_SIZE")
|
||||
else:
|
||||
reader.raiseUnexpectedValue($res.error())
|
||||
|
||||
## RestValidatorIndex
|
||||
proc writeValue*(writer: var JsonWriter[RestJson],
|
||||
value: RestValidatorIndex) {.
|
||||
|
|
|
@ -105,7 +105,7 @@ type
|
|||
RestSyncCommitteeDuty* = object
|
||||
pubkey*: ValidatorPubKey
|
||||
validator_index*: ValidatorIndex
|
||||
validator_sync_committee_indices*: seq[SyncSubcommitteeIndex]
|
||||
validator_sync_committee_indices*: seq[ValidatorIndexInSyncCommittee]
|
||||
|
||||
RestSyncCommitteeMessage* = object
|
||||
slot*: Slot
|
||||
|
|
Loading…
Reference in New Issue