Cache lifetime-constant Beacon Node API responses
@varex83 ya está trabajando en esto.
Desde el 3/9/2026.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
Summary
Several Beacon Node API responses are constant for the lifetime of the client (genesis data, the chain spec, slots-per-epoch / slot duration, the deposit contract, …) yet Pluto re-fetches them over HTTP on every call. We should cache these once and reuse them, while being conservative: only cache what is genuinely immutable, and when in doubt make the extra call rather than risk serving stale data.
This came out of the core/scheduler review (PR #466). SchedulerActor::get_duty_definition issues a live fetch_slots_config() round-trip on every query just to derive slots_per_epoch:
slots_per_epoch never changes, so this is a per-call beacon round-trip on a hot path that blocks the actor. A general cache for lifetime-constant responses fixes this class of problem rather than just the one call site.
Where caching should live
Almost all the constant-data helpers funnel through two private base fetchers in extensions.rs, which makes them the natural memoization points:
fetch_spec_data(backs spec / slots config / fork config / domains): https://github.com/NethermindEth/pluto/blob/6a25109aaa6341f551754d0a02728dd75d8917eb/crates/eth2api/src/extensions.rs#L231fetch_genesis_data(backs genesis time / validators root / fork version / genesis domain): https://github.com/NethermindEth/pluto/blob/6a25109aaa6341f551754d0a02728dd75d8917eb/crates/eth2api/src/extensions.rs#L238
Memoizing just these two makes every downstream helper (fetch_genesis_time, fetch_slots_config, fetch_fork_config, fetch_domain*, …) cheap.
Note that EthBeaconNodeApiClient itself is an OpenAPI-generated struct, so a cache field can't simply be added to it without changing the generator:
A caching layer (or a small wrapper type) is therefore preferable. There is already precedent for this pattern in the crate — the epoch-aware ValidatorCache:
Reference: what Charon caches
Charon delegates this caching to go-eth2-client. Its eth2wrap code generator marks each endpoint with a Latency flag; Latency: false means "this endpoint is cached in go-eth2-client" (the generator literally emits that comment):
- interfaces map: https://github.com/ObolNetwork/charon/blob/749d2d7ab0b8ace34f2e686a5af5910c8adb4dc0/app/eth2wrap/genwrap/genwrap.go#L99
- "cached" comment template: https://github.com/ObolNetwork/charon/blob/749d2d7ab0b8ace34f2e686a5af5910c8adb4dc0/app/eth2wrap/genwrap/genwrap.go#L62
The endpoints Charon/go-eth2-client cache (Latency: false) are: BeaconBlockRoot, DepositContract, Domain, Genesis, NodePeerCount, NodeVersion, SlotDuration, SlotsPerEpoch, Spec. Notably ForkSchedule and Fork are NOT cached by Charon (Latency: true).
Category 1 — cache these (lifetime-constant; Charon caches them too)
| Data | Pluto method | Backing endpoint |
|---|---|---|
| Genesis (time, validators root, genesis fork version) | fetch_genesis_data → fetch_genesis_time, fetch_genesis_validators_root, fetch_genesis_fork_version |
get_genesis |
| Chain spec | fetch_spec_data / fetch_spec |
get_spec |
| Slot duration & slots-per-epoch | fetch_slots_config |
derived from spec |
| Signing domains | fetch_domain_type, fetch_genesis_domain, fetch_domain |
derived from spec + genesis |
| Deposit contract (address, chain id) | — (not yet wrapped) | get_deposit_contract |
| Beacon node version | — (not yet wrapped) | get_node_version |
Caching fetch_spec_data and fetch_genesis_data covers the whole first four rows at once.
Category 2 — semantically constant-ish, but do NOT cache (err on the side of caution)
| Data | Pluto method | Why not |
|---|---|---|
| Fork schedule | fetch_fork_config → get_fork_schedule |
Future forks can be (re)scheduled. Charon explicitly does not cache this (Latency: true). In Pluto it is derived from the spec, so it rides along with the spec cache only as far as the spec itself; treat new forks as a reason to re-read. |
| State fork | get_state_fork |
Per-state / per-fork-epoch, not lifetime-constant. Charon does not cache it. |
| Peer count | get_peer_count |
go-eth2-client marks it Latency: false, but it is semantically dynamic — do not cache in Pluto. |
| Block root | get_block_root |
Cached by go-eth2-client keyed by block_id; a single value cache is wrong here. Out of scope. |
Everything else (duties, validator state, syncing status, head/finality, pools, block production/submission, rewards, …) is dynamic and must not be cached.
Proposed scope
- Introduce a memoization layer for the two base fetchers (
fetch_spec_data,fetch_genesis_data) so all constant-data helpers become effectively free after the first call. - Use it to make
slots_per_epochavailable synchronously to the scheduler, removing the per-callfetch_slots_config()round-trip atscheduler.rs#L341. - Optionally extend the same mechanism to
get_deposit_contractandget_node_versionif/when they get high-level wrappers. - Leave Category 2 endpoints uncached.
- Lenguaje dominante
- Rust
- Estrellas
- 8
- Forks
- 5
- Merge medio
- 4 d 18 h
- PR fusionados (30 d)
- 4
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de NethermindEth/pluto
-
Dificultad 4/5 3-5 días Aptitud para principiantes 52/100
NethermindEth/pluto#719 ·
-
enhancement rust
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
NethermindEth/pluto#640 ·
-
rust
Dificultad 5/5 Más de una semana Aptitud para principiantes 45/100
NethermindEth/pluto#638 · 1 comentario ·
-
enhancement rust
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
NethermindEth/pluto#635 ·
-
Improve `alpha test peers`: match Charon's probes; reduce timeoutsPosiblemente ocupada @varex83agent la tomó hace 22 días. Abiertobug track:orchestration-cli
Dificultad 5/5 Más de una semana Aptitud para principiantes 28/100
NethermindEth/pluto#632 ·
Todos los issues de NethermindEth/pluto
Issues similares
-
bug: workspace access hint suggests a --subject command that fails for hyphen-leading OIDC subjectsAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
type: bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
`last_error_thread_local_then_global` fails when it runs beside the `lumen_event_detail` testAbiertoA-FFI C-Testing D-Straightforward S-Ready
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
docs priority:P3 size:XS
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
Los mantenedores suelen responder en 1 día
-
Appimage ConventionsAbiertoenhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día