Skip to content

Support Erigon Caplin consensus client#297

Open
stakepeter wants to merge 1 commit into
attestantio:masterfrom
stakefish:feat/erigon-caplin-support
Open

Support Erigon Caplin consensus client#297
stakepeter wants to merge 1 commit into
attestantio:masterfrom
stakefish:feat/erigon-caplin-support

Conversation

@stakepeter

Copy link
Copy Markdown

Summary

Erigon's Caplin consensus client emits a few JSON fields in non-spec-compliant forms. This PR softens the affected unmarshalers to accept both spec and Caplin forms while keeping marshal output spec-strict. The fix is purely additive — public API, marshal output, and SSZ encoding are all unchanged.

Three classes of divergence are handled:

  1. Bare-number uint64 fields in execution_requests and pending_* state queues. Caplin's struct definitions in cl/cltypes/solid/{deposits,withdrawal,consolidation}.go omit the spec's ,string tag on amount, index, slot, validator_index, and withdrawable_epoch. Soften phase0.{Gwei,Slot,Epoch,ValidatorIndex}.UnmarshalJSON and electra.DepositRequest's JSON parsing to accept both "42" (spec) and 42 (Caplin). Marshal still emits "42".
  2. previous_epoch_participation / current_epoch_participation as a single hex string. Caplin's ParticipationBitList.MarshalJSON emits the raw SSZ encoding as "0x..."; the spec requires a JSON array of decimal-string flags. Added altair.ParseParticipationFlags / MarshalParticipationFlags helpers and wired them into the altair / bellatrix / capella / deneb / electra / fulu BeaconState JSON paths. Accepts both forms; emits spec form.
  3. Provider detection. Added a caplin case to multi.Service's provider detection so the multi-client recognizes Caplin nodes.

This makes downstream consumers work directly against Caplin without per-application JSON-rewriting shims.

Test plan

  • go test ./... — all packages green
  • go vet ./... clean; gofmt -l clean on touched files
  • New positive tests for each lenience point: bare numbers for phase0.{Gwei,Slot,Epoch,ValidatorIndex}, mixed/bare/missing/invalid cases for electra.DepositRequest, hex/array/null/invalid cases for altair.ParseParticipationFlags
  • Round-trip tests (TestBeaconBlockJSON/Good, TestSignedBeaconBlockYAML/Good, TestMarshalParticipationFlags_Roundtrip, TestDepositRequestUnmarshalJSON marshal-after-parse) confirm wire output is byte-identical for spec-form inputs
  • Manually verified each Caplin divergence by reading the corresponding struct in github.com/erigontech/erigon's cl/ package

Caplin emits several JSON fields with bare numbers where the beacon API
spec requires quoted decimal strings, and serializes
`previous_epoch_participation`/`current_epoch_participation` as a single
0x hex string instead of a JSON array. Soften the affected unmarshalers
to accept both forms while keeping marshaling spec-strict, and recognize
Caplin in the multi-client provider detection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant