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
7 changes: 5 additions & 2 deletions specs/gloas/builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,11 @@ to include. They produce a `SignedExecutionPayloadBid` as follows.
`get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`,
where `parent_state` is the post-state of `bid.parent_block_root`.
07. Set `bid.gas_limit` to be the gas limit of the constructed payload, which
must match the `gas_limit` in the `SignedProposerPreferences` referenced in
step 6.
**MUST** satisfy
`is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, target_gas_limit)`,
where `parent_gas_limit` is the `gas_limit` of the parent execution payload
and `target_gas_limit` is the `target_gas_limit` in the
`SignedProposerPreferences` referenced in step 6.
08. Set `bid.builder_index` to be the index of the builder performing these
actions.
09. Set `bid.slot` to be the slot for which this bid is aimed. This slot
Expand Down
1 change: 1 addition & 0 deletions specs/gloas/fork.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def upgrade_to_gloas(pre: fulu.BeaconState) -> BeaconState:
# [New in Gloas:EIP7732]
latest_execution_payload_bid=ExecutionPayloadBid(
block_hash=pre.latest_execution_payload_header.block_hash,
gas_limit=pre.latest_execution_payload_header.gas_limit,
execution_requests_root=hash_tree_root(ExecutionRequests()),
),
# [New in Gloas:EIP7732]
Expand Down
29 changes: 25 additions & 4 deletions specs/gloas/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class ProposerPreferences(Container):
proposal_slot: Slot
validator_index: ValidatorIndex
fee_recipient: ExecutionAddress
gas_limit: uint64
target_gas_limit: uint64
```

#### New `SignedProposerPreferences`
Expand Down Expand Up @@ -347,7 +347,6 @@ where `parent_state` is the post-state of `bid.parent_block_root`, and the alias
`is_active_builder(state, bid.builder_index)` returns `True`.
- _[REJECT]_ `bid.execution_payment == 0`.
- _[REJECT]_ `bid.fee_recipient == proposer_preferences.fee_recipient`.
- _[REJECT]_ `bid.gas_limit == proposer_preferences.gas_limit`.
- _[REJECT]_ The length of KZG commitments is less than or equal to the
limitation defined in the consensus layer -- i.e. validate that
`len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
Expand All @@ -358,12 +357,34 @@ where `parent_state` is the post-state of `bid.parent_block_root`, and the alias
- _[IGNORE]_ `bid.value` is less or equal than the builder's excess balance --
i.e. `can_builder_cover_bid(state, builder_index, amount)` returns `True`.
- _[IGNORE]_ `bid.parent_block_hash` is the block hash of a known execution
payload in fork choice.
payload in fork choice and
`is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, proposer_preferences.target_gas_limit)`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just realized this but shouldn't this be a REJECT if is_gas_limit_target_compatible = False? we do the same if fee recipient is incorrect, wondering if we used IGNORE just because it's combined with "known execution payload in fork choice" condition

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it should. Can you open a PR for this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is `True` where `parent_gas_limit` is the `gas_limit` of that execution
payload.
- _[IGNORE]_ `bid.parent_block_root` is the hash tree root of a known beacon
block in fork choice.
- _[REJECT]_ `signed_execution_payload_bid.signature` is valid with respect to
the `bid.builder_index`.

```python
def is_gas_limit_target_compatible(
parent_gas_limit: uint64, gas_limit: uint64, target_gas_limit: uint64
) -> bool:
"""
Check if ``gas_limit`` is compatible with ``target_gas_limit`` under the
EIP-1559 transition rule from ``parent_gas_limit``.
"""
max_gas_limit_difference = max(parent_gas_limit // 1024, 1) - 1
min_gas_limit = parent_gas_limit - max_gas_limit_difference

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have to worry about overflow here? What if parent_gas_limit is really small (or 0, as we encountered at default Gloas genesis).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually nvm, it's fine because of how max_gas_limit_difference is calculated (parent_gas_limit <= 1024 implies max_gas_limit_difference == 0).

max_gas_limit = parent_gas_limit + max_gas_limit_difference

if target_gas_limit >= min_gas_limit and target_gas_limit <= max_gas_limit:
return gas_limit == target_gas_limit
if target_gas_limit > max_gas_limit:
return gas_limit == max_gas_limit
return gas_limit == min_gas_limit
Comment thread
jtraglia marked this conversation as resolved.
```

*Note*: Implementations SHOULD include DoS prevention measures to mitigate spam
from malicious builders submitting numerous bids with minimal value increments.
Possible strategies include: (1) only forwarding bids that exceed the current
Expand All @@ -376,7 +397,7 @@ bid at regular time intervals.

This topic is used to propagate signed proposer preferences as
`SignedProposerPreferences`. These messages allow validators to communicate
their preferred `fee_recipient` and `gas_limit` to builders.
their preferred `fee_recipient` and `target_gas_limit` to builders.

The following validations MUST pass before forwarding the
`signed_proposer_preferences` on the network, assuming the alias
Expand Down
10 changes: 5 additions & 5 deletions specs/gloas/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ A validator MAY broadcast `SignedProposerPreferences` messages to the
`get_upcoming_proposal_slots(state, validator_index)`. These include any future
proposal slots within the proposer lookahead, i.e. the current epoch up to
`MIN_SEED_LOOKAHEAD` epochs ahead. This allows builders to construct execution
payloads with the validator's preferred `fee_recipient` and `gas_limit`. If a
validator does not broadcast a `SignedProposerPreferences` message, this implies
that the validator will not accept any trustless bids for that slot.
payloads with the validator's preferred `fee_recipient` and `target_gas_limit`.
If a validator does not broadcast a `SignedProposerPreferences` message, this
implies that the validator will not accept any trustless bids for that slot.

```python
def get_upcoming_proposal_slots(
Expand Down Expand Up @@ -162,8 +162,8 @@ To construct each `SignedProposerPreferences`:
4. Set `preferences.validator_index` to the validator's index.
5. Set `preferences.fee_recipient` to the execution address where the validator
wishes to receive the builder payment.
6. Set `preferences.gas_limit` to the validator's preferred gas limit for this
execution payload.
6. Set `preferences.target_gas_limit` to the validator's preferred gas limit for
this execution payload.
7. Instantiate a new `SignedProposerPreferences` object as `signed_preferences`.
8. Set `signed_preferences.message` to `preferences`.
9. Set `signed_preferences.signature` to the result of
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from eth_consensus_specs.test.context import (
single_phase,
spec_test,
with_gloas_and_later,
)


@with_gloas_and_later
@spec_test
@single_phase
def test_increase_within_limit(spec):
assert spec.is_gas_limit_target_compatible(60_000_000, 60_000_100, 60_000_100)


@with_gloas_and_later
@spec_test
@single_phase
def test_increase_exceeding_limit(spec):
# max_gas_limit_difference = 60_000_000 // 1024 - 1 = 58_592
assert spec.is_gas_limit_target_compatible(60_000_000, 60_058_592, 100_000_000)


@with_gloas_and_later
@spec_test
@single_phase
def test_increase_exceeding_limit_off_by_one_fails(spec):
# gas_limit one above max_gas_limit (= 60_058_592) must fail (off by one)
assert not spec.is_gas_limit_target_compatible(60_000_000, 60_058_593, 100_000_000)


@with_gloas_and_later
@spec_test
@single_phase
def test_decrease_within_limit(spec):
assert spec.is_gas_limit_target_compatible(60_000_000, 59_999_990, 59_999_990)


@with_gloas_and_later
@spec_test
@single_phase
def test_decrease_exceeding_limit(spec):
# max_gas_limit_difference = 60_000_000 // 1024 - 1 = 58_592
assert spec.is_gas_limit_target_compatible(60_000_000, 59_941_408, 30_000_000)


@with_gloas_and_later
@spec_test
@single_phase
def test_target_equals_parent(spec):
assert spec.is_gas_limit_target_compatible(60_000_000, 60_000_000, 60_000_000)


@with_gloas_and_later
@spec_test
@single_phase
def test_parent_gas_limit_underflows(spec):
# parent_gas_limit // 1024 = 0; guard clamps to max(0, 1) - 1 = 0 (no underflow)
assert spec.is_gas_limit_target_compatible(1023, 1023, 60_000_000)