mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-21 06:48:27 +00:00
Gloas - add get_payload_attestation_endpoint (#8497)
Co-Authored-By: shane-moore <skm1790@gmail.com> Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com> Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu> Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
@@ -2536,6 +2536,14 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
task_spawner_filter.clone(),
|
||||
);
|
||||
|
||||
// GET validator/payload_attestation_data/{slot}
|
||||
let get_validator_payload_attestation_data = get_validator_payload_attestation_data(
|
||||
eth_v1.clone(),
|
||||
chain_filter.clone(),
|
||||
not_while_syncing_filter.clone(),
|
||||
task_spawner_filter.clone(),
|
||||
);
|
||||
|
||||
// GET validator/aggregate_attestation?attestation_data_root,slot
|
||||
let get_validator_aggregate_attestation = get_validator_aggregate_attestation(
|
||||
any_version.clone(),
|
||||
@@ -3347,6 +3355,7 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
.uor(get_validator_blinded_blocks)
|
||||
.uor(get_validator_execution_payload_envelope)
|
||||
.uor(get_validator_attestation_data)
|
||||
.uor(get_validator_payload_attestation_data)
|
||||
.uor(get_validator_aggregate_attestation)
|
||||
.uor(get_validator_sync_committee_contribution)
|
||||
.uor(get_lighthouse_health)
|
||||
|
||||
@@ -248,6 +248,106 @@ pub fn get_validator_attestation_data<T: BeaconChainTypes>(
|
||||
.boxed()
|
||||
}
|
||||
|
||||
// GET validator/payload_attestation_data/{slot}
|
||||
pub fn get_validator_payload_attestation_data<T: BeaconChainTypes>(
|
||||
eth_v1: EthV1Filter,
|
||||
chain_filter: ChainFilter<T>,
|
||||
not_while_syncing_filter: NotWhileSyncingFilter,
|
||||
task_spawner_filter: TaskSpawnerFilter<T>,
|
||||
) -> ResponseFilter {
|
||||
use eth2::beacon_response::{EmptyMetadata, ForkVersionedResponse};
|
||||
use ssz::Encode;
|
||||
use warp::http::Response;
|
||||
|
||||
eth_v1
|
||||
.and(warp::path("validator"))
|
||||
.and(warp::path("payload_attestation_data"))
|
||||
.and(warp::path::param::<Slot>().or_else(|_| async {
|
||||
Err(warp_utils::reject::custom_bad_request(
|
||||
"Invalid slot".to_string(),
|
||||
))
|
||||
}))
|
||||
.and(warp::path::end())
|
||||
.and(warp::header::optional::<Accept>("accept"))
|
||||
.and(not_while_syncing_filter)
|
||||
.and(task_spawner_filter)
|
||||
.and(chain_filter)
|
||||
.then(
|
||||
|slot: Slot,
|
||||
accept_header: Option<Accept>,
|
||||
not_synced_filter: Result<(), Rejection>,
|
||||
task_spawner: TaskSpawner<T::EthSpec>,
|
||||
chain: Arc<BeaconChain<T>>| {
|
||||
task_spawner.blocking_response_task(Priority::P0, move || {
|
||||
not_synced_filter?;
|
||||
|
||||
let fork_name = chain.spec.fork_name_at_slot::<T::EthSpec>(slot);
|
||||
|
||||
// Payload attestations are only valid for Gloas and later forks
|
||||
if !fork_name.gloas_enabled() {
|
||||
return Err(warp_utils::reject::custom_bad_request(format!(
|
||||
"Payload attestations are not supported for fork: {fork_name}"
|
||||
)));
|
||||
}
|
||||
|
||||
let payload_attestation_data = chain
|
||||
.produce_payload_attestation_data(slot)
|
||||
.map_err(|e| match e {
|
||||
BeaconChainError::InvalidSlot(_)
|
||||
| BeaconChainError::NoBlockForSlot(_) => {
|
||||
warp_utils::reject::custom_bad_request(format!(
|
||||
"Unable to produce payload attestation data: {e:?}"
|
||||
))
|
||||
}
|
||||
_ => warp_utils::reject::custom_server_error(format!(
|
||||
"Unable to produce payload attestation data: {e:?}"
|
||||
)),
|
||||
})?;
|
||||
|
||||
match accept_header {
|
||||
Some(Accept::Ssz) => Response::builder()
|
||||
.status(200)
|
||||
.header("Content-Type", "application/octet-stream")
|
||||
.header("Eth-Consensus-Version", fork_name.to_string())
|
||||
.body(payload_attestation_data.as_ssz_bytes().into())
|
||||
.map(|res: Response<warp::hyper::Body>| res)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
"Failed to build SSZ response: {e}"
|
||||
))
|
||||
}),
|
||||
_ => {
|
||||
let json_response = ForkVersionedResponse {
|
||||
version: fork_name,
|
||||
metadata: EmptyMetadata {},
|
||||
data: payload_attestation_data,
|
||||
};
|
||||
Response::builder()
|
||||
.status(200)
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Eth-Consensus-Version", fork_name.to_string())
|
||||
.body(
|
||||
serde_json::to_string(&json_response)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
"Failed to serialize response: {e}"
|
||||
))
|
||||
})?
|
||||
.into(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
warp_utils::reject::custom_server_error(format!(
|
||||
"Failed to build JSON response: {e}"
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.boxed()
|
||||
}
|
||||
|
||||
// GET validator/blinded_blocks/{slot}
|
||||
pub fn get_validator_blinded_blocks<T: BeaconChainTypes>(
|
||||
eth_v1: EthV1Filter,
|
||||
|
||||
@@ -3,7 +3,8 @@ use beacon_chain::test_utils::RelativeSyncCommittee;
|
||||
use beacon_chain::{
|
||||
BeaconChain, ChainConfig, StateSkipConfig, WhenSlotSkipped,
|
||||
test_utils::{
|
||||
AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType, test_spec,
|
||||
AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType,
|
||||
fork_name_from_env, test_spec,
|
||||
},
|
||||
};
|
||||
use bls::{AggregateSignature, Keypair, PublicKeyBytes, SecretKey, Signature, SignatureBytes};
|
||||
@@ -4434,6 +4435,53 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_get_validator_payload_attestation_data(self) -> Self {
|
||||
let slot = self.chain.slot().unwrap();
|
||||
let fork_name = self.chain.spec.fork_name_at_slot::<E>(slot);
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.get_validator_payload_attestation_data(slot)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.version(), Some(fork_name));
|
||||
|
||||
let result = response.into_data();
|
||||
let expected = self.chain.produce_payload_attestation_data(slot).unwrap();
|
||||
|
||||
assert_eq!(result.beacon_block_root, expected.beacon_block_root);
|
||||
assert_eq!(result.slot, expected.slot);
|
||||
assert_eq!(result.payload_present, expected.payload_present);
|
||||
assert_eq!(result.blob_data_available, expected.blob_data_available);
|
||||
|
||||
let ssz_result = self
|
||||
.client
|
||||
.get_validator_payload_attestation_data_ssz(slot)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ssz_result, expected);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_get_validator_payload_attestation_data_pre_gloas(self) -> Self {
|
||||
let slot = self.chain.slot().unwrap();
|
||||
|
||||
// The endpoint should return a 400 error for pre-Gloas forks
|
||||
match self
|
||||
.client
|
||||
.get_validator_payload_attestation_data(slot)
|
||||
.await
|
||||
{
|
||||
Ok(result) => panic!("query for pre-Gloas slot should fail, got: {result:?}"),
|
||||
Err(e) => assert_eq!(e.status().unwrap(), 400),
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(clippy::await_holding_lock)] // This is a test, so it should be fine.
|
||||
pub async fn test_get_validator_aggregate_attestation_v1(self) -> Self {
|
||||
let attestation = self
|
||||
@@ -8057,6 +8105,30 @@ async fn get_validator_attestation_data_with_skip_slots() {
|
||||
.await;
|
||||
}
|
||||
|
||||
// TODO(EIP-7732): Remove `#[ignore]` once gloas beacon chain harness is implemented
|
||||
#[ignore]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn get_validator_payload_attestation_data() {
|
||||
if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
|
||||
return;
|
||||
}
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_get_validator_payload_attestation_data()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn get_validator_payload_attestation_data_pre_gloas() {
|
||||
if fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
|
||||
return;
|
||||
}
|
||||
ApiTester::new()
|
||||
.await
|
||||
.test_get_validator_payload_attestation_data_pre_gloas()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn get_validator_aggregate_attestation_v1() {
|
||||
ApiTester::new()
|
||||
|
||||
Reference in New Issue
Block a user