Gloas ptc duties beacon node response (#8415)

Co-Authored-By: shane-moore <skm1790@gmail.com>

Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu>

Co-Authored-By: Eitan Seri-Levi <eserilev@gmail.com>

Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com>
This commit is contained in:
Shane K Moore
2026-04-26 08:25:00 -07:00
committed by GitHub
parent 276c4d5ff3
commit fae7941b2d
6 changed files with 411 additions and 4 deletions

View File

@@ -3474,7 +3474,6 @@ impl ApiTester {
self
}
// TODO(EIP-7732): Add test_get_validator_duties_ptc function to test PTC duties endpoint
pub async fn test_get_validator_duties_proposer_v2(self) -> Self {
let current_epoch = self.chain.epoch().unwrap();
@@ -3598,6 +3597,17 @@ impl ApiTester {
"should not get attester duties outside of tolerance"
);
assert_eq!(
self.client
.post_validator_duties_ptc(next_epoch, &[0])
.await
.unwrap_err()
.status()
.map(Into::into),
Some(400),
"should not get ptc duties outside of tolerance"
);
self.chain.slot_clock.set_current_time(
current_epoch_start - self.chain.spec.maximum_gossip_clock_disparity(),
);
@@ -3621,6 +3631,88 @@ impl ApiTester {
.await
.expect("should get attester duties within tolerance");
self.client
.post_validator_duties_ptc(next_epoch, &[0])
.await
.expect("should get ptc duties within tolerance");
self
}
pub async fn test_get_validator_duties_ptc(self) -> Self {
let current_epoch = self.chain.epoch().unwrap().as_u64();
let half = current_epoch / 2;
let first = current_epoch - half;
let last = current_epoch + half;
for epoch in first..=last {
for indices in self.interesting_validator_indices() {
let epoch = Epoch::from(epoch);
// The endpoint does not allow getting duties past the next epoch.
if epoch > current_epoch + 1 {
assert_eq!(
self.client
.post_validator_duties_ptc(epoch, indices.as_slice())
.await
.unwrap_err()
.status()
.map(Into::into),
Some(400)
);
continue;
}
let results = self
.client
.post_validator_duties_ptc(epoch, indices.as_slice())
.await
.unwrap();
let dependent_root = self
.chain
.block_root_at_slot(
(epoch - 1).start_slot(E::slots_per_epoch()) - 1,
WhenSlotSkipped::Prev,
)
.unwrap()
.unwrap_or(self.chain.head_beacon_block_root());
assert_eq!(results.dependent_root, dependent_root);
let result_duties = results.data;
let state = self
.chain
.state_at_slot(
epoch.start_slot(E::slots_per_epoch()),
StateSkipConfig::WithStateRoots,
)
.unwrap();
let expected_duties: Vec<PtcDuty> = indices
.iter()
.filter_map(|&validator_index| {
let validator = state.validators().get(validator_index as usize)?;
let slot = state
.get_ptc_assignment(validator_index as usize, epoch, &self.chain.spec)
.unwrap()?;
Some(PtcDuty {
pubkey: validator.pubkey,
validator_index,
slot,
})
})
.collect();
assert_eq!(
result_duties, expected_duties,
"ptc duties should exactly match state assignments"
);
}
}
self
}
@@ -7871,6 +7963,9 @@ async fn get_light_client_finality_update() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn get_validator_duties_early() {
if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
return;
}
ApiTester::new()
.await
.test_get_validator_duties_early()
@@ -7936,6 +8031,29 @@ async fn get_validator_duties_proposer_v2_with_skip_slots() {
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn get_validator_duties_ptc() {
if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
return;
}
ApiTester::new_with_hard_forks()
.await
.test_get_validator_duties_ptc()
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn get_validator_duties_ptc_with_skip_slots() {
if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
return;
}
ApiTester::new_with_hard_forks()
.await
.skip_slots(E::slots_per_epoch() * 2)
.test_get_validator_duties_ptc()
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn block_production() {
ApiTester::new().await.test_block_production().await;