mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
@@ -48,7 +48,8 @@ use directory::DEFAULT_ROOT_DIR;
|
||||
use eth2::types::{
|
||||
self as api_types, BroadcastValidation, ContextDeserialize, EndpointVersion, ForkChoice,
|
||||
ForkChoiceNode, LightClientUpdatesQuery, PublishBlockRequest, StateId as CoreStateId,
|
||||
ValidatorBalancesRequestBody, ValidatorId, ValidatorStatus, ValidatorsRequestBody,
|
||||
ValidatorBalancesRequestBody, ValidatorId, ValidatorIdentitiesRequestBody, ValidatorStatus,
|
||||
ValidatorsRequestBody,
|
||||
};
|
||||
use eth2::{CONSENSUS_VERSION_HEADER, CONTENT_TYPE_HEADER, SSZ_CONTENT_TYPE_HEADER};
|
||||
use health_metrics::observe::Observe;
|
||||
@@ -702,6 +703,34 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
},
|
||||
);
|
||||
|
||||
// POST beacon/states/{state_id}/validator_identities
|
||||
let post_beacon_state_validator_identities = beacon_states_path
|
||||
.clone()
|
||||
.and(warp::path("validator_identities"))
|
||||
.and(warp::path::end())
|
||||
.and(warp_utils::json::json_no_body())
|
||||
.then(
|
||||
|state_id: StateId,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
query: ValidatorIdentitiesRequestBody| {
|
||||
// Prioritise requests for validators at the head. These should be fast to service
|
||||
// and could be required by the validator client.
|
||||
let priority = if let StateId(eth2::types::StateId::Head) = state_id {
|
||||
Priority::P0
|
||||
} else {
|
||||
Priority::P1
|
||||
};
|
||||
task_spawner.blocking_json_task(priority, move || {
|
||||
crate::validators::get_beacon_state_validator_identities(
|
||||
state_id,
|
||||
chain,
|
||||
Some(&query.ids),
|
||||
)
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// GET beacon/states/{state_id}/validators?id,status
|
||||
let get_beacon_state_validators = beacon_states_path
|
||||
.clone()
|
||||
@@ -4852,6 +4881,7 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.uor(post_beacon_pool_bls_to_execution_changes)
|
||||
.uor(post_beacon_state_validators)
|
||||
.uor(post_beacon_state_validator_balances)
|
||||
.uor(post_beacon_state_validator_identities)
|
||||
.uor(post_beacon_rewards_attestations)
|
||||
.uor(post_beacon_rewards_sync_committee)
|
||||
.uor(post_validator_duties_attester)
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::state_id::StateId;
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use eth2::types::{
|
||||
self as api_types, ExecutionOptimisticFinalizedResponse, ValidatorBalanceData, ValidatorData,
|
||||
ValidatorId, ValidatorStatus,
|
||||
ValidatorId, ValidatorIdentityData, ValidatorStatus,
|
||||
};
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
@@ -119,3 +119,51 @@ pub fn get_beacon_state_validator_balances<T: BeaconChainTypes>(
|
||||
finalized: Some(finalized),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_beacon_state_validator_identities<T: BeaconChainTypes>(
|
||||
state_id: StateId,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
optional_ids: Option<&[ValidatorId]>,
|
||||
) -> Result<ExecutionOptimisticFinalizedResponse<Vec<ValidatorIdentityData>>, warp::Rejection> {
|
||||
let (data, execution_optimistic, finalized) = state_id
|
||||
.map_state_and_execution_optimistic_and_finalized(
|
||||
&chain,
|
||||
|state, execution_optimistic, finalized| {
|
||||
let ids_filter_set: Option<HashSet<&ValidatorId>> = match optional_ids {
|
||||
// Same logic as validator_balances endpoint above
|
||||
Some([]) => None,
|
||||
Some(ids) => Some(HashSet::from_iter(ids.iter())),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok((
|
||||
// From the BeaconState, extract the Validator data and convert it into ValidatorIdentityData type
|
||||
state
|
||||
.validators()
|
||||
.iter()
|
||||
.enumerate()
|
||||
// filter by validator id(s) if provided
|
||||
.filter(|(index, validator)| {
|
||||
ids_filter_set.as_ref().is_none_or(|ids_set| {
|
||||
ids_set.contains(&ValidatorId::PublicKey(validator.pubkey))
|
||||
|| ids_set.contains(&ValidatorId::Index(*index as u64))
|
||||
})
|
||||
})
|
||||
.map(|(index, validator)| ValidatorIdentityData {
|
||||
index: index as u64,
|
||||
pubkey: validator.pubkey,
|
||||
activation_epoch: validator.activation_epoch,
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
execution_optimistic,
|
||||
finalized,
|
||||
))
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(api_types::ExecutionOptimisticFinalizedResponse {
|
||||
data,
|
||||
execution_optimistic: Some(execution_optimistic),
|
||||
finalized: Some(finalized),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -964,6 +964,87 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_beacon_states_validator_identities(self) -> Self {
|
||||
for state_id in self.interesting_state_ids() {
|
||||
for validator_indices in self.interesting_validator_indices() {
|
||||
let state_opt = state_id.state(&self.chain).ok();
|
||||
let validators: Vec<Validator> = match state_opt.as_ref() {
|
||||
Some((state, _execution_optimistic, _finalized)) => {
|
||||
state.validators().clone().to_vec()
|
||||
}
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
let validator_index_ids = validator_indices
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(ValidatorId::Index)
|
||||
.collect::<Vec<ValidatorId>>();
|
||||
|
||||
let validator_pubkey_ids = validator_indices
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|i| {
|
||||
ValidatorId::PublicKey(
|
||||
validators
|
||||
.get(i as usize)
|
||||
.map_or(PublicKeyBytes::empty(), |val| val.pubkey),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<ValidatorId>>();
|
||||
|
||||
let result_index_ids = self
|
||||
.client
|
||||
.post_beacon_states_validator_identities(state_id.0, validator_index_ids)
|
||||
.await
|
||||
.unwrap()
|
||||
.map(|res| res.data);
|
||||
let result_pubkey_ids = self
|
||||
.client
|
||||
.post_beacon_states_validator_identities(state_id.0, validator_pubkey_ids)
|
||||
.await
|
||||
.unwrap()
|
||||
.map(|res| res.data);
|
||||
|
||||
let expected = state_opt.map(|(state, _execution_optimistic, _finalized)| {
|
||||
// If validator_indices is empty, return identities for all validators
|
||||
if validator_indices.is_empty() {
|
||||
state
|
||||
.validators()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, validator)| ValidatorIdentityData {
|
||||
index: index as u64,
|
||||
pubkey: validator.pubkey,
|
||||
activation_epoch: validator.activation_epoch,
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
let mut validators = Vec::with_capacity(validator_indices.len());
|
||||
|
||||
for i in validator_indices {
|
||||
if i < state.validators().len() as u64 {
|
||||
// access each validator, and then transform the data into ValidatorIdentityData
|
||||
let validator = state.validators().get(i as usize).unwrap();
|
||||
validators.push(ValidatorIdentityData {
|
||||
index: i,
|
||||
pubkey: validator.pubkey,
|
||||
activation_epoch: validator.activation_epoch,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
validators
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(result_index_ids, expected, "{:?}", state_id);
|
||||
assert_eq!(result_pubkey_ids, expected, "{:?}", state_id);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_beacon_states_validators(self) -> Self {
|
||||
for state_id in self.interesting_state_ids() {
|
||||
for statuses in self.interesting_validator_statuses() {
|
||||
@@ -6685,6 +6766,8 @@ async fn beacon_get_state_info() {
|
||||
.await
|
||||
.test_beacon_states_validator_balances()
|
||||
.await
|
||||
.test_beacon_states_validator_identities()
|
||||
.await
|
||||
.test_beacon_states_committees()
|
||||
.await
|
||||
.test_beacon_states_validator_id()
|
||||
|
||||
Reference in New Issue
Block a user