Implement POST validators/validator_balances APIs (#4872)
* Add POST for fetching validators from state * Implement POST for balances * Tests
This commit is contained in:
parent
e02adbf7bf
commit
b882519d2f
@ -26,6 +26,7 @@ pub mod test_utils;
|
|||||||
mod ui;
|
mod ui;
|
||||||
mod validator;
|
mod validator;
|
||||||
mod validator_inclusion;
|
mod validator_inclusion;
|
||||||
|
mod validators;
|
||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
use crate::produce_block::{produce_blinded_block_v2, produce_block_v2, produce_block_v3};
|
use crate::produce_block::{produce_blinded_block_v2, produce_block_v2, produce_block_v3};
|
||||||
@ -41,7 +42,8 @@ use bytes::Bytes;
|
|||||||
use directory::DEFAULT_ROOT_DIR;
|
use directory::DEFAULT_ROOT_DIR;
|
||||||
use eth2::types::{
|
use eth2::types::{
|
||||||
self as api_types, BroadcastValidation, EndpointVersion, ForkChoice, ForkChoiceNode,
|
self as api_types, BroadcastValidation, EndpointVersion, ForkChoice, ForkChoiceNode,
|
||||||
PublishBlockRequest, ValidatorId, ValidatorStatus,
|
PublishBlockRequest, ValidatorBalancesRequestBody, ValidatorId, ValidatorStatus,
|
||||||
|
ValidatorsRequestBody,
|
||||||
};
|
};
|
||||||
use lighthouse_network::{types::SyncState, EnrExt, NetworkGlobals, PeerId, PubsubMessage};
|
use lighthouse_network::{types::SyncState, EnrExt, NetworkGlobals, PeerId, PubsubMessage};
|
||||||
use lighthouse_version::version_with_platform;
|
use lighthouse_version::version_with_platform;
|
||||||
@ -663,47 +665,32 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
query_res: Result<api_types::ValidatorBalancesQuery, warp::Rejection>| {
|
query_res: Result<api_types::ValidatorBalancesQuery, warp::Rejection>| {
|
||||||
task_spawner.blocking_json_task(Priority::P1, move || {
|
task_spawner.blocking_json_task(Priority::P1, move || {
|
||||||
let query = query_res?;
|
let query = query_res?;
|
||||||
let (data, execution_optimistic, finalized) = state_id
|
crate::validators::get_beacon_state_validator_balances(
|
||||||
.map_state_and_execution_optimistic_and_finalized(
|
state_id,
|
||||||
&chain,
|
chain,
|
||||||
|state, execution_optimistic, finalized| {
|
query.id.as_deref(),
|
||||||
Ok((
|
)
|
||||||
state
|
})
|
||||||
.validators()
|
},
|
||||||
.iter()
|
);
|
||||||
.zip(state.balances().iter())
|
|
||||||
.enumerate()
|
|
||||||
// filter by validator id(s) if provided
|
|
||||||
.filter(|(index, (validator, _))| {
|
|
||||||
query.id.as_ref().map_or(true, |ids| {
|
|
||||||
ids.iter().any(|id| match id {
|
|
||||||
ValidatorId::PublicKey(pubkey) => {
|
|
||||||
&validator.pubkey == pubkey
|
|
||||||
}
|
|
||||||
ValidatorId::Index(param_index) => {
|
|
||||||
*param_index == *index as u64
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.map(|(index, (_, balance))| {
|
|
||||||
Some(api_types::ValidatorBalanceData {
|
|
||||||
index: index as u64,
|
|
||||||
balance: *balance,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
execution_optimistic,
|
|
||||||
finalized,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(api_types::ExecutionOptimisticFinalizedResponse {
|
// POST beacon/states/{state_id}/validator_balances
|
||||||
data,
|
let post_beacon_state_validator_balances = beacon_states_path
|
||||||
execution_optimistic: Some(execution_optimistic),
|
.clone()
|
||||||
finalized: Some(finalized),
|
.and(warp::path("validator_balances"))
|
||||||
})
|
.and(warp::path::end())
|
||||||
|
.and(warp::body::json())
|
||||||
|
.then(
|
||||||
|
|state_id: StateId,
|
||||||
|
task_spawner: TaskSpawner<T::EthSpec>,
|
||||||
|
chain: Arc<BeaconChain<T>>,
|
||||||
|
query: ValidatorBalancesRequestBody| {
|
||||||
|
task_spawner.blocking_json_task(Priority::P1, move || {
|
||||||
|
crate::validators::get_beacon_state_validator_balances(
|
||||||
|
state_id,
|
||||||
|
chain,
|
||||||
|
Some(&query.ids),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -721,69 +708,34 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
query_res: Result<api_types::ValidatorsQuery, warp::Rejection>| {
|
query_res: Result<api_types::ValidatorsQuery, warp::Rejection>| {
|
||||||
task_spawner.blocking_json_task(Priority::P1, move || {
|
task_spawner.blocking_json_task(Priority::P1, move || {
|
||||||
let query = query_res?;
|
let query = query_res?;
|
||||||
let (data, execution_optimistic, finalized) = state_id
|
crate::validators::get_beacon_state_validators(
|
||||||
.map_state_and_execution_optimistic_and_finalized(
|
state_id,
|
||||||
&chain,
|
chain,
|
||||||
|state, execution_optimistic, finalized| {
|
&query.id,
|
||||||
let epoch = state.current_epoch();
|
&query.status,
|
||||||
let far_future_epoch = chain.spec.far_future_epoch;
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Ok((
|
// POST beacon/states/{state_id}/validators
|
||||||
state
|
let post_beacon_state_validators = beacon_states_path
|
||||||
.validators()
|
.clone()
|
||||||
.iter()
|
.and(warp::path("validators"))
|
||||||
.zip(state.balances().iter())
|
.and(warp::path::end())
|
||||||
.enumerate()
|
.and(warp::body::json())
|
||||||
// filter by validator id(s) if provided
|
.then(
|
||||||
.filter(|(index, (validator, _))| {
|
|state_id: StateId,
|
||||||
query.id.as_ref().map_or(true, |ids| {
|
task_spawner: TaskSpawner<T::EthSpec>,
|
||||||
ids.iter().any(|id| match id {
|
chain: Arc<BeaconChain<T>>,
|
||||||
ValidatorId::PublicKey(pubkey) => {
|
query: ValidatorsRequestBody| {
|
||||||
&validator.pubkey == pubkey
|
task_spawner.blocking_json_task(Priority::P1, move || {
|
||||||
}
|
crate::validators::get_beacon_state_validators(
|
||||||
ValidatorId::Index(param_index) => {
|
state_id,
|
||||||
*param_index == *index as u64
|
chain,
|
||||||
}
|
&query.ids,
|
||||||
})
|
&query.statuses,
|
||||||
})
|
)
|
||||||
})
|
|
||||||
// filter by status(es) if provided and map the result
|
|
||||||
.filter_map(|(index, (validator, balance))| {
|
|
||||||
let status = api_types::ValidatorStatus::from_validator(
|
|
||||||
validator,
|
|
||||||
epoch,
|
|
||||||
far_future_epoch,
|
|
||||||
);
|
|
||||||
|
|
||||||
let status_matches =
|
|
||||||
query.status.as_ref().map_or(true, |statuses| {
|
|
||||||
statuses.contains(&status)
|
|
||||||
|| statuses.contains(&status.superstatus())
|
|
||||||
});
|
|
||||||
|
|
||||||
if status_matches {
|
|
||||||
Some(api_types::ValidatorData {
|
|
||||||
index: index as u64,
|
|
||||||
balance: *balance,
|
|
||||||
status,
|
|
||||||
validator: validator.clone(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
execution_optimistic,
|
|
||||||
finalized,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(api_types::ExecutionOptimisticFinalizedResponse {
|
|
||||||
data,
|
|
||||||
execution_optimistic: Some(execution_optimistic),
|
|
||||||
finalized: Some(finalized),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -4709,6 +4661,8 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
.uor(post_beacon_pool_voluntary_exits)
|
.uor(post_beacon_pool_voluntary_exits)
|
||||||
.uor(post_beacon_pool_sync_committees)
|
.uor(post_beacon_pool_sync_committees)
|
||||||
.uor(post_beacon_pool_bls_to_execution_changes)
|
.uor(post_beacon_pool_bls_to_execution_changes)
|
||||||
|
.uor(post_beacon_state_validators)
|
||||||
|
.uor(post_beacon_state_validator_balances)
|
||||||
.uor(post_beacon_rewards_attestations)
|
.uor(post_beacon_rewards_attestations)
|
||||||
.uor(post_beacon_rewards_sync_committee)
|
.uor(post_beacon_rewards_sync_committee)
|
||||||
.uor(post_validator_duties_attester)
|
.uor(post_validator_duties_attester)
|
||||||
|
119
beacon_node/http_api/src/validators.rs
Normal file
119
beacon_node/http_api/src/validators.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
use crate::state_id::StateId;
|
||||||
|
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||||
|
use eth2::types::{
|
||||||
|
self as api_types, ExecutionOptimisticFinalizedResponse, ValidatorBalanceData, ValidatorData,
|
||||||
|
ValidatorId, ValidatorStatus,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub fn get_beacon_state_validators<T: BeaconChainTypes>(
|
||||||
|
state_id: StateId,
|
||||||
|
chain: Arc<BeaconChain<T>>,
|
||||||
|
query_ids: &Option<Vec<ValidatorId>>,
|
||||||
|
query_statuses: &Option<Vec<ValidatorStatus>>,
|
||||||
|
) -> Result<ExecutionOptimisticFinalizedResponse<Vec<ValidatorData>>, warp::Rejection> {
|
||||||
|
let (data, execution_optimistic, finalized) = state_id
|
||||||
|
.map_state_and_execution_optimistic_and_finalized(
|
||||||
|
&chain,
|
||||||
|
|state, execution_optimistic, finalized| {
|
||||||
|
let epoch = state.current_epoch();
|
||||||
|
let far_future_epoch = chain.spec.far_future_epoch;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
state
|
||||||
|
.validators()
|
||||||
|
.iter()
|
||||||
|
.zip(state.balances().iter())
|
||||||
|
.enumerate()
|
||||||
|
// filter by validator id(s) if provided
|
||||||
|
.filter(|(index, (validator, _))| {
|
||||||
|
query_ids.as_ref().map_or(true, |ids| {
|
||||||
|
ids.iter().any(|id| match id {
|
||||||
|
ValidatorId::PublicKey(pubkey) => &validator.pubkey == pubkey,
|
||||||
|
ValidatorId::Index(param_index) => {
|
||||||
|
*param_index == *index as u64
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// filter by status(es) if provided and map the result
|
||||||
|
.filter_map(|(index, (validator, balance))| {
|
||||||
|
let status = api_types::ValidatorStatus::from_validator(
|
||||||
|
validator,
|
||||||
|
epoch,
|
||||||
|
far_future_epoch,
|
||||||
|
);
|
||||||
|
|
||||||
|
let status_matches = query_statuses.as_ref().map_or(true, |statuses| {
|
||||||
|
statuses.contains(&status)
|
||||||
|
|| statuses.contains(&status.superstatus())
|
||||||
|
});
|
||||||
|
|
||||||
|
if status_matches {
|
||||||
|
Some(ValidatorData {
|
||||||
|
index: index as u64,
|
||||||
|
balance: *balance,
|
||||||
|
status,
|
||||||
|
validator: validator.clone(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
execution_optimistic,
|
||||||
|
finalized,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(ExecutionOptimisticFinalizedResponse {
|
||||||
|
data,
|
||||||
|
execution_optimistic: Some(execution_optimistic),
|
||||||
|
finalized: Some(finalized),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_beacon_state_validator_balances<T: BeaconChainTypes>(
|
||||||
|
state_id: StateId,
|
||||||
|
chain: Arc<BeaconChain<T>>,
|
||||||
|
optional_ids: Option<&[ValidatorId]>,
|
||||||
|
) -> Result<ExecutionOptimisticFinalizedResponse<Vec<ValidatorBalanceData>>, warp::Rejection> {
|
||||||
|
let (data, execution_optimistic, finalized) = state_id
|
||||||
|
.map_state_and_execution_optimistic_and_finalized(
|
||||||
|
&chain,
|
||||||
|
|state, execution_optimistic, finalized| {
|
||||||
|
Ok((
|
||||||
|
state
|
||||||
|
.validators()
|
||||||
|
.iter()
|
||||||
|
.zip(state.balances().iter())
|
||||||
|
.enumerate()
|
||||||
|
// filter by validator id(s) if provided
|
||||||
|
.filter(|(index, (validator, _))| {
|
||||||
|
optional_ids.map_or(true, |ids| {
|
||||||
|
ids.iter().any(|id| match id {
|
||||||
|
ValidatorId::PublicKey(pubkey) => &validator.pubkey == pubkey,
|
||||||
|
ValidatorId::Index(param_index) => {
|
||||||
|
*param_index == *index as u64
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(|(index, (_, balance))| ValidatorBalanceData {
|
||||||
|
index: index as u64,
|
||||||
|
balance: *balance,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
execution_optimistic,
|
||||||
|
finalized,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(api_types::ExecutionOptimisticFinalizedResponse {
|
||||||
|
data,
|
||||||
|
execution_optimistic: Some(execution_optimistic),
|
||||||
|
finalized: Some(finalized),
|
||||||
|
})
|
||||||
|
}
|
@ -850,6 +850,18 @@ impl ApiTester {
|
|||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|res| res.data);
|
.map(|res| res.data);
|
||||||
|
let result_post_index_ids = self
|
||||||
|
.client
|
||||||
|
.post_beacon_states_validator_balances(state_id.0, validator_index_ids)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.map(|res| res.data);
|
||||||
|
let result_post_pubkey_ids = self
|
||||||
|
.client
|
||||||
|
.post_beacon_states_validator_balances(state_id.0, validator_pubkey_ids)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.map(|res| res.data);
|
||||||
|
|
||||||
let expected = state_opt.map(|(state, _execution_optimistic, _finalized)| {
|
let expected = state_opt.map(|(state, _execution_optimistic, _finalized)| {
|
||||||
let mut validators = Vec::with_capacity(validator_indices.len());
|
let mut validators = Vec::with_capacity(validator_indices.len());
|
||||||
@ -868,6 +880,8 @@ impl ApiTester {
|
|||||||
|
|
||||||
assert_eq!(result_index_ids, expected, "{:?}", state_id);
|
assert_eq!(result_index_ids, expected, "{:?}", state_id);
|
||||||
assert_eq!(result_pubkey_ids, expected, "{:?}", state_id);
|
assert_eq!(result_pubkey_ids, expected, "{:?}", state_id);
|
||||||
|
assert_eq!(result_post_index_ids, expected, "{:?}", state_id);
|
||||||
|
assert_eq!(result_post_pubkey_ids, expected, "{:?}", state_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -913,7 +927,6 @@ impl ApiTester {
|
|||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|res| res.data);
|
.map(|res| res.data);
|
||||||
|
|
||||||
let result_pubkey_ids = self
|
let result_pubkey_ids = self
|
||||||
.client
|
.client
|
||||||
.get_beacon_states_validators(
|
.get_beacon_states_validators(
|
||||||
@ -924,6 +937,18 @@ impl ApiTester {
|
|||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|res| res.data);
|
.map(|res| res.data);
|
||||||
|
let post_result_index_ids = self
|
||||||
|
.client
|
||||||
|
.post_beacon_states_validators(state_id.0, Some(validator_index_ids), None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.map(|res| res.data);
|
||||||
|
let post_result_pubkey_ids = self
|
||||||
|
.client
|
||||||
|
.post_beacon_states_validators(state_id.0, Some(validator_pubkey_ids), None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.map(|res| res.data);
|
||||||
|
|
||||||
let expected = state_opt.map(|state| {
|
let expected = state_opt.map(|state| {
|
||||||
let epoch = state.current_epoch();
|
let epoch = state.current_epoch();
|
||||||
@ -959,6 +984,8 @@ impl ApiTester {
|
|||||||
|
|
||||||
assert_eq!(result_index_ids, expected, "{:?}", state_id);
|
assert_eq!(result_index_ids, expected, "{:?}", state_id);
|
||||||
assert_eq!(result_pubkey_ids, expected, "{:?}", state_id);
|
assert_eq!(result_pubkey_ids, expected, "{:?}", state_id);
|
||||||
|
assert_eq!(post_result_index_ids, expected, "{:?}", state_id);
|
||||||
|
assert_eq!(post_result_pubkey_ids, expected, "{:?}", state_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,6 +317,18 @@ impl BeaconNodeHttpClient {
|
|||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn post_with_opt_response<T: Serialize, U: IntoUrl, R: DeserializeOwned>(
|
||||||
|
&self,
|
||||||
|
url: U,
|
||||||
|
body: &T,
|
||||||
|
) -> Result<Option<R>, Error> {
|
||||||
|
if let Some(response) = self.post_generic(url, body, None).await.optional()? {
|
||||||
|
response.json().await.map_err(Into::into)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform a HTTP POST request with a custom timeout.
|
/// Perform a HTTP POST request with a custom timeout.
|
||||||
async fn post_with_timeout<T: Serialize, U: IntoUrl>(
|
async fn post_with_timeout<T: Serialize, U: IntoUrl>(
|
||||||
&self,
|
&self,
|
||||||
@ -524,6 +536,29 @@ impl BeaconNodeHttpClient {
|
|||||||
self.get_opt(path).await
|
self.get_opt(path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `POST beacon/states/{state_id}/validator_balances`
|
||||||
|
///
|
||||||
|
/// Returns `Ok(None)` on a 404 error.
|
||||||
|
pub async fn post_beacon_states_validator_balances(
|
||||||
|
&self,
|
||||||
|
state_id: StateId,
|
||||||
|
ids: Vec<ValidatorId>,
|
||||||
|
) -> Result<Option<ExecutionOptimisticFinalizedResponse<Vec<ValidatorBalanceData>>>, Error>
|
||||||
|
{
|
||||||
|
let mut path = self.eth_path(V1)?;
|
||||||
|
|
||||||
|
path.path_segments_mut()
|
||||||
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||||
|
.push("beacon")
|
||||||
|
.push("states")
|
||||||
|
.push(&state_id.to_string())
|
||||||
|
.push("validator_balances");
|
||||||
|
|
||||||
|
let request = ValidatorBalancesRequestBody { ids };
|
||||||
|
|
||||||
|
self.post_with_opt_response(path, &request).await
|
||||||
|
}
|
||||||
|
|
||||||
/// `GET beacon/states/{state_id}/validators?id,status`
|
/// `GET beacon/states/{state_id}/validators?id,status`
|
||||||
///
|
///
|
||||||
/// Returns `Ok(None)` on a 404 error.
|
/// Returns `Ok(None)` on a 404 error.
|
||||||
@ -563,6 +598,29 @@ impl BeaconNodeHttpClient {
|
|||||||
self.get_opt(path).await
|
self.get_opt(path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `POST beacon/states/{state_id}/validators`
|
||||||
|
///
|
||||||
|
/// Returns `Ok(None)` on a 404 error.
|
||||||
|
pub async fn post_beacon_states_validators(
|
||||||
|
&self,
|
||||||
|
state_id: StateId,
|
||||||
|
ids: Option<Vec<ValidatorId>>,
|
||||||
|
statuses: Option<Vec<ValidatorStatus>>,
|
||||||
|
) -> Result<Option<ExecutionOptimisticFinalizedResponse<Vec<ValidatorData>>>, Error> {
|
||||||
|
let mut path = self.eth_path(V1)?;
|
||||||
|
|
||||||
|
path.path_segments_mut()
|
||||||
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||||
|
.push("beacon")
|
||||||
|
.push("states")
|
||||||
|
.push(&state_id.to_string())
|
||||||
|
.push("validators");
|
||||||
|
|
||||||
|
let request = ValidatorsRequestBody { ids, statuses };
|
||||||
|
|
||||||
|
self.post_with_opt_response(path, &request).await
|
||||||
|
}
|
||||||
|
|
||||||
/// `GET beacon/states/{state_id}/committees?slot,index,epoch`
|
/// `GET beacon/states/{state_id}/committees?slot,index,epoch`
|
||||||
///
|
///
|
||||||
/// Returns `Ok(None)` on a 404 error.
|
/// Returns `Ok(None)` on a 404 error.
|
||||||
|
@ -278,17 +278,18 @@ pub struct FinalityCheckpointsData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(try_from = "&str")]
|
#[serde(into = "String")]
|
||||||
|
#[serde(try_from = "std::borrow::Cow<str>")]
|
||||||
pub enum ValidatorId {
|
pub enum ValidatorId {
|
||||||
PublicKey(PublicKeyBytes),
|
PublicKey(PublicKeyBytes),
|
||||||
Index(u64),
|
Index(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for ValidatorId {
|
impl TryFrom<std::borrow::Cow<'_, str>> for ValidatorId {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
fn try_from(s: std::borrow::Cow<str>) -> Result<Self, Self::Error> {
|
||||||
Self::from_str(s)
|
Self::from_str(&s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,6 +318,12 @@ impl fmt::Display for ValidatorId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ValidatorId> for String {
|
||||||
|
fn from(id: ValidatorId) -> String {
|
||||||
|
id.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ValidatorData {
|
pub struct ValidatorData {
|
||||||
#[serde(with = "serde_utils::quoted_u64")]
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
@ -492,6 +499,15 @@ pub struct ValidatorsQuery {
|
|||||||
pub status: Option<Vec<ValidatorStatus>>,
|
pub status: Option<Vec<ValidatorStatus>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct ValidatorsRequestBody {
|
||||||
|
#[serde(default)]
|
||||||
|
pub ids: Option<Vec<ValidatorId>>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub statuses: Option<Vec<ValidatorStatus>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct CommitteeData {
|
pub struct CommitteeData {
|
||||||
#[serde(with = "serde_utils::quoted_u64")]
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
@ -656,6 +672,12 @@ pub struct ValidatorBalancesQuery {
|
|||||||
pub id: Option<Vec<ValidatorId>>,
|
pub id: Option<Vec<ValidatorId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct ValidatorBalancesRequestBody {
|
||||||
|
pub ids: Vec<ValidatorId>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct BlobIndicesQuery {
|
pub struct BlobIndicesQuery {
|
||||||
@ -1879,3 +1901,20 @@ pub struct BlobsBundle<E: EthSpec> {
|
|||||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")]
|
#[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")]
|
||||||
pub blobs: BlobsList<E>,
|
pub blobs: BlobsList<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validator_id_serde() {
|
||||||
|
let id_str = "\"1\"";
|
||||||
|
let x: ValidatorId = serde_json::from_str(id_str).unwrap();
|
||||||
|
assert_eq!(x, ValidatorId::Index(1));
|
||||||
|
assert_eq!(serde_json::to_string(&x).unwrap(), id_str);
|
||||||
|
|
||||||
|
let pubkey_str = "\"0xb824b5ede33a7b05a378a84b183b4bc7e7db894ce48b659f150c97d359edca2f503081d6678d1200f582ec7cafa9caf2\"";
|
||||||
|
let y: ValidatorId = serde_json::from_str(pubkey_str).unwrap();
|
||||||
|
assert_eq!(serde_json::to_string(&y).unwrap(), pubkey_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user