Skip to content

feat: move deposit/withdrawal/stake processing into ConsensusState - #440

Merged
matthias-wright merged 43 commits into
mainfrom
m/refactor-deposit-withdrawal
Sep 4, 2026
Merged

matthias-wright merged 43 commits into
mainfrom
m/refactor-deposit-withdrawal

Conversation

@matthias-wright

Copy link
Copy Markdown
Collaborator

This reworks how Summit handles deposits, withdrawals, staking, and committee transitions: the logic moves out of the finalizer actor and into ConsensusState, making the state transition self-contained, deterministic, and unit-testable without the finalizer/EL harness.
This also addresses #339 and #362, superseding #379 and #397.

Changes:

  • Move execution request (deposit, withdrawal, etc) processing from the finalizer actor into the ConsensusState.
  • Execution requests are no longer parsed on arrival. They are only buffered.
  • Withdrawal queue format was simplified, withdrawals are no longer keyed by validator key.
  • Balance is no longer deducted when the withdrawal request arrives. The withdrawal amount is deducted from the balance only after the withdrawal lands in a block.
  • Partial withdrawal requests for active validators are clamped to avoid withdrawing the balance below MinimumStake.
  • Removed MaximumStake param, validators can stake as much as they want.
  • When MinimumStake is increased, validators with balance < MinimumStake are still removed from the committee (if the resulting committee size is still larger than a defined minimum), but the remaining balance is no longer withdrawn automatically. Removed validators may withdraw their balance at any time.
  • Removed the has_pending_deposit and has_pending_withdrawal fields from the validator accounts.
  • Added FullPayoutPending to distinguish a validator that has left the committee with its full balance committed to a pending payout (must not rejoin) from a plain Inactive validator (out of committee, keeps its balance, may rejoin via a top-up and may hold a pending partial withdrawal). Without the FullPayoutPending, an incoming deposit would re-activate a validator whose entire balance is about to be withdrawn.
  • Reject unverified-block withdrawals before EL forkchoice adoption.
  • Clamp terminal-block payouts against a raised minimum.

@matthias-wright
matthias-wright force-pushed the m/refactor-deposit-withdrawal branch from d57c7b6 to b8b0a0f Compare August 6, 2026 10:00
@matthias-wright
matthias-wright merged commit a41d1dc into main Sep 4, 2026
4 checks passed
@matthias-wright
matthias-wright deleted the m/refactor-deposit-withdrawal branch September 4, 2026 07:18
matthias-wright added a commit that referenced this pull request Sep 4, 2026
Builds on #440.

### Update to 2026.5.0 (4bee996):
- Bumps all commonware crates from 2026.4.0 to 2026.5.0.
- Applies the API updates.
- Updates the syncer with the recent marshal changes, specifically:
    - Introduces new modules:
- floor.rs: processed floor as (height, round); all fetches gated by
fetch_if_permitted, denying at/below either floor.
- stream.rs: durable application-progress cursor (last acked height).
- acks.rs: FIFO pipeline of in-flight application acks, capped by
`max_pending_acks`.
- delivery.rs: parsed deliveries held for batch certificate
verification.
     - Uses the new `commonware-actor` crate to rebuild the mailbox.
- Resolver now attaches a local annotation to each fetch which contains
information about if the fetch is for a Notarization/Certified/Finalized
and the corresponding round/height. This information can be used when
processing the response, for example for discarding stale data.
     - Resolver no longer blocks on delivery.
     - The actor.rs run loop is now select_loop! with arms ordered.
     - Notarization arm no longer eagerly fetches a missing block

This update also fixes
#357,
#356, and
#346.

### Update to 2026.7.0 (1c8c524):
- Bumps all commonware crates to 2026.7.0 (commonware skipped 2026.6.0).
- Port marshal’s new asynchronous durability model into the syncer.
- Return durability handles for proposed, verified, and certified
blocks.
- Gate certification and notarized updates on durable block and
certificate storage.
- Keep finalized archive syncs non-blocking while preserving per-batch
dispatch ordering.
- Preserve `NotarizedBlock` before `FinalizedBlock` ordering for the
same block.
- Support multiple verified candidates per round and epoch-terminal
reproposals.
- Apply buffer-delivered blocks to pending floor anchors.
- Port resolver, deduplication, closed-response, and archive
existence-check refinements.
matthias-wright added a commit that referenced this pull request Sep 4, 2026
…443)

Builds on #440 and
#442.

The deposit request signature format changed in
#282.

This PR freezes three signed deposit requests as
`types/fixtures/deposit_requests.json` in the 288-byte EL wire format,
plus tests that pin both directions.
The frozen deposit requests are used for testing the deposit request
function in the client SDKs.

Changes:
- `committed_fixtures_match_generator`: the file matches what the
current signing/encoding code produces; any change to the wire format,
signing message, or domain derivation fails here and forces a conscious
regen
- `frozen_requests_parse_and_round_trip`: `try_from_eth_bytes` parses
the frozen bytes into exactly the recorded fields and re-encodes
identically
- `frozen_requests_verify_and_process`: the vectors pass signature
verification and produce the expected validator accounts
- `mutated_frozen_requests_are_rejected`: corrupted signatures/amounts
are rejected with the right `DepositRejectionReason`; the index bytes
are provably outside the signed message
matthias-wright added a commit that referenced this pull request Sep 4, 2026
Builds on #442 (which
builds on #440).

Changes:
- Add counters for critical error logs.
- Report equivocation to finalizer and add critical logs with counters
that will be picked up by AlertManager.
matthias-wright added a commit that referenced this pull request Sep 4, 2026
…#453)

Builds on #445 (which
builds on #442 and
#440).

Changes:
 - Add a standalone localhost deposit-signing server.
 - Load the weak-subjectivity anchor from TOML.
 - Add withdrawal queue getters.
 - Report withdrawal parsing failures as warnings.
 - Fix the missing Prometheus counter import.
kriss39 pushed a commit to kriss39/seismic that referenced this pull request Sep 21, 2026
…eismicSystems/deploy#115)

summit removed the MaximumStake protocol param in
SeismicSystems/summit#440 ("Removed `MaximumStake` param, validators can
stake as much as they want"), which dropped validator_maximum_stake from
its example_genesis.toml. SummitStarterDriftTests fetches that file from
summit main live, so the drift suite went red on every deploy branch the
moment it merged. This is what that test is for: the starter carries
summit's parameter set, and summit owns the schema.

The starter's key set matches summit main again. The two example-devnet
copies lose the same line, so no file in the repo names a parameter
summit no longer has.

Removing it from example-devnet does not move
summit.genesis_config_digest. The digest is SSZ over the parsed Genesis,
and a field the struct no longer declares is ignored on the way in —
`summit genesis digest` returns 0x20103ec0…9271 for that file with the
line and without it. So the manifest is untouched and network_id is
unchanged.

That same check surfaced drift this commit deliberately does not fix.
example-devnet's committed digest is 0x85b39636…cadc, and summit main
computes 0x20103ec0…9271 for the file as committed — stale from summit's
genesis struct evolving, not from anything here. It also predates three
params summit has since added (treasury_address,
minimum_validator_count, invalid_deposit_tax); it parses because each
has a serde default, and writing those defaults explicitly is
digest-neutral.

Nothing in CI catches any of that: CommittedNetworkDirTests feeds the
committed digest back in through digest_fn, because summit publishes no
release binary, so the one gate that would recompute it never runs.
Re-pinning example-devnet to a summit revision is its own change, and
worth doing alongside a way to notice the next time it drifts.

deploy_gcp/genesis/example_genesis*.toml still carry the param. They
belong to the GCP path and no drift guard reads them.

Verified with summit built at fa436b4 (main) and enclave's
seismic-manifest at ec85afb; the starter's key set was checked against
summit main's example_genesis.toml with the assertion the drift test
makes.

Co-authored-by: Claude Opus 5 (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