Add builder execution requests (EIP-8282) - #5359
Conversation
The gloas bid and envelope carry an `ExecutionRequests` extended with `builder_deposits` (0x03) and `builder_exits` (0x04) per ethereum/consensus-specs#5359. Using `ssz.electra.ExecutionRequests.hashTreeRoot` in the gloas-only code paths produced a root over the electra-shaped container — wrong even when both builder lists are empty, because the gloas container has two additional zero-hash leaves. Switch the four gloas-only call sites to `ssz.gloas.ExecutionRequests`: * `produceBlockBody.ts` self-build bid construction * `verifyExecutionPayloadEnvelope.ts` bid↔envelope cross-check * `executionPayloadEnvelope.ts` gossip validation * `upgradeStateToGloas.ts` genesis bid default-value root Refs: ethereum/consensus-specs#5359, ethereum/EIPs#11760 🤖 Generated with AI assistance
processBuilderDepositRequest (3 cases): * register on first appearance when PoP verifies * drop silently when PoP fails * top-up an existing builder without re-verifying signature and without rebinding withdrawal credentials (matches validator deposit contract semantics) processBuilderExitRequest (5 cases): * drop for unknown pubkey * drop for inactive builder (`deposit_epoch >= finalized_epoch`) * drop when `source_address` ≠ builder execution address * drop when builder already has pending withdrawal queued * initiate exit on the happy path (sets withdrawableEpoch = currentEpoch + MIN_BUILDER_WITHDRAWABILITY_DELAY) JSON shape (4 cases): * BuilderDepositRequest snake_case round-trip * BuilderExitRequest snake_case round-trip * ExecutionRequests carries builder_deposits / builder_exits alongside the existing deposits/withdrawals/consolidations keys * ExecutionPayloadEnvelope JSON round-trip with builder requests populated Refs: ethereum/consensus-specs#5359, ethereum/EIPs#11760 🤖 Generated with AI assistance
|
On a side note, since there is concern about adding a lot of noise in the spec just for the builder onboarding mechanism at the fork. I wonder if we can extract that part from beacon-chain.md cleanly and put it in a separate file, labeling that this mechanism is a one time use only |
|
|
||
| ## Becoming a builder | ||
|
|
||
| ### Builder withdrawal credentials |
There was a problem hiding this comment.
Why is this removed? We still have withdrawal credentials for builders, instead of withdrawal prefix we have builder version for the first byte
There was a problem hiding this comment.
I guess we should also point out what the supposedly correct value of builder version should be in gloas, albeit it is not checked or enforced anywhere
There was a problem hiding this comment.
Why is this removed? We still have withdrawal credentials for builders, instead of withdrawal prefix we have builder version for the first byte
This section was removed because I believe it's sufficiently covered by the "submit deposit" section.
I guess we should also point out what the supposedly correct value of builder version should be in gloas, albeit it is not checked or enforced anywhere
If this PR is merged, I'm planning to follow up with a PR which states that new builder deposits should use version 0 instead of version 3 (BUILDER_WITHDRAWAL_PREFIX). This change is independent of EIP-8282 and I don't want to overcomplicate this PR. But yes, this will not be enforced by the protocol. It will be possible to create a builder with whatever version. Doing so would be unwise though, as it may restrict future abilities. We want to allow this so that future builder versions can exist at the fork. For example, we may decide to have separate versions for payload builders and proof builders, for when mandatory proofs are a thing.
There was a problem hiding this comment.
Just leaving a random thought that version might be an overengineering or a wise forward-thinking decision. No idea at the moment 🤷♂️
There was a problem hiding this comment.
Yeah 😅 hopefully the latter. Good to have options though I guess.
For the most part, this is already the case. The onboarding function is in |
| | Name | Value | | ||
| | ------------------------ | -------------------------- | | ||
| | `DOMAIN_EXECUTION_PROOF` | `DomainType('0x0E000000')` | | ||
| | `DOMAIN_EXECUTION_PROOF` | `DomainType('0x0F000000')` | |
There was a problem hiding this comment.
| | `DOMAIN_EXECUTION_PROOF` | `DomainType('0x0F000000')` | | |
| | `DOMAIN_EXECUTION_PROOF` | `DomainType('0x0G000000')` | |
There was a problem hiding this comment.
Hmm 0x0F doesn't exist yet here. Since this is based on Gloas, not Heze. But yeah, we can change this optimistically.
There was a problem hiding this comment.
If this comes before Heze, the domain in Heze would change instead. If that makes sense.
There was a problem hiding this comment.
Either this or Heze's one should be changed. Slightly prefer to change this one to G because it's not entirely scheduled to ship this.
There was a problem hiding this comment.
To be clear, since both are currently based off Gloas they do not need to be different right now. After thinking about this for a while, I have just pushed a commit with changes Heze's DOMAIN_INCLUSION_LIST_COMMITTEE to 0x10000000. I changed this instead of DOMAIN_EXECUTION_PROOF because (1) I consider optional proofs to be part of Gloas and (2) I expect optional proofs to go live on mainnet before Heze does.
| add_builder_to_registry( | ||
| state, | ||
| request.pubkey, | ||
| uint8(request.withdrawal_credentials[0]), |
There was a problem hiding this comment.
can't this be set to any arbitrary value between 0x00 and 0xFF?
There was a problem hiding this comment.
Yes it can. And that's intentional. This would work the same as validators do today. For instance, there's nothing stopping you from creating a validator with a 0x04 withdrawal credential. Do you think we should restrict this to some value? It would make it difficult/impossible to have another builder version at the fork. For example say builders v0 are for execution payloads and builders v1 are for block proofs. At the fork for mandatory proofs, we may want v1 builders to exist in the registry already.
There was a problem hiding this comment.
yeah we have the same for validators today, I don't see any harm, not right now anyways since version is unused. seems reasonable to keep the door open to have new type of builders before the actual fork, but would be good then if we can ensure that tooling will set the version to 0x00 in gloas
There was a problem hiding this comment.
Yup will ensure tooling uses 0x00 for builders.
There was a problem hiding this comment.
I believe it's better to constrain this value, it's fine if you want to have it configurable in a range. But allowing any value to be used now would preclude us from actually enforcing behavior on a version if we need to in the future. Eg. Suppose we want to force in the future that all builders of type 0xEF must have execution address potuz.eth. Some builder can frontrun and prevent that behavior right now by sending an 0xEF builder right now. It would be better to at least reserve an unused section right now, eg for example assert request.withdrawal_credentials[0] & 0xF0 == 0x00.
There was a problem hiding this comment.
@potuz let's debate this later. I'm not strongly opposed to reserving those versions just in case, but I don't believe there will be a situation in which it would be necessary. As said on discord, I believe such checks should exist elsewhere, not when deciding if the builder should be added to the registry.
| @with_gloas_and_later | ||
| @spec_state_test | ||
| def test_process_parent_execution_payload__builder_deposit_after_pending_validator(spec, state): | ||
| def test_process_parent_execution_payload__builder_credential_deposits_queued(spec, state): |
There was a problem hiding this comment.
test case(s) for builder exit requests are missing
There was a problem hiding this comment.
What kind of tests do you have in mind here? Feel free to commit some. To be clear, we do have builder exit requests here but these are not with process_parent_execution_payload.
There was a problem hiding this comment.
if I comment out L1211 does any test catch this?
the tests you referenced are calling process_builder_exit_request directly but not if it's wired up correctly in process_parent_execution_payload, I might be missing a test that catches this
There was a problem hiding this comment.
I'm pretty sure the answer is no, that would not be caught with the current tests. We should add a test for this. I'm a bit busy at the moment. Would you have time to add a test for this?
There was a problem hiding this comment.
yes I can push a test for that, currently running the existing tests against lodestar to make sure we are passing them
There was a problem hiding this comment.
pushed a test for this c84f2e4, this will catch if process_parent_execution_payload is incomplete and doesn't call process_builder_exit_request
| # 2**8 (= 256) builder deposit requests | ||
| MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD: 256 | ||
| # 2**4 (= 16) builder exit requests | ||
| MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD: 16 |
There was a problem hiding this comment.
This may be very costly, but with these numbers assymmetric, someone could make a ton of deposits and then withdraw all of them and take the whole churn for a long time.
There was a problem hiding this comment.
I don't think there is a good reason to use such a low value for exits as they are generally cheap to process
There was a problem hiding this comment.
Staying in the target of 2 exit requests per payload, it would require locking up 14,400 ETH ($30m) to delay the builder exit queue by one day. This doesn't feel like a realistic concern.
There was a problem hiding this comment.
no, not a concern imo, we have a really high MIN_BUILDER_WITHDRAWABILITY_DELAY so this would be way too expensive, and exiting builders isn't actually time sensitive and already takes a long time
|
|
||
| ### Withdrawal prefixes | ||
|
|
||
| *Note*: `BUILDER_WITHDRAWAL_PREFIX` is a temporary constant which is only used |
There was a problem hiding this comment.
A postteriori it would've been cooler to have this one be 0x0B or 0xBB
There was a problem hiding this comment.
We still can do this btw. I would support this.
| ```python | ||
| class BuilderExitRequest(Container): | ||
| source_address: ExecutionAddress | ||
| pubkey: BLSPubkey |
There was a problem hiding this comment.
For validators, this entry is called validator_pubkey, perhaps this one should be called builder_pubkey for symmetry.
There was a problem hiding this comment.
Eh I would prefer not to change this, but not strongly opposed.
WithdrawalRequest(which you're comparing it to) usesvalidator_pubkeybut I would argue that it's necessary there because the structure name does not contain "validator". This is unlikeBuilderExitRequestin which it's explicit that the pubkey is associated with a builder.pubkeyis used inBuilderDepositRequest, so if we change this we would have to change that too, and then it's non-symmetric withDepositRequestwhich also usespubkey.
| add_builder_to_registry( | ||
| state, | ||
| request.pubkey, | ||
| uint8(request.withdrawal_credentials[0]), |
There was a problem hiding this comment.
I believe it's better to constrain this value, it's fine if you want to have it configurable in a range. But allowing any value to be used now would preclude us from actually enforcing behavior on a version if we need to in the future. Eg. Suppose we want to force in the future that all builders of type 0xEF must have execution address potuz.eth. Some builder can frontrun and prevent that behavior right now by sending an 0xEF builder right now. It would be better to at least reserve an unused section right now, eg for example assert request.withdrawal_credentials[0] & 0xF0 == 0x00.
implements the following spec changes required to pass `v1.7.0-alpha.11` spec tests - ethereum/consensus-specs#5359 - ethereum/consensus-specs#5377 - ethereum/consensus-specs#5373 - ethereum/consensus-specs#5365 - ethereum/consensus-specs#5364 - ethereum/consensus-specs#5368 --------- Co-authored-by: NC <17676176+ensi321@users.noreply.github.com>
This PR integrates EIP-8282 into Gloas.
Note: This was made in collaboration with @ensi321 🙂