Skip to content

Commit 84454a9

Browse files
authored
Restrict builder deposits to payload builders (#5439)
Alternative to #5435 which restricts builder registrations to the payload builder version in Gloas, i.e. only builders with `version` of `PAYLOAD_BUILDER_VERSION` can exist for now. Builder deposit requests are ignored unless the withdrawal credentials start with `BUILDER_WITHDRAWAL_PREFIX`. This keeps Gloas strict about accepted builder deposit credentials while leaving room for future forks to define additional builder versions.
1 parent bd46c06 commit 84454a9

6 files changed

Lines changed: 56 additions & 29 deletions

File tree

pysetup/spec_builders/heze.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ def is_inclusion_list_satisfied(self: ExecutionEngine,
6868
def deprecate_functions(cls) -> set[str]:
6969
return {
7070
"initialize_ptc_window",
71-
"is_builder_withdrawal_credential",
7271
"is_pending_validator",
7372
"onboard_builders_from_pending_deposits",
7473
"upgrade_to_gloas",

specs/gloas/beacon-chain.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1774,13 +1774,17 @@ caching should account for this behavior.
17741774

17751775
```python
17761776
def process_builder_deposit_request(state: BeaconState, request: BuilderDepositRequest) -> None:
1777+
# Ignore deposits with unexpected withdrawal credential prefixes
1778+
if not is_builder_withdrawal_credential(request.withdrawal_credentials):
1779+
return
1780+
17771781
builder_pubkeys = [b.pubkey for b in state.builders]
17781782
if request.pubkey not in builder_pubkeys:
17791783
if is_valid_builder_deposit_signature(request):
17801784
add_builder_to_registry(
17811785
state,
17821786
request.pubkey,
1783-
uint8(request.withdrawal_credentials[0]),
1787+
PAYLOAD_BUILDER_VERSION,
17841788
ExecutionAddress(request.withdrawal_credentials[12:]),
17851789
request.amount,
17861790
state.slot,

specs/gloas/builder.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,15 @@ must include:
4343

4444
- `pubkey`: The builder's BLS public key.
4545
- `withdrawal_credentials`: The withdrawal credentials, where the first byte is
46-
the builder version and the last 20 bytes are the execution-layer address that
47-
will receive withdrawals. For the version, execution payload builders should
48-
use `PAYLOAD_BUILDER_VERSION`.
46+
`BUILDER_WITHDRAWAL_PREFIX` and the last 20 bytes are the execution-layer
47+
address that will receive withdrawals.
4948
- `amount`: At least `MIN_DEPOSIT_AMOUNT` gwei.
5049
- `signature`: BLS proof of possession over the corresponding `DepositMessage`
5150
under `DOMAIN_BUILDER_DEPOSIT`.
5251

52+
*Note*: A builder deposit request with withdrawal credentials that do not start
53+
with `BUILDER_WITHDRAWAL_PREFIX` will be ignored and the funds will be lost.
54+
5355
*Note*: Builders may be onboarded at the fork by submitting a deposit to the
5456
validator deposit contract with a `BUILDER_WITHDRAWAL_PREFIX` withdrawal
5557
credential. This must be done late enough that the deposit is still pending at

tests/core/pyspec/eth_consensus_specs/test/gloas/block_processing/test_process_builder_deposit_request.py

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,14 @@ def test_process_builder_deposit_request__new_builder(spec, state):
8080

8181
@with_gloas_and_later
8282
@spec_state_test
83-
def test_process_builder_deposit_request__new_builder_nonzero_version(spec, state):
83+
def test_process_builder_deposit_request__new_builder_non_builder_withdrawal_prefix(spec, state):
8484
"""
85-
Test fresh builder deposit with a non-zero version.
85+
Test fresh builder deposit with a non-builder withdrawal prefix.
8686
87-
The version (the first byte of the withdrawal credentials) is not
88-
constrained: it is recorded on the builder verbatim and is committed to by
89-
the proof of possession.
87+
Gloas drops new builder deposits that do not use BUILDER_WITHDRAWAL_PREFIX.
9088
"""
9189
amount = spec.MIN_DEPOSIT_AMOUNT
92-
version = spec.uint8(7)
93-
withdrawal_credentials = bytes([version]) + b"\x00" * 11 + b"\x42" * 20
90+
withdrawal_credentials = b"\x01" + b"\x00" * 11 + b"\x42" * 20
9491
builder_deposit_request = prepare_builder_deposit_request(
9592
spec, state, amount, withdrawal_credentials=withdrawal_credentials, signed=True
9693
)
@@ -103,16 +100,9 @@ def test_process_builder_deposit_request__new_builder_nonzero_version(spec, stat
103100
state,
104101
pre_state,
105102
builder_deposit_request=builder_deposit_request,
106-
expected_builder_balance=amount,
107-
expected_execution_address=spec.ExecutionAddress(
108-
builder_deposit_request.withdrawal_credentials[12:]
109-
),
110-
expected_builder_withdrawable_epoch=spec.FAR_FUTURE_EPOCH,
103+
state_unchanged=True,
111104
)
112105

113-
builder_index = [b.pubkey for b in state.builders].index(builder_deposit_request.pubkey)
114-
assert state.builders[builder_index].version == version
115-
116106

117107
@with_gloas_and_later
118108
@spec_state_test
@@ -403,16 +393,16 @@ def test_process_builder_deposit_request__top_up_last_index(spec, state):
403393
@spec_state_test
404394
def test_process_builder_deposit_request__top_up_ignores_request_fields(spec, state):
405395
"""
406-
Test that a top-up for an existing builder ignores the supplied withdrawal
407-
credentials. The existing registration is unchanged.
396+
Test that a top-up for an existing builder ignores the supplied execution
397+
address. The existing registration is unchanged.
408398
"""
409399
builder_pubkey = state.builders[0].pubkey
410400
amount = spec.MIN_DEPOSIT_AMOUNT
411401
pre_balance = state.builders[0].balance
412402
pre_builder_count = len(state.builders)
413403

414404
# Use withdrawal credentials that differ from the registration
415-
withdrawal_credentials = b"\x07" + b"\x00" * 11 + b"\x42" * 20
405+
withdrawal_credentials = spec.BUILDER_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x42" * 20
416406
assert state.builders[0].version != spec.uint8(withdrawal_credentials[0])
417407
assert state.builders[0].execution_address != spec.ExecutionAddress(withdrawal_credentials[12:])
418408

@@ -441,6 +431,34 @@ def test_process_builder_deposit_request__top_up_ignores_request_fields(spec, st
441431
assert state.builders[0].execution_address == pre_state.builders[0].execution_address
442432

443433

434+
@with_gloas_and_later
435+
@spec_state_test
436+
def test_process_builder_deposit_request__top_up_non_builder_withdrawal_prefix(spec, state):
437+
"""Test that top-ups with a non-builder withdrawal prefix are ignored."""
438+
builder_pubkey = state.builders[0].pubkey
439+
amount = spec.MIN_DEPOSIT_AMOUNT
440+
withdrawal_credentials = b"\x01" + b"\x00" * 11 + b"\x42" * 20
441+
builder_deposit_request = prepare_builder_deposit_request(
442+
spec,
443+
state,
444+
amount,
445+
pubkey=builder_pubkey,
446+
withdrawal_credentials=withdrawal_credentials,
447+
signed=True,
448+
)
449+
pre_state = state.copy()
450+
451+
yield from run_builder_deposit_request_processing(spec, state, builder_deposit_request)
452+
453+
assert_process_builder_deposit_request(
454+
spec,
455+
state,
456+
pre_state,
457+
builder_deposit_request=builder_deposit_request,
458+
state_unchanged=True,
459+
)
460+
461+
444462
#
445463
# Invalid deposits
446464
#

tests/core/pyspec/eth_consensus_specs/test/helpers/builder_deposit_requests.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ def prepare_process_builder_deposit_request(
4242
builder_index: Index for builder pubkey lookup. Default: len(state.builders)
4343
(a new builder).
4444
pubkey: Explicit BLSPubkey. Default: derived from builder_index.
45-
withdrawal_credentials: Explicit Bytes32 credentials. Default: version zero
46-
followed by an eth1 address derived from the pubkey.
45+
withdrawal_credentials: Explicit Bytes32 credentials. Default:
46+
BUILDER_WITHDRAWAL_PREFIX followed by an eth1 address derived from the pubkey.
4747
amount: Deposit amount in Gwei. Default: MIN_ACTIVATION_BALANCE.
4848
signed: If True, sign with a valid builder deposit signature.
4949
builders: Override state.builders list entirely. Use [] for empty registry.
@@ -70,8 +70,10 @@ def prepare_process_builder_deposit_request(
7070
if withdrawal_credentials is not None:
7171
effective_withdrawal_credentials = withdrawal_credentials
7272
else:
73-
# Version zero followed by an eth1 address derived from the pubkey
74-
effective_withdrawal_credentials = b"\x00" * 12 + spec.hash(effective_pubkey)[12:]
73+
# Builder withdrawal prefix followed by an eth1 address derived from the pubkey
74+
effective_withdrawal_credentials = (
75+
spec.BUILDER_WITHDRAWAL_PREFIX + b"\x00" * 11 + spec.hash(effective_pubkey)[12:]
76+
)
7577

7678
# Phase 3: Apply state overrides (before creating request)
7779
if builders is not None:

tests/core/pyspec/eth_consensus_specs/test/helpers/deposits.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,10 @@ def prepare_builder_deposit_request(
280280
privkey = builder_pubkey_to_privkey[pubkey]
281281

282282
if withdrawal_credentials is None:
283-
# Version zero followed by an eth1 address derived from the pubkey
284-
withdrawal_credentials = b"\x00" * 12 + spec.hash(pubkey)[12:]
283+
# Builder withdrawal prefix followed by an eth1 address derived from the pubkey
284+
withdrawal_credentials = (
285+
spec.BUILDER_WITHDRAWAL_PREFIX + b"\x00" * 11 + spec.hash(pubkey)[12:]
286+
)
285287

286288
request = spec.BuilderDepositRequest(
287289
pubkey=pubkey,

0 commit comments

Comments
 (0)