From d54e2fad84d4eb5f97610bb6106560334eccde2f Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 18 May 2026 19:40:26 -0600 Subject: [PATCH 1/7] Use dedicated cache for HTTP API route --- beacon_node/client/src/builder.rs | 1 + beacon_node/http_api/src/beacon/states.rs | 123 +++++++++++++--------- beacon_node/http_api/src/caches.rs | 32 ++++++ beacon_node/http_api/src/lib.rs | 14 ++- beacon_node/http_api/src/test_utils.rs | 1 + 5 files changed, 119 insertions(+), 52 deletions(-) create mode 100644 beacon_node/http_api/src/caches.rs diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 9dfb8304bc8..6f76e465131 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -639,6 +639,7 @@ where network_globals: self.network_globals.clone(), beacon_processor_send: Some(beacon_processor_channels.beacon_processor_tx.clone()), sse_logging_components: runtime_context.sse_logging_components.clone(), + historical_committee_cache: <_>::default(), }); let exit = runtime_context.executor.exit(); diff --git a/beacon_node/http_api/src/beacon/states.rs b/beacon_node/http_api/src/beacon/states.rs index 52b05a807b6..52b345c79a6 100644 --- a/beacon_node/http_api/src/beacon/states.rs +++ b/beacon_node/http_api/src/beacon/states.rs @@ -1,4 +1,5 @@ use crate::StateId; +use crate::caches::HistoricalCommitteeCache; use crate::task_spawner::{Priority, TaskSpawner}; use crate::utils::ResponseFilter; use crate::validator::pubkey_to_validator_index; @@ -13,7 +14,10 @@ use eth2::types::{ }; use ssz::Encode; use std::sync::Arc; -use types::{AttestationShufflingId, BeaconStateError, CommitteeCache, EthSpec, RelativeEpoch}; +use types::{ + AttestationShufflingId, BeaconStateError, CommitteeCache, EthSpec, RelativeEpoch, + RelativeEpochError, +}; use warp::filters::BoxedFilter; use warp::http::Response; use warp::hyper::Body; @@ -26,6 +30,8 @@ type BeaconStatesPath = BoxedFilter<( Arc>, )>; +type BeaconStatesCommitteesFilter = BoxedFilter<(Arc,)>; + // GET beacon/states/{state_id}/pending_consolidations pub fn get_beacon_state_pending_consolidations( beacon_states_path: BeaconStatesPath, @@ -337,17 +343,20 @@ pub fn get_beacon_state_sync_committees( // GET beacon/states/{state_id}/committees?slot,index,epoch pub fn get_beacon_state_committees( beacon_states_path: BeaconStatesPath, + beacon_states_committees_filter: BeaconStatesCommitteesFilter, ) -> ResponseFilter { beacon_states_path .clone() .and(warp::path("committees")) .and(warp::query::()) + .and(beacon_states_committees_filter) .and(warp::path::end()) .then( |state_id: StateId, task_spawner: TaskSpawner, chain: Arc>, - query: eth2::types::CommitteesQuery| { + query: eth2::types::CommitteesQuery, + historical_committee_cache: Arc| { task_spawner.blocking_json_task(Priority::P1, move || { let (data, execution_optimistic, finalized) = state_id .map_state_and_execution_optimistic_and_finalized( @@ -374,26 +383,20 @@ pub fn get_beacon_state_committees( // Attempt to read from the chain cache if there exists a // shuffling_id - let maybe_cached_shuffling = if let Some(shuffling_id) = - shuffling_id.as_ref() + let maybe_cached_shuffling = + if let Some(shuffling_id) = shuffling_id.as_ref() { + historical_committee_cache.get(shuffling_id) + } else { + None + }; + + let committee_cache = if let Some(shuffling) = + maybe_cached_shuffling { - chain - .shuffling_cache - .try_write_for(std::time::Duration::from_secs(1)) - .and_then(|mut cache_write| cache_write.get(shuffling_id)) - .and_then(|cache_item| cache_item.wait().ok()) + shuffling } else { - None - }; - - let committee_cache = - if let Some(shuffling) = maybe_cached_shuffling { - shuffling - } else { - let possibly_built_cache = match RelativeEpoch::from_epoch( - current_epoch, - epoch, - ) { + let committee_cache = + match RelativeEpoch::from_epoch(current_epoch, epoch) { Ok(relative_epoch) if state.committee_cache_is_initialized( relative_epoch, @@ -401,41 +404,61 @@ pub fn get_beacon_state_committees( { state.committee_cache(relative_epoch).cloned() } - _ => CommitteeCache::initialized( - state, - epoch, - &chain.spec, - ), + Ok(_) | Err(RelativeEpochError::EpochTooLow { .. }) => { + CommitteeCache::initialized( + state, + epoch, + &chain.spec, + ) + } + Err(RelativeEpochError::EpochTooHigh { .. }) => { + Err(BeaconStateError::EpochOutOfBounds) + } + Err(RelativeEpochError::ArithError(e)) => { + Err(BeaconStateError::ArithError(e)) + } } - .map_err(|e| match e { - BeaconStateError::EpochOutOfBounds => { - warp_utils::reject::custom_bad_request(format!( - "epoch {} out of bounds for state at {}", - epoch, current_epoch - )) + .map_err(|e| { + match e { + BeaconStateError::EpochOutOfBounds => { + let max_sprp = + T::EthSpec::slots_per_historical_root() + as u64; + let first_subsequent_restore_point_slot = + ((epoch.start_slot( + T::EthSpec::slots_per_epoch(), + ) / max_sprp) + + 1) + * max_sprp; + if epoch < current_epoch { + warp_utils::reject::custom_bad_request( + format!( + "epoch out of bounds, \ + try state at slot {}", + first_subsequent_restore_point_slot, + ), + ) + } else { + warp_utils::reject::custom_bad_request( + "epoch out of bounds, \ + too far in future" + .into(), + ) + } + } + _ => warp_utils::reject::unhandled_error( + BeaconChainError::from(e), + ), } - _ => warp_utils::reject::unhandled_error( - BeaconChainError::from(e), - ), })?; - // Attempt to write to the beacon cache (only if the cache - // size is not the default value). - if chain.config.shuffling_cache_size - != beacon_chain::shuffling_cache::DEFAULT_CACHE_SIZE - && let Some(shuffling_id) = shuffling_id - && let Some(mut cache_write) = chain - .shuffling_cache - .try_write_for(std::time::Duration::from_secs(1)) - { - cache_write.insert_committee_cache( - shuffling_id, - &possibly_built_cache, - ); - } + if let Some(shuffling_id) = shuffling_id { + historical_committee_cache + .insert(shuffling_id, committee_cache.clone()); + } - possibly_built_cache - }; + committee_cache + }; // Use either the supplied slot or all slots in the epoch. let slots = diff --git a/beacon_node/http_api/src/caches.rs b/beacon_node/http_api/src/caches.rs new file mode 100644 index 00000000000..d6b0271bc98 --- /dev/null +++ b/beacon_node/http_api/src/caches.rs @@ -0,0 +1,32 @@ +use lru::LruCache; +use parking_lot::Mutex; +use std::num::NonZeroUsize; +use std::sync::Arc; +use types::{AttestationShufflingId, CommitteeCache}; + +const HISTORICAL_COMMITTEE_CACHE_SIZE: usize = 16; + +pub struct HistoricalCommitteeCache { + committees: Mutex>>, +} + +impl Default for HistoricalCommitteeCache { + fn default() -> Self { + Self { + committees: Mutex::new(LruCache::new( + NonZeroUsize::new(HISTORICAL_COMMITTEE_CACHE_SIZE) + .expect("HISTORICAL_COMMITTEE_CACHE_SIZE is non-zero"), + )), + } + } +} + +impl HistoricalCommitteeCache { + pub fn get(&self, id: &AttestationShufflingId) -> Option> { + self.committees.lock().get(id).cloned() + } + + pub fn insert(&self, id: AttestationShufflingId, cache: Arc) { + self.committees.lock().put(id, cache); + } +} diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index f31817c5ba7..e05f7d138a5 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -12,6 +12,7 @@ mod beacon; mod block_id; mod build_block_contents; mod builder_states; +mod caches; mod custody; mod database; mod light_client; @@ -40,6 +41,7 @@ use crate::beacon::execution_payload_envelope::{ post_beacon_execution_payload_envelope_ssz, }; use crate::beacon::pool::*; +use crate::caches::HistoricalCommitteeCache; use crate::light_client::{get_light_client_bootstrap, get_light_client_updates}; use crate::utils::{AnyVersionFilter, EthV1Filter}; use crate::validator::post_validator_liveness_epoch; @@ -132,6 +134,7 @@ pub struct Context { pub network_globals: Option>>, pub beacon_processor_send: Option>, pub sse_logging_components: Option, + pub historical_committee_cache: Arc, } /// Configuration for the HTTP server. @@ -416,6 +419,11 @@ pub fn serve( }) .boxed(); + let historical_committee_cache = ctx.historical_committee_cache.clone(); + let beacon_states_committees_filter = warp::any() + .map(move || historical_committee_cache.clone()) + .boxed(); + // Create a `warp` filter that provides access to the network sender channel. let network_tx = ctx .network_senders @@ -628,8 +636,10 @@ pub fn serve( states::get_beacon_state_validators_id(beacon_states_path.clone()); // GET beacon/states/{state_id}/committees?slot,index,epoch - let get_beacon_state_committees = - states::get_beacon_state_committees(beacon_states_path.clone()); + let get_beacon_state_committees = states::get_beacon_state_committees( + beacon_states_path.clone(), + beacon_states_committees_filter, + ); // GET beacon/states/{state_id}/sync_committees?epoch let get_beacon_state_sync_committees = diff --git a/beacon_node/http_api/src/test_utils.rs b/beacon_node/http_api/src/test_utils.rs index 27e2a27d35c..cbd10e497f5 100644 --- a/beacon_node/http_api/src/test_utils.rs +++ b/beacon_node/http_api/src/test_utils.rs @@ -293,6 +293,7 @@ pub async fn create_api_server_with_config( network_globals: Some(network_globals), beacon_processor_send: Some(beacon_processor_send), sse_logging_components: None, + historical_committee_cache: <_>::default(), }); let (listening_socket, server) = From 65c4004550147e9452d68ddc4d7c2eb6fc494345 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 18 May 2026 19:54:37 -0600 Subject: [PATCH 2/7] Revert unwanted change --- beacon_node/http_api/src/beacon/states.rs | 67 ++++++++--------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/beacon_node/http_api/src/beacon/states.rs b/beacon_node/http_api/src/beacon/states.rs index 52b345c79a6..48876bcf6c0 100644 --- a/beacon_node/http_api/src/beacon/states.rs +++ b/beacon_node/http_api/src/beacon/states.rs @@ -390,13 +390,14 @@ pub fn get_beacon_state_committees( None }; - let committee_cache = if let Some(shuffling) = - maybe_cached_shuffling - { - shuffling - } else { - let committee_cache = - match RelativeEpoch::from_epoch(current_epoch, epoch) { + let committee_cache = + if let Some(shuffling) = maybe_cached_shuffling { + shuffling + } else { + let committee_cache = match RelativeEpoch::from_epoch( + current_epoch, + epoch, + ) { Ok(relative_epoch) if state.committee_cache_is_initialized( relative_epoch, @@ -418,47 +419,25 @@ pub fn get_beacon_state_committees( Err(BeaconStateError::ArithError(e)) } } - .map_err(|e| { - match e { - BeaconStateError::EpochOutOfBounds => { - let max_sprp = - T::EthSpec::slots_per_historical_root() - as u64; - let first_subsequent_restore_point_slot = - ((epoch.start_slot( - T::EthSpec::slots_per_epoch(), - ) / max_sprp) - + 1) - * max_sprp; - if epoch < current_epoch { - warp_utils::reject::custom_bad_request( - format!( - "epoch out of bounds, \ - try state at slot {}", - first_subsequent_restore_point_slot, - ), - ) - } else { - warp_utils::reject::custom_bad_request( - "epoch out of bounds, \ - too far in future" - .into(), - ) - } - } - _ => warp_utils::reject::unhandled_error( - BeaconChainError::from(e), - ), + .map_err(|e| match e { + BeaconStateError::EpochOutOfBounds => { + warp_utils::reject::custom_bad_request(format!( + "epoch {} out of bounds for state at {}", + epoch, current_epoch + )) } + _ => warp_utils::reject::unhandled_error( + BeaconChainError::from(e), + ), })?; - if let Some(shuffling_id) = shuffling_id { - historical_committee_cache - .insert(shuffling_id, committee_cache.clone()); - } + if let Some(shuffling_id) = shuffling_id { + historical_committee_cache + .insert(shuffling_id, committee_cache.clone()); + } - committee_cache - }; + committee_cache + }; // Use either the supplied slot or all slots in the epoch. let slots = From 2e0d099579662870c1765bc5f7da3e095b2ffa08 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 18 May 2026 21:15:18 -0600 Subject: [PATCH 3/7] Use cache for finalized epochs --- beacon_node/http_api/src/beacon/states.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/beacon_node/http_api/src/beacon/states.rs b/beacon_node/http_api/src/beacon/states.rs index 48876bcf6c0..ce7d813f4f1 100644 --- a/beacon_node/http_api/src/beacon/states.rs +++ b/beacon_node/http_api/src/beacon/states.rs @@ -15,7 +15,7 @@ use eth2::types::{ use ssz::Encode; use std::sync::Arc; use types::{ - AttestationShufflingId, BeaconStateError, CommitteeCache, EthSpec, RelativeEpoch, + AttestationShufflingId, BeaconStateError, CommitteeCache, EthSpec, Hash256, RelativeEpoch, RelativeEpochError, }; use warp::filters::BoxedFilter; @@ -378,7 +378,15 @@ pub fn get_beacon_state_committees( shuffling_decision_block, }) } else { - None + if epoch < chain.head().finalized_checkpoint().epoch { + // Use the case for finalized epochs + Some(AttestationShufflingId { + shuffling_epoch: epoch, + shuffling_decision_block: Hash256::ZERO, + }) + } else { + None + } }; // Attempt to read from the chain cache if there exists a From 38d5879937ea9a0114991b9470bc14997eaf2a41 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 18 May 2026 21:21:25 -0600 Subject: [PATCH 4/7] Use enum --- beacon_node/http_api/src/beacon/states.rs | 25 ++++++++++------------- beacon_node/http_api/src/caches.rs | 11 +++++++--- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/beacon_node/http_api/src/beacon/states.rs b/beacon_node/http_api/src/beacon/states.rs index ce7d813f4f1..12d6505fbce 100644 --- a/beacon_node/http_api/src/beacon/states.rs +++ b/beacon_node/http_api/src/beacon/states.rs @@ -1,5 +1,5 @@ use crate::StateId; -use crate::caches::HistoricalCommitteeCache; +use crate::caches::{HistoricalCommitteeCache, HistoricalShufflingId}; use crate::task_spawner::{Priority, TaskSpawner}; use crate::utils::ResponseFilter; use crate::validator::pubkey_to_validator_index; @@ -373,20 +373,17 @@ pub fn get_beacon_state_committees( let shuffling_id = if let Ok(Some(shuffling_decision_block)) = chain.block_root_at_slot(decision_slot, WhenSlotSkipped::Prev) { - Some(AttestationShufflingId { - shuffling_epoch: epoch, - shuffling_decision_block, - }) - } else { - if epoch < chain.head().finalized_checkpoint().epoch { - // Use the case for finalized epochs - Some(AttestationShufflingId { + Some(HistoricalShufflingId::ShufflingId( + AttestationShufflingId { shuffling_epoch: epoch, - shuffling_decision_block: Hash256::ZERO, - }) - } else { - None - } + shuffling_decision_block, + }, + )) + } else if epoch < chain.head().finalized_checkpoint().epoch { + // Use the case for finalized epochs + Some(HistoricalShufflingId::FinalizedEpoch(epoch)) + } else { + None }; // Attempt to read from the chain cache if there exists a diff --git a/beacon_node/http_api/src/caches.rs b/beacon_node/http_api/src/caches.rs index d6b0271bc98..b746f4baeae 100644 --- a/beacon_node/http_api/src/caches.rs +++ b/beacon_node/http_api/src/caches.rs @@ -6,8 +6,13 @@ use types::{AttestationShufflingId, CommitteeCache}; const HISTORICAL_COMMITTEE_CACHE_SIZE: usize = 16; +pub enum HistoricalShufflingId { + FinalizedEpoch(Epoch), + ShufflingId(AttestationShufflingId), +} + pub struct HistoricalCommitteeCache { - committees: Mutex>>, + committees: Mutex>>, } impl Default for HistoricalCommitteeCache { @@ -22,11 +27,11 @@ impl Default for HistoricalCommitteeCache { } impl HistoricalCommitteeCache { - pub fn get(&self, id: &AttestationShufflingId) -> Option> { + pub fn get(&self, id: &HistoricalShufflingId) -> Option> { self.committees.lock().get(id).cloned() } - pub fn insert(&self, id: AttestationShufflingId, cache: Arc) { + pub fn insert(&self, id: HistoricalShufflingId, cache: Arc) { self.committees.lock().put(id, cache); } } From 8c59f823d1e58f5666039afb42292189f8a9ed9b Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 18 May 2026 21:30:40 -0600 Subject: [PATCH 5/7] You need to run cargo check when writing code --- beacon_node/http_api/src/beacon/states.rs | 2 +- beacon_node/http_api/src/caches.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/beacon_node/http_api/src/beacon/states.rs b/beacon_node/http_api/src/beacon/states.rs index 12d6505fbce..1b765aa2276 100644 --- a/beacon_node/http_api/src/beacon/states.rs +++ b/beacon_node/http_api/src/beacon/states.rs @@ -15,7 +15,7 @@ use eth2::types::{ use ssz::Encode; use std::sync::Arc; use types::{ - AttestationShufflingId, BeaconStateError, CommitteeCache, EthSpec, Hash256, RelativeEpoch, + AttestationShufflingId, BeaconStateError, CommitteeCache, EthSpec, RelativeEpoch, RelativeEpochError, }; use warp::filters::BoxedFilter; diff --git a/beacon_node/http_api/src/caches.rs b/beacon_node/http_api/src/caches.rs index b746f4baeae..596334b6a05 100644 --- a/beacon_node/http_api/src/caches.rs +++ b/beacon_node/http_api/src/caches.rs @@ -2,10 +2,11 @@ use lru::LruCache; use parking_lot::Mutex; use std::num::NonZeroUsize; use std::sync::Arc; -use types::{AttestationShufflingId, CommitteeCache}; +use types::{AttestationShufflingId, CommitteeCache, Epoch}; const HISTORICAL_COMMITTEE_CACHE_SIZE: usize = 16; +#[derive(Eq, Hash, PartialEq)] pub enum HistoricalShufflingId { FinalizedEpoch(Epoch), ShufflingId(AttestationShufflingId), From d27a455f4836a5d91b8e6610c76b0eef291f6d2c Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 18 May 2026 22:04:28 -0600 Subject: [PATCH 6/7] Allow to customize size --- beacon_node/client/src/builder.rs | 6 +++++- beacon_node/http_api/src/caches.rs | 19 ++++++++++++------- beacon_node/http_api/src/lib.rs | 5 ++++- beacon_node/http_api/src/test_utils.rs | 8 +++++--- beacon_node/src/config.rs | 3 +++ 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 6f76e465131..a82abb7796d 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -36,6 +36,7 @@ use rand::SeedableRng; use rand::rngs::{OsRng, StdRng}; use slasher::Slasher; use slasher_service::SlasherService; +use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::Duration; @@ -639,7 +640,10 @@ where network_globals: self.network_globals.clone(), beacon_processor_send: Some(beacon_processor_channels.beacon_processor_tx.clone()), sse_logging_components: runtime_context.sse_logging_components.clone(), - historical_committee_cache: <_>::default(), + historical_committee_cache: Arc::new(http_api::HistoricalCommitteeCache::new( + NonZeroUsize::new(self.http_api_config.historical_committee_cache_size) + .unwrap_or(NonZeroUsize::new(1).expect("1 > 0")), + )), }); let exit = runtime_context.executor.exit(); diff --git a/beacon_node/http_api/src/caches.rs b/beacon_node/http_api/src/caches.rs index 596334b6a05..d92571594a7 100644 --- a/beacon_node/http_api/src/caches.rs +++ b/beacon_node/http_api/src/caches.rs @@ -4,25 +4,30 @@ use std::num::NonZeroUsize; use std::sync::Arc; use types::{AttestationShufflingId, CommitteeCache, Epoch}; -const HISTORICAL_COMMITTEE_CACHE_SIZE: usize = 16; +/// 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>>, } -impl Default for HistoricalCommitteeCache { - fn default() -> Self { +impl HistoricalCommitteeCache { + pub fn new(size: NonZeroUsize) -> Self { Self { - committees: Mutex::new(LruCache::new( - NonZeroUsize::new(HISTORICAL_COMMITTEE_CACHE_SIZE) - .expect("HISTORICAL_COMMITTEE_CACHE_SIZE is non-zero"), - )), + committees: Mutex::new(LruCache::new(size)), } } } diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index e05f7d138a5..74bf1ccd764 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -41,7 +41,8 @@ use crate::beacon::execution_payload_envelope::{ post_beacon_execution_payload_envelope_ssz, }; use crate::beacon::pool::*; -use crate::caches::HistoricalCommitteeCache; +use crate::caches::DEFAULT_HISTORICAL_COMMITTEE_CACHE_SIZE; +pub use crate::caches::HistoricalCommitteeCache; use crate::light_client::{get_light_client_bootstrap, get_light_client_updates}; use crate::utils::{AnyVersionFilter, EthV1Filter}; use crate::validator::post_validator_liveness_epoch; @@ -151,6 +152,7 @@ pub struct Config { #[serde(with = "eth2::types::serde_status_code")] pub duplicate_block_status_code: StatusCode, pub target_peers: usize, + pub historical_committee_cache_size: usize, } impl Default for Config { @@ -166,6 +168,7 @@ impl Default for Config { enable_beacon_processor: true, duplicate_block_status_code: StatusCode::ACCEPTED, target_peers: 100, + historical_committee_cache_size: DEFAULT_HISTORICAL_COMMITTEE_CACHE_SIZE, } } } diff --git a/beacon_node/http_api/src/test_utils.rs b/beacon_node/http_api/src/test_utils.rs index cbd10e497f5..4c75fbb7609 100644 --- a/beacon_node/http_api/src/test_utils.rs +++ b/beacon_node/http_api/src/test_utils.rs @@ -1,4 +1,4 @@ -use crate::{Config, Context}; +use crate::{Config, Context, caches::HistoricalCommitteeCache}; use beacon_chain::{ BeaconChain, BeaconChainTypes, custody_context::NodeCustodyType, @@ -22,10 +22,10 @@ use lighthouse_network::{ }; use network::{NetworkReceivers, NetworkSenders}; use sensitive_url::SensitiveUrl; -use std::future::Future; use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; +use std::{future::Future, num::NonZeroUsize}; use store::MemoryStore; use task_executor::test_utils::TestRuntime; use types::{ChainSpec, EthSpec}; @@ -293,7 +293,9 @@ pub async fn create_api_server_with_config( network_globals: Some(network_globals), beacon_processor_send: Some(beacon_processor_send), sse_logging_components: None, - historical_committee_cache: <_>::default(), + historical_committee_cache: Arc::new(HistoricalCommitteeCache::new( + NonZeroUsize::new(16).unwrap(), + )), }); let (listening_socket, server) = diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 8ba2c0f3214..f10f9e3b455 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -215,6 +215,9 @@ pub fn get_config( if let Some(cache_size) = clap_utils::parse_optional(cli_args, "shuffling-cache-size")? { client_config.chain.shuffling_cache_size = cache_size; + // Mantain backwards compatibility with users customizing `shuffling_cache_size` to tweak + // the behaviour of the HTTP API route `beacon/states/committees` + client_config.http_api.historical_committee_cache_size = cache_size; } if let Some(batches) = clap_utils::parse_optional(cli_args, "blob-publication-batches")? { From 3092a69a11306f6e1599c9ebcfa158bd2a5eb7b9 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 18 May 2026 22:23:40 -0600 Subject: [PATCH 7/7] nits --- beacon_node/client/src/builder.rs | 2 +- beacon_node/http_api/src/test_utils.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index a82abb7796d..f532ef716e2 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -642,7 +642,7 @@ where sse_logging_components: runtime_context.sse_logging_components.clone(), historical_committee_cache: Arc::new(http_api::HistoricalCommitteeCache::new( NonZeroUsize::new(self.http_api_config.historical_committee_cache_size) - .unwrap_or(NonZeroUsize::new(1).expect("1 > 0")), + .unwrap_or(NonZeroUsize::MIN), )), }); diff --git a/beacon_node/http_api/src/test_utils.rs b/beacon_node/http_api/src/test_utils.rs index 4c75fbb7609..f27a04d17a2 100644 --- a/beacon_node/http_api/src/test_utils.rs +++ b/beacon_node/http_api/src/test_utils.rs @@ -294,7 +294,7 @@ pub async fn create_api_server_with_config( beacon_processor_send: Some(beacon_processor_send), sse_logging_components: None, historical_committee_cache: Arc::new(HistoricalCommitteeCache::new( - NonZeroUsize::new(16).unwrap(), + NonZeroUsize::new(http_config.historical_committee_cache_size).unwrap(), )), });