Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/e2e/kurtosis.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
participants:
# Two identical nodes. buildoor is wired to node 1 (cl-1/el-1) and publishes
# its p2p bids through node 1's beacon API, which only gossips them to peers:
# since lodestar v1.47.0 (ChainSafe/lodestar#9998) the API publish path no
# longer feeds the node's own bid pool and gossipsub never loops a
# self-published message back, so node 1's validators are blind to buildoor's
# p2p bids. The post-Gloas p2p phase is therefore won on node 2's proposals,
# whose bid pool is fed by gossip from node 1.
- el_type: nethermind
el_image: ethpandaops/nethermind:glamsterdam-devnet-8
cl_type: lodestar
cl_image: ethpandaops/lodestar:glamsterdam-devnet-8
vc_image: ethpandaops/lodestar:glamsterdam-devnet-8
validator_count: 32
supernode: true
count: 2
# From Gloas the external builder is configured on the VALIDATOR client and
# the beacon node requests bids from it on the validator's behalf, so the
# CL-side --builder.urls the package wires up only covers the pre-Gloas
Expand All @@ -18,7 +26,13 @@ participants:

network_params:
preset: minimal
genesis_delay: 20
# buildoor is launched after both participants and must be listening before
# slot 0: the lodestar VCs register their validators with the builder once
# at the start of epoch 0 and retry only at the next epoch boundary, which
# is already Gloas (gloas_fork_epoch 1), so a late buildoor loses the whole
# pre-Gloas Builder API phase (slots 0-7). Two nodes take ~90 s to come up
# on a GitHub runner.
genesis_delay: 120
gloas_fork_epoch: 1

mev_type: buildoor
Expand Down
5 changes: 5 additions & 0 deletions .github/scripts/e2e-kurtosis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,11 @@ jq -e '.data.PRESET_BASE == "minimal" and (.data.GLOAS_FORK_EPOCH | tonumber) ==
# both are active cannot tell us which one the proposer actually used. The
# post-Gloas phases therefore run one flow at a time, toggled through the
# settings API, and only accept wins from slots frozen after the toggle.
#
# The p2p phase needs the enclave's second node: buildoor publishes its bids
# through node 1's beacon API, which only gossips them to peers (lodestar >=
# v1.47.0 no longer feeds its own bid pool from the API path), so node 1's
# validators never see them and the win comes from a node 2 proposal.

echo "== Phase 1: pre-Gloas Builder API (getHeader / blinded block)"
pre_block=$(wait_for_win pre-gloas builder_api 0 $((GLOAS_SLOT - 1)) "$PREGLOAS_TIMEOUT_SECONDS")
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/_shared-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ jobs:
e2e_kurtosis:
name: Run Kurtosis E2E
runs-on: ubuntu-latest
# The check runs three win phases in one enclave (pre-Gloas Builder API,
# post-Gloas p2p, post-Gloas Builder API); the post-Gloas ones first wait
# for the builder's deposit to activate on chain.
# The check runs three win phases in one two-node enclave (pre-Gloas
# Builder API, post-Gloas p2p, post-Gloas Builder API); the post-Gloas
# ones first wait for the builder's deposit to activate on chain. The
# second node is what makes the p2p phase observable at all: the bid must
# reach a proposer over gossip (see .github/e2e/kurtosis.yaml).
timeout-minutes: 60
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
14 changes: 14 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,20 @@ npm run clean
- Calls Engine API to construct execution payloads (forkchoiceUpdated → getPayload)
- Emits `PayloadReadyEvent` to subscribers; plan-involved skips fire
`BuildSkippedEvent` (deduped per slot) for the slot results tracker
- **Missing-block fallback** (`applyAttributesFallback`): when no attributes
arrived for a slot by its build start time, the previous slot's are
re-used with the proposal slot advanced and the event marked
`Synthesized`. Such attributes are stale whenever the state moved in
between (an epoch transition changes the expected withdrawals), and Teku
emits next-slot attributes only ~30 ms before the build start, so the
fallback can win the race against a late node event. A node-received
event for the same parent tuple therefore SUPERSEDES a build that ran
from synthesized attributes (`supersedeSynthesizedBuild`): unless its
build inputs are identical (`PayloadAttributesEvent.BuildInputsEqual`),
the in-flight engine build is cancelled, an already emitted payload is
withdrawn from the payload cache (a `PayloadBuildFailedEvent` with reason
`superseded by beacon node attributes` is recorded) and the tuple is
rebuilt from the node's attributes via the late-build path

2. **Payload Bidder** (`pkg/payload_bidder/`) — shared Gloas+ bid/reveal domain
- `Signer`, `BuildSignedBid`, `BuildSignedEnvelope`: bid/envelope construction + signing
Expand Down
Loading