Skip to content

Add initial FOCIL spec #609

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Add initial FOCIL spec #609

wants to merge 6 commits into from

Conversation

jihoonsong
Copy link

This PR adds initial FOCIL spec. It mainly adds three new methods.

i) engine_newPayloadV5
engine_newPayloadV5 is introduced as engine_newPayloadV4 will be shipped in Prague. engine_newPayloadV5 takes an inclusion list (IL) as a parameter and verifies if the payload satisfies the IL constraints. (For the IL constraints, please refer to Execution Layer section in EIP-7805.)

As IL isn't recorded onchain, it cannot be enforced during syncing. Currently, this spec adopts a naive approach: CL passes IL only when not syncing and EL enforces the IL constraints only if the given IL is not null. We're looking for feedback on whether there is a better approach such as using a sync complete flag.

ii) engine_getInclusionListV1
EL must provide an IL when engine_getInclusionListV1 is called. FOCIL as in EIP-7805 does not dictate IL construction algorithm and expects that having diverse approaches would help foster censorship resistance.

iii) engine_updatePayloadWithInclusionListV1
A proposer should listen to all ILs submitted by IL committee members and apply the aggregated IL to its payload before proposing a block. There are two ways to achieve this.

a) use engine_forkchoiceUpdated
We can add the IL field to payloadAttributes and call forkchoiceUpdated initially with a null IL field at the start of a slot, then call it again with the actual IL once it’s ready.

This will require modifying FCU to allow updates to an ongoing payload building process. If I’m not mistaken, geth and reth currently early return a valid response without updating the existing payload building process.

b) add a new Engine API
The second option is adding a new Engine API. We welcome feedback on better ways of applying IL.

We’re in the early stages of FOCIL implementation and would appreciate your feedback. Thank you.

Copy link
Contributor

@ensi321 ensi321 left a comment

Choose a reason for hiding this comment

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

I think there once was an experimental folder for your purpose but was later removed because the folder is empty.

You can refer to #340 to see how eip6110.md is placed.

@jihoonsong
Copy link
Author

Moved EIP-7805 spec under the experimental folder. Thank you for your review and providing the reference! @ensi321

@jihoonsong
Copy link
Author

I think engine_updatePayloadWithInclusionListV1 should check if current timestamp is equal or later than eip7805 timestamp. As this is a draft, I'll leave this as a comment and would encourage people to revisit this after more core devs onboard.

@GrapeBaBa
Copy link

Will engine_newPayloadV5 change to engine_newPayloadV4 since engine_newPayloadV4 was not shipped in Prague?


#### Response

* result: `inclusionList`: `Array of DATA` - Array of transaction objects, each object is a byte list (`DATA`) representing `TransactionType || TransactionPayload` or `LegacyTransaction` as defined in [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718).
Copy link
Contributor

Choose a reason for hiding this comment

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

We can introduce a response object like it is done in the forkchoiceUpdated case. Should we extend inclusion list with some meta information in the future, it will be smoother with an object in response

Copy link
Author

Choose a reason for hiding this comment

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

We had object for that purpose but removed it as it makes the caller's job easier. I want to ask @terencechain's opinion on this. Relevant discussion here.


#### Request

* method: `engine_updatePayloadWithInclusionListV1`
Copy link
Contributor

Choose a reason for hiding this comment

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

This method is supposed to update the payload build process. The problem with doing it via a separate call can be illustrated as the following:
Suppose IL update and fork choice update are triggered at the same time, two potential outcomes:

  1. IL update is handled first and it gets lost because fork choice update may restart the payload build process, in this case an invalid payload wrt IL can be built
  2. Fork choice update is handled first, then payloadId is no longer valid and IL update fails

For the second case there can be error in the response, so CL will re-send IL information with the new payloadId. For the first case it is up to EL to move the IL information from the old build process to the new one.

To avoid such failure modes IL can be made a part of a payloadAttributes. In this case all the information required for the payload build process will be updated atomically, in the way it is done today. If such approach was under consideration then I am curious why it wasn’t chosen?

Copy link
Author

Choose a reason for hiding this comment

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

This comment is very spot on. I'm gathering feedback on the approach recently that is forkchoiceUpdated vs updatePayloadWithInclusionList.

One thing is that updatePayloadWithInclusionList is called with payloadId and it's supposed to be called after IL view freeze deadline. It makes a pair of calls, which is forkchoiceUpdated followed by updatePayloadWithInclusionList.

For the first case, I think it's implementation dependent. As long as it has the same payloadId, the EL can use ILs that it has been provided. Currently, Geth is implemented in this way.

For the second case, I'm not sure if I understood the scenario. The returned payloadId of forkchoiceUpdated should be fed to updatePayloadWithInclusionList. If the CL calls forkchoiceUpdated with different build params, it will have updatePayloadWithInclusionList with different payloadId. It's just different context.

This may arise a question regarding scope. Some may argue that placing ILs into payloadAttribute could give us a better scope. But another feedback I got is it's not right to overload payloadAttributes as ILs don't participate in choosing a head. I don't have a strong opinion tbh and I do love to have more feedback on this.

Another point I want to share is that the number of ILs is not monotonically increasing. It will decrease when there is any equivocation. So the CL would want to pass the ILs after the view freeze deadline. Of course it won't hurt even if the EL builds payload with equivocated ILs as long as it satisfies non-equivocated ILs.

Copy link
Contributor

@mkalinin mkalinin Jun 19, 2025

Choose a reason for hiding this comment

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

One of the specifics of the fcU call is that it can be called multiple time, each time with different head restarting the build process, then ILs should be moved from one process to another.

payloadAttributes isn't related to the head at all, it keeps information required for the build process only; from this perspective IL should be a part of payloadAttributes too. The thing is that the canonical head state itself is a very important part of the payload build process, this is why fcU has double semantics (fc update that sets the EL into the canonical state + build process trigger).

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for the feedback! When other parameters are not changed, fcU approach consumes a bit more bandwidth than updatePayloadWithInclusionList. Would you say the clarity gained from clearer semantics outweighs this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants