Use dedicated cache for HTTP API route (#9318)

- PR https://github.com/sigp/lighthouse/pull/9305 wants to store PTCs in the committee cache.

BUT the http API route wants to use the committee cache and insert historical committees (i.e. given state at epoch 1000, compute and store the committee for epoch 900).

If we want a single cache to serve both use cases we need to:
- Have entries in the committee cache that have no PTC: Makes reading PTCs from the cache not deterministic
- Compute historical PTC: A bunch of complicated code that's useless

Instead we can add a separate cache for the API, very simple one, that caches committees only. And have the one in the beacon chain compute and cache PTCs always.

### Performance impact

Slightly additional memory cost for users of the `beacon/states/committees` route. Caching is almost equivalent, except for queries of recent committees that may already exist in the beacon chain's committee cache.

### AI disclousure

This PR was written by hand 90%. Claude fixed some warp type issues


  


Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com>
This commit is contained in:
Lion - dapplion
2026-05-18 23:12:17 -06:00
committed by GitHub
parent fd0852a8e5
commit 398efc3acc
6 changed files with 115 additions and 41 deletions

View File

@@ -0,0 +1,43 @@
use lru::LruCache;
use parking_lot::Mutex;
use std::num::NonZeroUsize;
use std::sync::Arc;
use types::{AttestationShufflingId, CommitteeCache, Epoch};
/// See `shuffling_cache::DEFAULT_CACHE_SIZE` for rationale
pub const DEFAULT_HISTORICAL_COMMITTEE_CACHE_SIZE: usize = 16;
/// Indexes the `HistoricalCommitteeCache`. We can compute committees for very old epochs, and we
/// can't retrieve the decision root cheaply from a state. For those cases we allow the cache to
/// key those committees by finalized epoch.
#[derive(Eq, Hash, PartialEq)]
pub enum HistoricalShufflingId {
FinalizedEpoch(Epoch),
ShufflingId(AttestationShufflingId),
}
/// Dedicated cache for attestation committees, used exclusively by the HTTP API.
///
/// This may contain committees for finalized and unfinalized epochs. The name is slightly
/// missleading :)
pub struct HistoricalCommitteeCache {
committees: Mutex<LruCache<HistoricalShufflingId, Arc<CommitteeCache>>>,
}
impl HistoricalCommitteeCache {
pub fn new(size: NonZeroUsize) -> Self {
Self {
committees: Mutex::new(LruCache::new(size)),
}
}
}
impl HistoricalCommitteeCache {
pub fn get(&self, id: &HistoricalShufflingId) -> Option<Arc<CommitteeCache>> {
self.committees.lock().get(id).cloned()
}
pub fn insert(&self, id: HistoricalShufflingId, cache: Arc<CommitteeCache>) {
self.committees.lock().put(id, cache);
}
}