ObolNetwork / ObolNetwork/charon

app: distribute cluster proposer config (fee recipient / gas limit) to validator clients

Open
#4,692 0 comments 0 reactions 1 assignee View on GitHub

@KaloyanTanev is already working on this.

Since Sep 9, 2026.

protocol
Dominant language
Go
Stars
222
Forks
138
Avg merge
2d 6h
Merged PRs (30d)
35

Description

🎯 Problem to be solved

Charon currently ignores the VC's proposer config: prepare_beacon_proposer is a no-op (core/validatorapi/router.go, submitProposalPreparations) and register_validator is ignored (core/validatorapi/validatorapi.go, SubmitValidatorRegistrations). Charon injects the lock's fee recipient itself. As a result the VC-side fee recipient / gas limit are unmanaged and irrelevant today — CDVN VCs set none, and Teku even hardcodes --validators-proposer-default-fee-recipient 0x0000…0000.

Post-gloas the VC signs fee_recipient and target_gas_limit into SignedProposerPreferences (#4691), so its local config becomes load-bearing and must match the lock cluster-wide or the partial signatures won't aggregate. This issue: give Charon a way to push the cluster-canonical fee recipient + gas limit (lock FeeRecipientAddresses / TargetGasLimit) into the VCs.

This has independent, pre-gloas value — it makes VCs hold the correct fee recipient rather than relying on Charon's override — so it can land before the gloas duty.

Sub-task of the gloas epic #4324.

🛠️ Proposed solution

Findings

  • No standard config file exists. The ecosystem is standardizing an API instead — keymanager-APIs#87 (/eth/v1/validator/config, closed/contentious, not ratified), explicitly to kill the "different config dialect per client" burden it names for dappnode/eth-docker.
  • Per-client config surfaces:
    • Prysm / Teku / Lodestar — one central proposer_config JSON: --proposer-settings-file / --validators-proposer-config / --proposerSettingsFile.
    • Nimbus — per-validator files <validators-dir>/<pubkey>/suggested_fee_recipient.hex + suggested_gas_limit.json.
    • Lighthousevalidator_definitions.yml (keystore-entangled; standalone fee-recipient file removed); CDVN profile authors it from proposer-config.json on every container start (ObolNetwork/charon-distributed-validator-node#487).
  • Applying updates (matters for coordinated gas_limit bumps, which are applied staggered across operators): file rewrite + VC restart everywhere. File hot-reload exists only on Teku (--Xvalidators-proposer-config-refresh-enabled, per epoch) and Nimbus (per-validator files read live); Prysm/Lodestar re-read on restart; the CDVN Lighthouse adapter regenerates validator_definitions.yml from proposer-config.json on every container start, so a restart applies updates there too.

Mechanism

File-based, exclusively. The keymanager API is ruled out permanently (decision 2026-09-17) — charon generates proposer-config.json, per-client adapters derive native formats from it, and updates apply via file rewrite + VC restart. Post-gloas this same file is the alignment surface for the values VCs sign (SignedProposerPreferences, and later the builder url/auth_data signed into BuilderRequestAuth), so it must be byte-consistent across the cluster.

Tasks

  • Decide mechanism: (B) per-client file generation — one JSON parsed natively by Prysm/Teku/Lodestar (JSON is valid YAML); Nimbus + Lighthouse via generate-from-JSON adapters (LH: author the whole validator_definitions.yml — a supported workflow — generate, not merge). Always-on (no feature flag — the diff is small and generation is best-effort/create-once, decided in review of #4700).
  • Resolve canonical config from the lock: keyed by this node's pubshares (the identities the VC manages); fee_recipient from FeeRecipientAddresses, gas_limit from TargetGasLimit with registration/30M fallback (#4700)
  • keymanager path ruled out permanently — file-based is the mechanism
  • file path: generate proposer-config.json next to the lock, create-if-missing, best-effort (#4700)
  • Adapters: CDVN run.sh layer (all 5 VCs) — Prysm/Teku direct flag (native parse); Lodestar flag + extension shim (cp to .yml: its readFile throws UnsupportedFileFormat for .json, but content parses — unknown builder.enabled ignored, gas_limit must be string; verified in packages/cli/src/util/proposerConfig.ts); Nimbus renderer → per-validator suggested_fee_recipient.hex + suggested_gas_limit.json; Lighthouse (new CDVN profile) renderer → full validator_definitions.yml generation (replaces import; --disable-auto-discover). Shared: wait-for-file guard (docker creates a directory when bind-mounting a missing file path), restart-semantics docs (hot: Teku w/ refresh flag, Nimbus; restart: Prysm/Lodestar/Lighthouse)
  • CDVN wiring: mount the config file per VC profile; replace Teku's hardcoded zero fee-recipient default (ObolNetwork/charon-distributed-validator-node#486, #487)
  • charon edit-in-sync flow: extend charon alpha feerecipient fetch (or sibling vc-config sync) to rewrite proposer-config.json from the effective quorum-gated state — the existing sign → Obol-API-quorum → fetch flow is the sync point; sign should print the follow-through (fetch on every node + VC restart on Prysm/Lodestar/Lighthouse). Impl notes: export/move the unexported generator helpers from app for cmd/ use; rewrite via temp-file+rename (atomic vs Teku's periodic re-read); #4693's mismatch metric detects laggards

🔗 References

  • Epic: #4324
  • Proposer preferences duty: #4691

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.