Add client side endpoint

This commit is contained in:
Tan Chee Keong
2025-02-19 21:46:12 +08:00
parent fc657db5ea
commit 8c7a995c91
2 changed files with 48 additions and 20 deletions

View File

@@ -2664,6 +2664,22 @@ impl BeaconNodeHttpClient {
) )
.await .await
} }
/// `POST validator/beacon_committee_selections`
pub async fn post_validator_beacon_committee_selections(
&self,
selections: &[BeaconCommitteeSelection],
) -> Result<(), Error> {
let mut path = self.eth_path(V1)?;
path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("validator")
.push("beacon_committee_selections");
self.post_with_timeout(path, &selections, self.timeouts.attester_duties)
.await
}
} }
/// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an /// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an

View File

@@ -13,7 +13,8 @@ use beacon_node_fallback::{ApiTopic, BeaconNodeFallback};
use doppelganger_service::DoppelgangerStatus; use doppelganger_service::DoppelgangerStatus;
use environment::RuntimeContext; use environment::RuntimeContext;
use eth2::types::{ use eth2::types::{
AttesterData, BeaconCommitteeSubscription, DutiesResponse, ProposerData, StateId, ValidatorId, AttesterData, BeaconCommitteeSelection, BeaconCommitteeSubscription, DutiesResponse,
ProposerData, StateId, ValidatorId,
}; };
use futures::{stream, StreamExt}; use futures::{stream, StreamExt};
use parking_lot::RwLock; use parking_lot::RwLock;
@@ -132,36 +133,47 @@ async fn make_selection_proof<T: SlotClock + 'static, E: EthSpec>(
distributed: bool, distributed: bool,
beacon_nodes: &Arc<BeaconNodeFallback<T, E>>, beacon_nodes: &Arc<BeaconNodeFallback<T, E>>,
) -> Result<Option<SelectionProof>, Error> { ) -> Result<Option<SelectionProof>, Error> {
if distributed { let selection_proof = if distributed {
// call the middleware for the endpoint /eth/v1/validator/beacon_committee_subscriptions // Call the endpoint /eth/v1/validator/beacon_committee_selections
// During the call, we submit a partial selection proof in the data field of the POST HTTP endpoint
// The end point (middleware) should return a full selection proof
let selections = BeaconCommitteeSelection {
validator_index: duty.validator_idnex,
slot: duty.slot,
selection_proof: validator_store
.produce_selection_proof(duty.pubkey, duty.slot)
.await
.map_err(Error::FailedToProduceSelectionProof)?;
};
beacon_nodes beacon_nodes
.first_success(|beacon_node| async move { .first_success(|beacon_node| async move {
beacon_node beacon_node
.post_validator_beacon_committee_subscriptions() .post_validator_beacon_committee_selections(selections)
.await .await
}) })
.await .await
.map_err(|e| Error::FailedToProduceSelectionProof(e.to_string())) .map_err(|e| Error::FailedToProduceSelectionProof(e.to_string()))
.map(|_| None)
} else { } else {
let selection_proof = validator_store validator_store
.produce_selection_proof(duty.pubkey, duty.slot) .produce_selection_proof(duty.pubkey, duty.slot)
.await .await
.map_err(Error::FailedToProduceSelectionProof)?; .map_err(Error::FailedToProduceSelectionProof)?;
};
selection_proof selection_proof
.is_aggregator(duty.committee_length as usize, spec) .is_aggregator(duty.committee_length as usize, spec)
.map_err(Error::InvalidModulo) .map_err(Error::InvalidModulo)
.map(|is_aggregator| { .map(|is_aggregator| {
if is_aggregator { if is_aggregator {
Some(selection_proof) Some(selection_proof)
} else { } else {
// Don't bother storing the selection proof if the validator isn't an // Don't bother storing the selection proof if the validator isn't an
// aggregator, we won't need it. // aggregator, we won't need it.
None None
} }
}) })
}
} }
impl DutyAndProof { impl DutyAndProof {