Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EIP-7805 (FOCIL) specs #4003

Open
wants to merge 48 commits into
base: dev
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
3a16a0e
Add focil containers
terencechain Sep 11, 2024
fa27c8f
Add process inclusion list aggregate
terencechain Sep 12, 2024
3c86963
Add inclusion list gossip conditions
terencechain Sep 14, 2024
8a1e940
Add execution api
terencechain Sep 15, 2024
833be94
Add validator spec
terencechain Sep 16, 2024
a2b68a7
Review feedback
terencechain Sep 17, 2024
fb4a3c3
Update forkchoice
terencechain Sep 17, 2024
c7a056b
Update based on latest discussion. No more IL aggregate
terencechain Sep 21, 2024
f84556c
Update fork-choice.md
terencechain Sep 26, 2024
2787b0d
Update per https://ethresear.ch/t/focil-cl-el-workflow/20526
terencechain Sep 30, 2024
0b09f96
Address feedback
terencechain Oct 2, 2024
6056b69
Clarify forkchoice and p2p
terencechain Oct 12, 2024
a8aec7c
Remove local
terencechain Oct 17, 2024
cbe6129
suggested changes
fradamt Oct 22, 2024
0efcf13
Merge pull request #5 from fradamt/focil-patch
terencechain Oct 22, 2024
f151c7c
replace parent_root with il_committee_root
fradamt Oct 22, 2024
b181655
add timing logic (deaadlines) to IL processing
fradamt Oct 23, 2024
0681f8c
missing :
fradamt Oct 25, 2024
2861684
Merge pull request #6 from fradamt/focil-patch
terencechain Oct 29, 2024
e678deb
Use eip7805
terencechain Nov 4, 2024
e9fdfc6
@jtraglia's suggestions
terencechain Nov 8, 2024
6ce0077
Update new inclusion list comments
terencechain Nov 19, 2024
be471b8
P2p spec feedbacks
terencechain Nov 19, 2024
c443db0
Add get attester head
terencechain Nov 19, 2024
c8b6296
Fix typo and make CI happy
hwwhww Dec 2, 2024
7fa44f4
fix byte limit check
fradamt Dec 16, 2024
84acfbb
ensure valid committee with <16 validators
nerolation Dec 30, 2024
702b9e5
Merge pull request #7 from nerolation/patch-1
terencechain Jan 2, 2025
561aed7
Merge branch 'dev' into focil-consensus
jtraglia Jan 14, 2025
c762a33
Add eip7805 to list of executable specs
jtraglia Jan 14, 2025
20b0c50
Fix simple linter warnings
jtraglia Jan 14, 2025
aca38ea
Fix some more linter issues
jtraglia Jan 14, 2025
1c6761a
Add execution_requests_list to notify_new_payload
jtraglia Jan 14, 2025
d63042e
Fix things regarding engine API
jtraglia Jan 14, 2025
86c86d0
Update eth2spec before linting
jtraglia Jan 14, 2025
7d8e6fb
Expand acronym in DOMAIN_IL_COMMITTEE and IL_COMMITTEE_SIZE
jtraglia Jan 14, 2025
19b50a6
Rename il_transactions to inclusion_list_transactions
jtraglia Jan 14, 2025
f25efbf
Change engine API param type to Sequence[Transaction]
jtraglia Jan 14, 2025
5a37c91
Fix various nits
jtraglia Jan 14, 2025
c411d45
Replace "since" with "up to"
jtraglia Jan 14, 2025
dcd31d6
Pull in electra's changes to verify_and_notify_new_payload
jtraglia Jan 14, 2025
3652904
Change inclusion_list_transactions to a Sequence
jtraglia Jan 15, 2025
2781459
Make some improvements to fork-choice doc
jtraglia Jan 15, 2025
7a2cb7a
Make time params work with minimal
jtraglia Jan 24, 2025
91054e6
Fix networking toc
jtraglia Jan 24, 2025
23e33cc
Update get proposer head for FOCIL
terencechain Jan 30, 2025
5be24fc
Merge pull request #8 from terencechain/focil-get-proposer-head
terencechain Jan 31, 2025
984be8a
Fix else indentation
jtraglia Feb 6, 2025
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
Prev Previous commit
Next Next commit
Fix things regarding engine API
jtraglia committed Jan 14, 2025
commit d63042ef8c3015f60697821869701401593a420c
41 changes: 41 additions & 0 deletions pysetup/spec_builders/eip7805.py
Original file line number Diff line number Diff line change
@@ -4,3 +4,44 @@

class EIP7805SpecBuilder(BaseSpecBuilder):
fork: str = EIP7805


@classmethod
def execution_engine_cls(cls) -> str:
return """
class NoopExecutionEngine(ExecutionEngine):

def notify_new_payload(self: ExecutionEngine,
execution_payload: ExecutionPayload,
parent_beacon_block_root: Root,
execution_requests_list: Sequence[bytes],
il_transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST]) -> bool:
return True

def notify_forkchoice_updated(self: ExecutionEngine,
head_block_hash: Hash32,
safe_block_hash: Hash32,
finalized_block_hash: Hash32,
payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]:
pass

def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadResponse:
# pylint: disable=unused-argument
raise NotImplementedError("no default block production")

def is_valid_block_hash(self: ExecutionEngine,
execution_payload: ExecutionPayload,
parent_beacon_block_root: Root,
execution_requests_list: Sequence[bytes],
il_transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST]) -> bool:
return True

def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool:
return True

def verify_and_notify_new_payload(self: ExecutionEngine,
new_payload_request: NewPayloadRequest) -> bool:
return True


EXECUTION_ENGINE = NoopExecutionEngine()"""
86 changes: 86 additions & 0 deletions specs/_features/eip7805/beacon-chain.md
Original file line number Diff line number Diff line change
@@ -24,7 +24,10 @@
- [Request data](#request-data)
- [Modified `NewPayloadRequest`](#modified-newpayloadrequest)
- [Engine APIs](#engine-apis)
- [Modified `is_valid_block_hash`](#modified-is_valid_block_hash)
- [Modified `notify_new_payload`](#modified-notify_new_payload)
- [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload)
- [Modified `process_execution_payload`](#modified-process_execution_payload)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
@@ -134,6 +137,42 @@ class NewPayloadRequest(object):

#### Engine APIs

##### Modified `is_valid_block_hash`

*Note*: The function `is_valid_block_hash` is modified to include the additional `il_transactions`.

```python
def is_valid_block_hash(self: ExecutionEngine,
execution_payload: ExecutionPayload,
parent_beacon_block_root: Root,
execution_requests_list: Sequence[bytes],
il_transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST]) -> bool:
"""
Return ``True`` if and only if ``execution_payload.block_hash`` is computed correctly.
"""
...
```

##### Modified `notify_new_payload`

*Note*: The function `notify_new_payload` is modified to include the additional `il_transactions`.

```python
def notify_new_payload(self: ExecutionEngine,
execution_payload: ExecutionPayload,
parent_beacon_block_root: Root,
execution_requests_list: Sequence[bytes],
il_transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST]) -> bool:
"""
Return ``True`` if and only if ``execution_payload`` and ``execution_requests_list``
are valid with respect to ``self.execution_state``.
"""
# TODO: move this outside of notify_new_payload.
# If execution client returns block does not satisfy inclusion list transactions, cache the block
# store.unsatisfied_inclusion_list_blocks.add(execution_payload.block_root)
...
```

##### Modified `verify_and_notify_new_payload`

*Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameter `il_transactions`
@@ -166,3 +205,50 @@ def verify_and_notify_new_payload(self: ExecutionEngine,

return True
```

##### Modified `process_execution_payload`

```python
def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None:
payload = body.execution_payload

# Verify consistency of the parent hash with respect to the previous execution payload header
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
# Verify prev_randao
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
# Verify timestamp
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
# Verify commitments are under limit
assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_ELECTRA
# Verify the execution payload is valid
versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments]
assert execution_engine.verify_and_notify_new_payload(
NewPayloadRequest(
execution_payload=payload,
versioned_hashes=versioned_hashes,
parent_beacon_block_root=state.latest_block_header.parent_root,
execution_requests=body.execution_requests,
il_transactions=[], # TODO: where do we get this?
)
)
# Cache execution payload header
state.latest_execution_payload_header = ExecutionPayloadHeader(
parent_hash=payload.parent_hash,
fee_recipient=payload.fee_recipient,
state_root=payload.state_root,
receipts_root=payload.receipts_root,
logs_bloom=payload.logs_bloom,
prev_randao=payload.prev_randao,
block_number=payload.block_number,
gas_limit=payload.gas_limit,
gas_used=payload.gas_used,
timestamp=payload.timestamp,
extra_data=payload.extra_data,
base_fee_per_gas=payload.base_fee_per_gas,
block_hash=payload.block_hash,
transactions_root=hash_tree_root(payload.transactions),
withdrawals_root=hash_tree_root(payload.withdrawals),
blob_gas_used=payload.blob_gas_used,
excess_blob_gas=payload.excess_blob_gas,
)
```
25 changes: 1 addition & 24 deletions specs/_features/eip7805/fork-choice.md
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@
- [Helpers](#helpers)
- [New `validate_inclusion_lists`](#new-validate_inclusion_lists)
- [Modified `Store`](#modified-store)
- [Modified `notify_new_payload`](#modified-notify_new_payload)
- [`get_attester_head`](#get_attester_head)
- [New `on_inclusion_list`](#new-on_inclusion_list)

@@ -70,29 +69,7 @@ class Store(object):
inclusion_lists: Dict[Tuple[Slot, Root], List[InclusionList]] = field(default_factory=dict) # [New in EIP-7805]
# [New in EIP-7805]
inclusion_list_equivocators: Dict[Tuple[Slot, Root], Set[ValidatorIndex]] = field(default_factory=dict)
unsatisfied_inclusion_list_blocks: Set[Root] # [New in EIP-7805]
```

##### Modified `notify_new_payload`

*Note*: The function `notify_new_payload` is modified to include the additional `il_transactions` parameter in EIP-7805.

```python
def notify_new_payload(self: ExecutionEngine,
execution_payload: ExecutionPayload,
execution_requests: ExecutionRequests,
parent_beacon_block_root: Root,
execution_requests_list: Sequence[bytes],
il_transactions: List[Transaction, MAX_TRANSACTIONS_PER_INCLUSION_LIST],
store: Store) -> bool:
"""
Return ``True`` if and only if ``execution_payload`` and ``execution_requests``
are valid with respect to ``self.execution_state``.
"""

# If execution client returns block does not satisfy inclusion list transactions, cache the block
store.unsatisfied_inclusion_list_blocks.add(execution_payload.block_root)
...
unsatisfied_inclusion_list_blocks: Set[Root] = field(default_factory=Set) # [New in EIP-7805]
```

##### `get_attester_head`
6 changes: 3 additions & 3 deletions specs/_features/eip7805/p2p-interface.md
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ This document contains the consensus-layer networking specification for EIP-7805

| Name | Value | Unit | Duration |
| - | - | :-: | :-: |
| `attestation_deadline` | `uint64(4)` | seconds | 4 seconds |
| `ATTESTATION_DEADLINE` | `uint64(4)` | seconds | 4 seconds |
Copy link
Member

Choose a reason for hiding this comment

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

should time parameters be defined as a fraction of SECONDS_PER_SLOT instead, or do we just define them as part of presets to work with minimal as well?

Copy link
Member

Choose a reason for hiding this comment

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

Oh you're right, this wouldn't work with minimal... I'll look into the best way to handle this later.

Copy link
Member

Choose a reason for hiding this comment

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

Is the solution something as simple as this?

Suggested change
| `ATTESTATION_DEADLINE` | `uint64(4)` | seconds | 4 seconds |
| `ATTESTATION_DEADLINE` | `SECONDS_PER_SLOT // 3` | seconds | 4 seconds |

Copy link
Member

Choose a reason for hiding this comment

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

Yes, that would work here. But not for other time values like:

| `PROPOSER_INCLUSION_LIST_CUT_OFF` | `uint64(11)` | seconds | 11 seconds |

Maybe that could be SECONDS_PER_SLOT - 1 instead.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks @bleesherman. I've done just that. Please see: 7a2cb7a

Copy link
Member

Choose a reason for hiding this comment

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

Thinking about this more, not sure if having those values defined in preset will get us where we want as during testing we might use mainnet preset and just reduce seconds per slot. This would also make reducing seconds per slot in the future harder as you need to update a bunch of time parameters. But this might be something to worry about later

Copy link
Member

Choose a reason for hiding this comment

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

To be clear, these are configuration values now. As of that commit I shared.

Copy link
Member

Choose a reason for hiding this comment

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

Might be specific to how we handle this in Lodestar but even if it's part of config we can't derive the value from SECONDS_PER_SLOT

Copy link
Member

Choose a reason for hiding this comment

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

Ah dang. Well I suppose clients could use the values without deriving them.

ATTESTATION_DEADLINE: 4
PROPOSER_INCLUSION_LIST_CUT_OFF: 11
VIEW_FREEZE_DEADLINE: 9

ATTESTATION_DEADLINE: 2
PROPOSER_INCLUSION_LIST_CUT_OFF: 5
VIEW_FREEZE_DEADLINE: 3

Copy link
Member

Choose a reason for hiding this comment

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

Well I suppose clients could use the values without deriving them.

That's what I did for now but will break if we change seconds per slot with mainnet config but it's possible to adapt these values as well now since we have them in config


### Configuration

@@ -50,9 +50,9 @@ The following validations MUST pass before forwarding the `inclusion_list` on th

Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't we also limiting IL size by MAX_BYTES_PER_INCLUSION_LIST = 8192 bytes as indicated in the EIP?

- _[REJECT]_ The size of `message` is within upperbound `MAX_BYTES_PER_INCLUSION_LIST`.
- _[REJECT]_ The slot `message.slot` is equal to the previous or current slot.
- _[IGNORE]_ The slot `message.slot` is equal to the current slot, or it is equal to the previous slot and the current time is less than `attestation_deadline` seconds into the slot.
- _[IGNORE]_ The slot `message.slot` is equal to the current slot, or it is equal to the previous slot and the current time is less than `ATTESTATION_DEADLINE` seconds into the slot.
- _[IGNORE]_ The `inclusion_list_committee` for slot `message.slot` on the current branch corresponds to `message.inclusion_list_committee_root`, as determined by `hash_tree_root(inclusion_list_committee) == message.inclusion_list_committee_root`.
- _[REJECT]_ The validator index `message.validator_index` is within the `inclusion_list_committee` corresponding to `message.inclusion_list_committee_root`.
- _[REJECT]_ The validator index `message.validator_index` is within the `inclusion_list_committee` corresponding to `message.inclusion_list_committee_root`.
- _[REJECT]_ The transactions `message.transactions` length is within upperbound `MAX_TRANSACTIONS_PER_INCLUSION_LIST`.
- _[IGNORE]_ The `message` is either the first or second valid message received from the validator with index `message.validator_index`.
- _[REJECT]_ The signature of `inclusion_list.signature` is valid with respect to the validator index.
3 changes: 1 addition & 2 deletions specs/_features/eip7805/validator.md
Original file line number Diff line number Diff line change
@@ -89,8 +89,7 @@ Proposers are still expected to propose `SignedBeaconBlock` at the beginning of

#### Update execution client with inclusion lists

The proposer should call `engine_updateInclusionListV1` at `PROPOSER_INCLUSION_LIST_CUT_OFF` into the slot with the list of the inclusion lists that gathered since `inclusion_list_CUT_OFF`.

The proposer should call `engine_updateInclusionListV1` at `PROPOSER_INCLUSION_LIST_CUT_OFF` into the slot with the list of the inclusion lists that gathered since `PROPOSER_INCLUSION_LIST_CUT_OFF`.
Copy link
Member

@nflaig nflaig Jan 14, 2025

Choose a reason for hiding this comment

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

@jtraglia shouldn't this say something like "up to" instead of "since"? I think this is related to https://github.com/ethereum/consensus-specs/pull/4003/files#r1912551318, there is no specific time when we start to build the inclusion list as it depends on when the node receives the block or some other cutoff we might wanna define if the block for current slot is late.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, "up to" is correct. Thanks I'll make that change.

And hmm. Would a late block change this? Wouldn't we always build the IL at PROPOSER_INCLUSION_LIST_CUT_OFF (11) seconds into the slot?

Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't we always build the IL at PROPOSER_INCLUSION_LIST_CUT_OFF (11) seconds into the slot?

Yes, the cutoff for the proposer is always the same. The other cutoff I mean is for IL committee members but this one does not matter for the proposer as it would just collect all ILs it received for the slot until PROPOSER_INCLUSION_LIST_CUT_OFF

Copy link
Member

Choose a reason for hiding this comment

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

Ah got it. Well I will leave it to someone else (maybe @terencechain) to clarify.

Choose a reason for hiding this comment

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

To clarify: The proposer cutoff is always the same (11sec), but for IL committee members:

  • They receive a block, and can build their ILs right after they saw it
  • They don't receive a block until 7s, in which case they should run get_head and build and release their ILs based on the node’s local head, so they can propagate their ILs to the rest of the network before their stop doing so (at 8s).

The rest of validators (not the proposer, and not IL committee members) have the freeze deadline cutoff 1sec later, at 9s, at which point they stop storing new ILs.


## New inclusion list committee duty