-
Notifications
You must be signed in to change notification settings - Fork 386
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
engine: Make execution requests a sidecar, take 2 #591
Conversation
I love the idea of removing the requests from EL block. We should keep iterating on that. However, when it comes to the Engine API definition, I think we should consider an approach where we send a list of opaque representations of the requests (like an array of byte arrays), similar to what was proposed here. This approach has the following benefits:
The requirements for that approach are:
|
After a fruitful discussion with @lucassaldanha I have updated the PR and its description with the design we came up to. The final design we propose stems from removing requests from EL block and passing them as a sidecar to the payload and leverages on the requests encoding proposed in #565 |
A thought after the ACDE call: we can use |
I think it's better to use the flat |
Here is the update to the system contracts (WIP): lightclient/sys-asm#22 |
Just for the sake of my own understanding, we expect to always (in Prague that is) see a list here with three elements (one for each request type) every block and independent of whether there are requests of a given type or not, is that correct? E.g. [
"0x00... 00... 00...", # Three deposits here
"0x", # No withdrawals
"0x02..." # One consolidation
] (So not exactly as #577 because to separate each request into a new array element we would need to parse the contract response) Edit: I just saw fjl comment about how single flat data is better, I'll wait until this is settled before updating the tests. |
Co-authored-by: Mario Vega <[email protected]>
EL would not have to parse data to serve request lists separately. Each list is obtained from the corresponding smart contract and then concatenated into a single flat list to compute the Obviously, (a) is better from EL perspective, while option (b) isn’t something complicated to do either. So, I would like to hear from CL client devs on that |
I significantly prefer (b). The only specific utility of the flat list is for hashing, and that can be done by |
I agree, I'm even less inclined to a single flat byte string now. Another advantage of three-element list (or N element for future forks) is that you can modulo the length of each element in the list against the length of a single request for the given type and immediately validate it has the correct size. We could even skip the request-type byte at the beginning of every request this way. |
I think it's better to serve the requests as a single flat byte array because that is also how they will be hashed to create the So I think we should relay the requests to the CL as the byte array |
I agree that it is a bit simpler to hash on a flat array but having a list of byte arrays you only need to do two byte array concatenations (or |
Yes I understand. But there is another benefit to the flat array, and it has to do with abstraction. At the moment, we are focused on the three request types coming out of three distinct contract invocations. However, this may not always be the case in the future. We could later decide that the withdrawal request queue logic should be changed and have a more complex behavior. We can't change the contract, but we could just add another system contract then and make it output the same withdrawal events. Or we could have a future system contract that outputs multiple kinds of events. For this reason, I strongly believe we should go with the flat byte array returning the contracts return data as-is. It removes the need for the EL to know anything about the output, and it allows the CL to be ignorant about the source of the requests. We should probably also remove the type-ordering requirement in CL validation. The only thing we really need to specify is the system contract call order for the EL. |
Also prefer (b), but I kinda understand the motivation for a flat list. If we are going with (b), the spec should be clear on the validity of ordering within the flat list. Should we expect the EL to return an ordered by type flat list? For e.g. if we receive [D1 , W1 ,D2, C1 , W2 ], should we
(3) doesn't make sense to me, I'm unclear if we should do (1) or (2) |
I updated the PR to send |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
fbb5de1
to
295e05b
Compare
295e05b
to
48de028
Compare
Requests to be removed from body and put into Engine-API sidecar Ref: ethereum/execution-apis#591 Issue board: #12106
Summary of changes - Remove `Requests` interface in favour of new `FlatRequest` struct - Add changes for new `RequestHash` calculation that `sha256` digests the set of flat requests - Remove `Requests` from block and body related structs and methods - Set of requests that gets pulled at the `Finalize` stage is now returned from there, both for execution and block-building Ref1: ethereum/execution-apis#591 Ref2: ethereum/EIPs#8854 Ref3: ethereum/EIPs#8924 Needs interface change - erigontech/interfaces#239 (Tasks board - #12106)
Alternative to:
Proposal
requestsRoot
commitment in the EL block header, originates from engine: Return and accept EL triggered requests as a sidecar #551 and engine: Return and accept EL triggered requests as a sidecar #551 (comment)getPayload
andnewPayload
as a sidecar using byte sequence representation similar to engine: unify request objects #565requestsHash
as a part ofblockHash
validation, note there is no need to keeprequests_hash
in the beacon block. CLs that runblockHash
validation on their own will still be able to do that by implementing the algo EL uses to computerequestsHash
requestsHash
in the EL block header against requests obtained from transaction executionrequests_01 = withdrawalContract.sysCall(), requests_02 = consolidationContract.sysCall()
; deposit contract will always be an exceptionexecutionRequests = requests_00 || requests_01 || requests_02
instead ofrequests = RLP([requests_00, requests_01, requests_02])
. And use theexecutionRequests
in Engine API and inrequestsHash
computation, the latter can be as simple asrequestsHash = executionRequests(requests)
Properties
blockHash
validation ensures that the beacon block contains requests that EL payload is committed to and then, upon executing a block, EL ensures that the same commitment corresponds to the requests obtained from transaction execution. These two steps ensure that either requests in the beacon block are the same as those produced by the transaction execution or the payload isINVALID
ToDo
requestsHash
computation