Skip to content

feat: implement proposer preferences for Gloas (EIP-7732)#1

Open
lodekeeper wants to merge 2 commits intounstablefrom
feat/proposer-preferences
Open

feat: implement proposer preferences for Gloas (EIP-7732)#1
lodekeeper wants to merge 2 commits intounstablefrom
feat/proposer-preferences

Conversation

@lodekeeper
Copy link
Owner

Description

End-to-end proposer preferences implementation for Gloas (EIP-7732), addressing beacon-APIs #570 and #435.

Beacon Node

  • Gossip: New proposer_preferences topic with full wiring (GossipType, SSZ type mapping, topic encoding, scoring parameters, FIFO queue, handler)
  • Validation: epoch+1 check, proposer lookahead match, dedup via seen cache, BLS signature verification under DOMAIN_PROPOSER_PREFERENCES
  • Pool: ProposerPreferencesPool (slot → preferences) with 2-epoch retention + SeenProposerPreferences tracking
  • Bid validation: Require matching preferences before accepting bids — fee_recipient and gas_limit must match proposer preferences (resolves TODO GLOAS comments)
  • API:
    • POST /eth/v1/validator/proposer_preferences — VC submits signed preferences
    • GET /eth/v1/beacon/pool/proposer_preferences — query pool (optional ?slot= filter)
  • SSE: proposer_preferences event type
  • Metrics: Pool size gauge + gossip/api insert outcome counters

Validator Client

  • pollProposerPreferences: Epoch-boundary polling — queries next-epoch proposer duties, filters own validators, signs preferences (fee_recipient + gas_limit from config), submits to BN
  • ValidatorStore.signProposerPreferences: Signs with DOMAIN_PROPOSER_PREFERENCES
  • External signer support: PROPOSER_PREFERENCES message type in web3signer client

State Transition

  • getProposerPreferencesSigningRoot: Computes signing root for proposer preferences

Tests

  • Unit tests for ProposerPreferencesPool (insert, dedup, prune)
  • Unit tests for proposer preferences validation (accept valid, reject bad lookahead, ignore duplicate, reject bad signature)
  • Gossip topic encoding/decoding test
  • API route test data for all new endpoints

Companion


Generated with assistance from AI (Codex CLI + Claude)

End-to-end proposer preferences implementation:

**Beacon Node:**
- New gossip topic `proposer_preferences` with validation, scoring, queue config
- ProposerPreferencesPool + SeenProposerPreferences (with pruning)
- Validation: epoch+1 check, proposer lookahead match, dedup, BLS signature
- Bid validation: require matching preferences (fee_recipient + gas_limit)
- API: POST /eth/v1/validator/proposer_preferences (submit)
- API: GET /eth/v1/beacon/pool/proposer_preferences (query)
- SSE event: proposer_preferences
- Metrics: pool size, gossip/api insert outcomes

**Validator Client:**
- pollProposerPreferences: epoch-boundary polling, queries next-epoch proposer
  duties, signs preferences with fee_recipient/gas_limit, submits to BN
- ValidatorStore.signProposerPreferences with DOMAIN_PROPOSER_PREFERENCES
- External signer support (PROPOSER_PREFERENCES message type)

**State Transition:**
- getProposerPreferencesSigningRoot helper

Addresses beacon-APIs ChainSafe#570 and ChainSafe#435.
Resolves TODO GLOAS comments in bid validation.

Generated with assistance from AI (Codex CLI + Claude).
- Use proposalSlot (not stateSlot) for domain computation to ensure
  correct fork version at the Gloas fork boundary
- Include PROPOSER_PREFERENCES_WEIGHT in maxPositiveScore sum
nflaig added a commit that referenced this pull request Feb 16, 2026
…sponse (ChainSafe#8908)

## Motivation

The e2e reqresp tests "should handle a server error" and "should handle
a server error after emitting two blocks" have been consistently flaky,
appearing in **~90% of all CI E2E test failures**. Analysis of ~100
recent CI runs confirmed this as the #1 source of E2E flakiness.

The failure pattern:
```
expected { code: "REQUEST_ERROR_SERVER_ERROR", errorMessage: "" }
to deeply equal { code: "REQUEST_ERROR_SERVER_ERROR", errorMessage: "TEST_EXAMPLE_ERROR_1234" }
```

The error status code is received correctly, but the error message is
empty.

## Root Cause

`responseEncodeError()` yields the error status byte and snappy-encoded
error message as **separate chunks** through the async generator:

```ts
yield Buffer.from([status]);  // chunk 1
yield* encodeErrorMessage(errorMessage, protocol.encoding);  // chunk 2+
```

When piped through `stream.sink`, libp2p can close/flush the stream
after the first yield completes but before the subsequent error message
chunks are delivered to the reader side. The `readErrorMessage()`
function on the receiving end then finds no data after the status byte
and returns an empty string.

## Fix

Collect the status byte and encoded error message into a single
`Buffer.concat()` yield, ensuring they are delivered atomically through
the stream. This eliminates the race condition without changing the wire
format.

## Notes

- All existing reqresp unit tests pass (85/85)
- The wire format is unchanged — the same bytes are sent, just in a
single chunk instead of multiple
- This is consistent with how other protocols handle similar issues
(combining header + payload)

> This PR was authored by an AI contributor. All code was reviewed by
sub-agents before submission.

---------

Co-authored-by: lodekeeper <lodekeeper@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <175061342+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Nico Flaig <nflaig@protonmail.com>
lodekeeper added a commit that referenced this pull request Feb 25, 2026
- Remove all write commands (pnpm build/lint, git checkout/merge, gh pr/api)
  from default allowlist — keep only read-only commands per review feedback
- Remove find from allowlist (supports -delete and -exec)
- Remove marketplace plugin config (PR #1 closed in favor of this PR)
- Use isolated --dataDir /tmp/lodestar-debug in local-mainnet-debug skill
  instead of touching default mainnet database
- Update cleanup section to only remove isolated debug directory
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