mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 10:11:44 +00:00
Update pool/attestations and committees endpoints (#1899)
## Issue Addressed
Catching up on a few eth2 spec updates:
## Proposed Changes
- adding query params to the `GET pool/attestations` endpoint
- allowing the `POST pool/attestations` endpoint to accept an array of attestations
- batching attestation submission
- moving `epoch` from a path param to a query param in the `committees` endpoint
## Additional Info
Co-authored-by: realbigsean <seananderson33@gmail.com>
This commit is contained in:
@@ -599,39 +599,34 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
},
|
||||
);
|
||||
|
||||
// GET beacon/states/{state_id}/committees/{epoch}
|
||||
// GET beacon/states/{state_id}/committees?slot,index,epoch
|
||||
let get_beacon_state_committees = beacon_states_path
|
||||
.clone()
|
||||
.and(warp::path("committees"))
|
||||
.and(warp::path::param::<Epoch>())
|
||||
.and(warp::query::<api_types::CommitteesQuery>())
|
||||
.and(warp::path::end())
|
||||
.and_then(
|
||||
|state_id: StateId,
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
epoch: Epoch,
|
||||
query: api_types::CommitteesQuery| {
|
||||
|state_id: StateId, chain: Arc<BeaconChain<T>>, query: api_types::CommitteesQuery| {
|
||||
// the api spec says if the epoch is not present then the epoch of the state should be used
|
||||
let query_state_id = query.epoch.map_or(state_id, |epoch| {
|
||||
StateId::slot(epoch.start_slot(T::EthSpec::slots_per_epoch()))
|
||||
});
|
||||
|
||||
blocking_json_task(move || {
|
||||
state_id.map_state(&chain, |state| {
|
||||
let relative_epoch =
|
||||
RelativeEpoch::from_epoch(state.current_epoch(), epoch).map_err(
|
||||
|_| {
|
||||
warp_utils::reject::custom_bad_request(format!(
|
||||
"state is epoch {} and only previous, current and next epochs are supported",
|
||||
state.current_epoch()
|
||||
))
|
||||
},
|
||||
)?;
|
||||
query_state_id.map_state(&chain, |state| {
|
||||
let epoch = state.slot.epoch(T::EthSpec::slots_per_epoch());
|
||||
|
||||
let committee_cache = if state
|
||||
.committee_cache_is_initialized(relative_epoch)
|
||||
.committee_cache_is_initialized(RelativeEpoch::Current)
|
||||
{
|
||||
state.committee_cache(relative_epoch).map(Cow::Borrowed)
|
||||
state
|
||||
.committee_cache(RelativeEpoch::Current)
|
||||
.map(Cow::Borrowed)
|
||||
} else {
|
||||
CommitteeCache::initialized(state, epoch, &chain.spec).map(Cow::Owned)
|
||||
}
|
||||
.map_err(BeaconChainError::BeaconStateError)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
.map_err(BeaconChainError::BeaconStateError)
|
||||
.map_err(warp_utils::reject::beacon_chain_error)?;
|
||||
|
||||
// Use either the supplied slot or all slots in the epoch.
|
||||
let slots = query.slot.map(|slot| vec![slot]).unwrap_or_else(|| {
|
||||
@@ -659,11 +654,11 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
let committee = committee_cache
|
||||
.get_beacon_committee(slot, index)
|
||||
.ok_or_else(|| {
|
||||
warp_utils::reject::custom_bad_request(format!(
|
||||
"committee index {} does not exist in epoch {}",
|
||||
index, epoch
|
||||
))
|
||||
})?;
|
||||
warp_utils::reject::custom_bad_request(format!(
|
||||
"committee index {} does not exist in epoch {}",
|
||||
index, epoch
|
||||
))
|
||||
})?;
|
||||
|
||||
response.push(api_types::CommitteeData {
|
||||
index,
|
||||
@@ -906,63 +901,119 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.and(warp::path::end())
|
||||
.and(warp::body::json())
|
||||
.and(network_tx_filter.clone())
|
||||
.and(log_filter.clone())
|
||||
.and_then(
|
||||
|chain: Arc<BeaconChain<T>>,
|
||||
attestation: Attestation<T::EthSpec>,
|
||||
network_tx: UnboundedSender<NetworkMessage<T::EthSpec>>| {
|
||||
attestations: Vec<Attestation<T::EthSpec>>,
|
||||
network_tx: UnboundedSender<NetworkMessage<T::EthSpec>>,
|
||||
log: Logger| {
|
||||
blocking_json_task(move || {
|
||||
let attestation = chain
|
||||
.verify_unaggregated_attestation_for_gossip(attestation.clone(), None)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::object_invalid(format!(
|
||||
"gossip verification failed: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
let mut failures = Vec::new();
|
||||
|
||||
publish_pubsub_message(
|
||||
&network_tx,
|
||||
PubsubMessage::Attestation(Box::new((
|
||||
attestation.subnet_id(),
|
||||
attestation.attestation().clone(),
|
||||
))),
|
||||
)?;
|
||||
for (index, attestation) in attestations.as_slice().iter().enumerate() {
|
||||
let attestation = match chain
|
||||
.verify_unaggregated_attestation_for_gossip(attestation.clone(), None)
|
||||
{
|
||||
Ok(attestation) => attestation,
|
||||
Err(e) => {
|
||||
error!(log,
|
||||
"Failure verifying attestation for gossip";
|
||||
"error" => ?e,
|
||||
"request_index" => index,
|
||||
"committee_index" => attestation.data.index,
|
||||
"attestation_slot" => attestation.data.slot,
|
||||
);
|
||||
failures.push(api_types::Failure::new(
|
||||
index,
|
||||
format!("Verification: {:?}", e),
|
||||
));
|
||||
// skip to the next attestation so we do not publish this one to gossip
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
chain
|
||||
.apply_attestation_to_fork_choice(&attestation)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::broadcast_without_import(format!(
|
||||
"not applied to fork choice: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
publish_pubsub_message(
|
||||
&network_tx,
|
||||
PubsubMessage::Attestation(Box::new((
|
||||
attestation.subnet_id(),
|
||||
attestation.attestation().clone(),
|
||||
))),
|
||||
)?;
|
||||
|
||||
chain
|
||||
.add_to_naive_aggregation_pool(attestation)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::broadcast_without_import(format!(
|
||||
"not applied to naive aggregation pool: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
let committee_index = attestation.attestation().data.index;
|
||||
let slot = attestation.attestation().data.slot;
|
||||
|
||||
Ok(())
|
||||
if let Err(e) = chain.apply_attestation_to_fork_choice(&attestation) {
|
||||
error!(log,
|
||||
"Failure applying verified attestation to fork choice";
|
||||
"error" => ?e,
|
||||
"request_index" => index,
|
||||
"committee_index" => committee_index,
|
||||
"slot" => slot,
|
||||
);
|
||||
failures.push(api_types::Failure::new(
|
||||
index,
|
||||
format!("Fork choice: {:?}", e),
|
||||
));
|
||||
};
|
||||
|
||||
if let Err(e) = chain.add_to_naive_aggregation_pool(attestation) {
|
||||
error!(log,
|
||||
"Failure adding verified attestation to the naive aggregation pool";
|
||||
"error" => ?e,
|
||||
"request_index" => index,
|
||||
"committee_index" => committee_index,
|
||||
"slot" => slot,
|
||||
);
|
||||
failures.push(api_types::Failure::new(
|
||||
index,
|
||||
format!("Naive aggregation pool: {:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
if failures.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(warp_utils::reject::indexed_bad_request(
|
||||
"error processing attestations".to_string(),
|
||||
failures,
|
||||
))
|
||||
}
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// GET beacon/pool/attestations
|
||||
// GET beacon/pool/attestations?committee_index,slot
|
||||
let get_beacon_pool_attestations = beacon_pool_path
|
||||
.clone()
|
||||
.and(warp::path("attestations"))
|
||||
.and(warp::path::end())
|
||||
.and_then(|chain: Arc<BeaconChain<T>>| {
|
||||
blocking_json_task(move || {
|
||||
let mut attestations = chain.op_pool.get_all_attestations();
|
||||
attestations.extend(chain.naive_aggregation_pool.read().iter().cloned());
|
||||
Ok(api_types::GenericResponse::from(attestations))
|
||||
})
|
||||
});
|
||||
.and(warp::query::<api_types::AttestationPoolQuery>())
|
||||
.and_then(
|
||||
|chain: Arc<BeaconChain<T>>, query: api_types::AttestationPoolQuery| {
|
||||
blocking_json_task(move || {
|
||||
let query_filter = |attestation: &Attestation<T::EthSpec>| {
|
||||
query
|
||||
.slot
|
||||
.map_or(true, |slot| slot == attestation.data.slot)
|
||||
&& query
|
||||
.committee_index
|
||||
.map_or(true, |index| index == attestation.data.index)
|
||||
};
|
||||
|
||||
let mut attestations = chain.op_pool.get_filtered_attestations(query_filter);
|
||||
attestations.extend(
|
||||
chain
|
||||
.naive_aggregation_pool
|
||||
.read()
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(query_filter),
|
||||
);
|
||||
Ok(api_types::GenericResponse::from(attestations))
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// POST beacon/pool/attester_slashings
|
||||
let post_beacon_pool_attester_slashings = beacon_pool_path
|
||||
|
||||
Reference in New Issue
Block a user