Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Cache lifetime-constant Beacon Node API responses

未关闭
#481 1 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

@varex83 已经在做这个了。

开始于 2026年9月3日。

评估

这个 Issue 还没有评估数据。

描述

enhancement

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:

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):

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

  1. 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.
  2. Use it to make slots_per_epoch available synchronously to the scheduler, removing the per-call fetch_slots_config() round-trip at scheduler.rs#L341.
  3. Optionally extend the same mechanism to get_deposit_contract and get_node_version if/when they get high-level wrappers.
  4. Leave Category 2 endpoints uncached.
主要语言
Rust
星标
8
派生
5
平均合并
4 天 18 小时
30 天内合并 PR
4

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

NethermindEth/pluto 的其他 Issue

查看 NethermindEth/pluto 的全部 Issue

相似的 Issue

更多 Rust Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。