WebUI builder exit button & exited-key safety - #144
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WebUI builder exit button & exited-key safety
Adds a builder exit button to the WebUI and hardens the lifecycle around what an exit actually means on chain. While reviewing the exit flow against the Gloas consensus specs, it turned out that an exited builder key is effectively burned — and that buildoor's auto-topup would cycle funds through the exited entry forever. This PR ships the button together with the guards and UI flagging that make exiting safe.
Builder exit button
WebUI exit button (6528f88)
The Builder Info card gains an "Exit Builder" button (visible when lifecycle management is available, the operator is logged in, and the builder is
registered/pending_finalization) with an inline confirm → submitting → done/error flow. It calls the existingPOST /api/lifecycle/exitendpoint, which submits an EIP-8282 builder exit request through the exit system contract.Also fixes
Manager.InitiateExitgating: it rejected builder index 0, but 0 is a valid builder index — only the registration flag tells whether an exit can be submitted.EIP-8282 predeploy address update + code guard (c10506c)
Updates the builder deposit/exit predeploy addresses to the current EIP-8282 draft (ethereum-genesis-generator#300). Since a stale address would silently accept requests as plain value transfers (an empty account reads storage slot 0 as zero, indistinguishable from an active contract with an empty queue),
ReadQueueFeenow verifies code exists at the contract address first and fails loudly withErrContractNotDeployedotherwise. Before the Amsterdam fork this is the normal "not yet deployed" state and is treated as deferred, like a too-high queue fee.Exit gas limit raise (c55b571)
The current EIP-8282 exit predeploy consumes ~590k gas for a request append (observed on glamsterdam-devnet-7), far above the ~100k an EIP-7002-style append would suggest. The exit gas limit now matches the deposit gas limit (1M).
Exited builder keys are burned
Checked against the Gloas consensus spec (
process_builder_deposit_request): onceinitiate_builder_exitsetswithdrawable_epoch(current +MIN_BUILDER_WITHDRAWABILITY_DELAY= 64 epochs), the builder permanently failsis_active_builder. A later deposit for the same pubkey never re-registers it — while the pubkey is still instate.buildersit is treated as a top-up of the exited entry, and if the entry was already swept (balance 0), the deposit resetswithdrawable_epochto now+64, locking the funds for another 64 epochs before the sweep returns them to the wallet. The spec says it outright:The pubkey only becomes depositable again once its registry index is reused by a different builder's deposit (
get_index_for_new_builderoverwrites swept slots), removing the pubkey from the registry — on a devnet with few builders, potentially never. Once it's gone,GetBuilderByPubkeyreturns nil and the normal registration flow deposits fresh (a restart picks this up automatically).Without guards this was a live money-cycling bug: after the sweep zeroes the balance,
NeedsTopupsees0 < thresholdand the auto-topup deposits into the exited entry every cooldown — wallet → exited entry → (64 epochs locked) → wallet, burning gas + queue fee each round, forever.Lifecycle guards
chain.HasBuilderExited(info): shared predicate for "exit initiated" (WithdrawableEpoch != FAR_FUTURE_EPOCH), with a table-driven test.lifecycle.ErrBuilderExited, refused by bothDepositService.CreateDeposit(the single choke point for deposits and top-ups; a fresh registration with the pubkey absent from the registry still passes) andBalanceService.NeedsTopup. The balance monitor treats it as a quiet steady state (debug log); the manual/api/lifecycle/topupendpoint returns the error to the caller.Manager.InitiateExitchecks the live chain entry (not the 1-minute-stale cached state) and rejects:process_builder_exit_requestsilently no-ops whileget_pending_balance_to_withdraw_for_builder != 0, so the transaction would confirm but the exit never happen.state_changewarning event (noticeExitOnce) the first time an initiated exit is seen on chain — including at startup after a restart — re-armed if the key ever shows up freshly registered again.WebUI exited-key flag
The Builder Info card shows an amber callout when the registration state is
exiting/exited: the key cannot be reactivated, deposits to it are withdrawn back to the wallet, automatic top-ups are disabled, and the key only becomes usable again after its registry slot is reused by another builder's deposit. The exit button itself is already hidden in those states.