Skip to content

Commit dc79053

Browse files
Savidclaude
andcommitted
fix(cannon): fall back to retained states for committee fetches on pruned beacons
Pruned beacons drop epoch-boundary states at the finalized split, which permanently starved the elaborated-attestation and sync-aggregate derivers. Fetch epoch N committees from the epoch N+1 boundary state (the retained split), and the sync committee from the finalized state with the epoch pinned so a period mismatch errors instead of returning wrong data. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent bf1f26c commit dc79053

2 files changed

Lines changed: 20 additions & 4 deletions

File tree

pkg/cannon/deriver/beacon/eth/v2/beacon_block_sync_aggregate.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,17 @@ func (b *BeaconBlockSyncAggregateDeriver) fetchSyncCommittee(
457457
State: fmt.Sprintf("%d", boundarySlot),
458458
})
459459
if err != nil {
460-
return nil, errors.Wrap(err, "failed to get sync committee from beacon node")
460+
// Pruned (non-archive) beacons drop the period-boundary state, but every
461+
// retained state in the period carries the same sync committee. Pinning
462+
// the epoch makes the node error on a period mismatch rather than
463+
// silently returning a different period's committee.
464+
resp, err = provider.SyncCommittee(ctx, &api.SyncCommitteeOpts{
465+
State: "finalized",
466+
Epoch: &epoch,
467+
})
468+
if err != nil {
469+
return nil, errors.Wrap(err, "failed to get sync committee from beacon node")
470+
}
461471
}
462472

463473
if resp == nil || resp.Data == nil {

pkg/cannon/ethereum/services/duties.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,15 @@ func (m *DutiesService) FetchBeaconCommittee(ctx context.Context, epoch phase0.E
137137

138138
committees, err := m.beacon.FetchBeaconCommittees(ctx, fmt.Sprintf("%d", phase0.Slot(epoch)*spec.SlotsPerEpoch), &epoch)
139139
if err != nil {
140-
m.log.WithError(err).WithContext(ctx).Error("Failed to fetch beacon committees")
141-
142-
return nil, err
140+
// Pruned (non-archive) beacons drop this epoch's boundary state once the
141+
// epoch finalizes, but the next epoch's boundary state — the finalized
142+
// split, which pruning retains — still carries this epoch's shuffling.
143+
committees, err = m.beacon.FetchBeaconCommittees(ctx, fmt.Sprintf("%d", phase0.Slot(epoch+1)*spec.SlotsPerEpoch), &epoch)
144+
if err != nil {
145+
m.log.WithError(err).WithContext(ctx).Error("Failed to fetch beacon committees")
146+
147+
return nil, err
148+
}
143149
}
144150

145151
m.beaconCommittees.Set(epoch, committees, time.Minute*90)

0 commit comments

Comments
 (0)