Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
14 changes: 9 additions & 5 deletions specs/gloas/builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,15 @@ to include. They produce a `SignedExecutionPayloadBid` as follows.
05. Set `bid.prev_randao` to be the previous RANDAO of the constructed payload,
that is `payload.prev_randao`.
06. Set `bid.fee_recipient` to be an execution address to receive the payment.
The proposer's preferred fee recipient can be obtained from the
`SignedProposerPreferences` associated with `bid.slot`.
07. Set `bid.gas_limit` to be the gas limit of the constructed payload. The
proposer's preferred gas limit can be obtained from the
`SignedProposerPreferences` associated with `bid.slot`.
The proposer's preferred fee recipient is obtained from the
`SignedProposerPreferences` whose `message.proposal_slot == bid.slot` and
whose `message.checkpoint_root` equals
`get_checkpoint_block(store, bid.parent_block_root, compute_epoch_at_slot(bid.slot) - 1)`.
Builders that cannot find a matching `SignedProposerPreferences` MUST NOT
broadcast the bid.
07. Set `bid.gas_limit` to be the gas limit of the constructed payload, which
must match the `gas_limit` in the same `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
50 changes: 27 additions & 23 deletions specs/gloas/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,16 @@ class PartialDataColumnGroupID(Container):

```python
class ProposerPreferences(Container):
checkpoint_root: Root
proposal_slot: Slot
validator_index: ValidatorIndex
fee_recipient: ExecutionAddress
gas_limit: uint64
```

The `checkpoint_root` is
`get_checkpoint_block(store, head_root, compute_epoch_at_slot(proposal_slot) - 1)`.

#### New `SignedProposerPreferences`

*[New in Gloas:EIP7732]*
Expand Down Expand Up @@ -355,18 +359,19 @@ This topic is used to propagate signed bids as `SignedExecutionPayloadBid`.

The following validations MUST pass before forwarding the
`signed_execution_payload_bid` on the network, assuming the alias
`bid = signed_execution_payload_bid.message`:
`bid = signed_execution_payload_bid.message` and the alias
`proposer_preferences` for the validated `SignedProposerPreferences` whose
`message.proposal_slot == bid.slot` and
`message.checkpoint_root == get_checkpoint_block(store, bid.parent_block_root, compute_epoch_at_slot(bid.slot) - 1)`:

- _[IGNORE]_ `bid.slot` is the current slot or the next slot.
- _[IGNORE]_ the `SignedProposerPreferences` where `preferences.proposal_slot`
is equal to `bid.slot` has been seen.
- _[IGNORE]_ `proposer_preferences` is defined (i.e. a matching
`SignedProposerPreferences` has been seen).
- _[REJECT]_ `bid.builder_index` is a valid/active builder index -- i.e.
`is_active_builder(state, bid.builder_index)` returns `True`.
- _[REJECT]_ `bid.execution_payment` is zero.
- _[REJECT]_ `bid.fee_recipient` matches the `fee_recipient` from the proposer's
`SignedProposerPreferences` associated with `bid.slot`.
- _[REJECT]_ `bid.gas_limit` matches the `gas_limit` from the proposer's
`SignedProposerPreferences` associated with `bid.slot`.
- _[REJECT]_ `bid.fee_recipient == proposer_preferences.message.fee_recipient`.
- _[REJECT]_ `bid.gas_limit == proposer_preferences.message.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 Down Expand Up @@ -403,33 +408,32 @@ The following validations MUST pass before forwarding the

- _[IGNORE]_ `preferences.proposal_slot` is in the current or next epoch -- i.e.
`compute_epoch_at_slot(preferences.proposal_slot)` is in
`[get_current_epoch(state), get_current_epoch(state) + 1]`.
`[compute_epoch_at_slot(current_slot), compute_epoch_at_slot(current_slot) + 1]`.
- _[IGNORE]_ `preferences.proposal_slot` has not already passed -- i.e.
`preferences.proposal_slot > state.slot`.
- _[IGNORE]_ `preferences.validator_index` is present at the correct slot in the
current or next epoch's portion of `state.proposer_lookahead` -- i.e.
`is_valid_proposal_slot(state, preferences)` returns `True`.
- _[IGNORE]_ The `signed_proposer_preferences` is the first valid message
received from the validator with index `preferences.validator_index` and the
given slot `preferences.proposal_slot`.
`preferences.proposal_slot > current_slot`.
Comment thread
nflaig marked this conversation as resolved.
Resolved
- _[IGNORE]_ The block with root `preferences.checkpoint_root` is unknown to the
node. Implementations MAY queue the message for re-processing once the block
becomes known.
- _[REJECT]_ `is_valid_proposal_slot(state, preferences)` returns `False`, where
`state` is the checkpoint state at
`(compute_epoch_at_slot(preferences.proposal_slot) - 1, preferences.checkpoint_root)`.
- _[IGNORE]_ The `signed_proposer_preferences` is the first valid message seen
for the tuple
`(preferences.checkpoint_root, preferences.proposal_slot, preferences.validator_index)`.
- _[REJECT]_ `signed_proposer_preferences.signature` is valid with respect to
the validator's public key.

```python
def is_valid_proposal_slot(state: BeaconState, preferences: ProposerPreferences) -> bool:
"""
Check if the validator is the proposer for the given slot in the current or
next epoch.
Check if the validator is the proposer for the given slot using the
checkpoint ``state`` identified by ``preferences.checkpoint_root``.
"""
current_epoch = get_current_epoch(state)
proposal_epoch = compute_epoch_at_slot(preferences.proposal_slot)
if proposal_epoch < current_epoch:
return False
if proposal_epoch > current_epoch + Epoch(1):
if get_current_epoch(state) != proposal_epoch - Epoch(1):
return False

index = (proposal_epoch - current_epoch) * SLOTS_PER_EPOCH
index += preferences.proposal_slot % SLOTS_PER_EPOCH
index = SLOTS_PER_EPOCH + preferences.proposal_slot % SLOTS_PER_EPOCH
return state.proposer_lookahead[index] == preferences.validator_index
```

Expand Down
17 changes: 10 additions & 7 deletions specs/gloas/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,18 @@ def get_upcoming_proposal_slots(
To construct each `SignedProposerPreferences`:

1. Instantiate a new `ProposerPreferences` object as `preferences`.
2. Set `preferences.proposal_slot` to `upcoming_proposal_slots[i]`.
3. Set `preferences.validator_index` to the validator's index.
4. Set `preferences.fee_recipient` to the execution address where the validator
2. Set `preferences.checkpoint_root` to
`get_checkpoint_block(store, head_root, compute_epoch_at_slot(preferences.proposal_slot) - 1)`,
where `head_root` is the proposer's current head.
3. Set `preferences.proposal_slot` to `upcoming_proposal_slots[i]`.
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.
5. Set `preferences.gas_limit` to the validator's preferred gas limit for this
6. Set `preferences.gas_limit` to the validator's preferred gas limit for this
execution payload.
6. Instantiate a new `SignedProposerPreferences` object as `signed_preferences`.
7. Set `signed_preferences.message` to `preferences`.
8. Set `signed_preferences.signature` to the result of
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
`get_proposer_preferences_signature(state, preferences, privkey)`.

```python
Expand Down