-
Notifications
You must be signed in to change notification settings - Fork 759
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
EIP-7685: Execution Layer Requests Implementation #3372
Conversation
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.
Left some comments. I think we need a sorting mechanism for any EIP which implements this.
For 6110:
Each deposit accumulated in the block must appear in the EIP-7685 requests list in the order they appear in the logs
For 7002:
It should be in the order it is pulled out of the queue (FIFO)
So this is not lexicographic, but in the order of how they are executed or in whatever order they get added to the FIFO queue.
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.
Looks good so far! I got a few comments. I like the tests 👍
packages/block/src/block.ts
Outdated
if (clRequests !== undefined && clRequests.length > 1) { | ||
for (let x = 1; x < clRequests.length; x++) { | ||
if (clRequests[x].type < clRequests[x - 1].type) | ||
throw new Error('requests are not sorted in ascending order') |
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.
Shouldn't this check be moved into the constructor? It is possible to create a block which does not satisfy this condition by using fromValuesArray
or fromRlpSerializedBlock
.
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.
Fair point. Will move
packages/block/src/types.ts
Outdated
@@ -286,4 +302,5 @@ export type ExecutionPayload = { | |||
parentBeaconBlockRoot?: PrefixedHexString | string // QUANTITY, 64 Bits | |||
// VerkleExecutionWitness is already a hex serialized object | |||
executionWitness?: VerkleExecutionWitness | null // QUANTITY, 64 Bits, null implies not available | |||
// TODO: Determine if we need the requestsRoot here |
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.
I would assume so!
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.
@g11tech , agree?
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.
I found this in the CL specs: https://github.com/ethereum/consensus-specs/blob/7bf43d1bc4fdb91059f0e6f4f7f0f3349b144950/specs/electra/beacon-chain.md#executionpayload
It is not updated yet (it is on old 6110 / 7002 which did not yet use 7685), but I would strongly assume that thus the requestsRoot
is added.
) | ||
} else { | ||
if (this.common.isActivatedEIP(7685)) { | ||
const valid = await block.requestsTrieIsValid() |
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.
Shouldn't we do this check before running all txs?
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.
If the generate
option is called, the requestsRoot
passed in the block
will be disregarded and the correct one derived so checking before we validate the generate
flag doesn't make sense. We validate it here if we are re-executing a block to ascertain its validity.
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.
If generate
is called we generate the requestsRoot
and put that in the block (this is correct). However, this check is done in case we are not using generate
(so generate
is false
). The block.requestsTrieIsValid
is called on whatever block is provided - this itself, should not change (so this can be done before running any txs). However what you also want to check is that the block.genRequestsTrieRoot(requests)
(so not block.requests
, but the requests
we just have accumulated in accumulateRequests(this)
) equals the provided block.header.requestsRoot
. If this is not the case, then the block thus has a different requests root and the block is incorrect.
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.
Ah, that makes sense. Will push an update shortly.
|
||
// TODO: Add in code to accumulate partial withdrawals (EIP-7002) | ||
|
||
if (requests.length > 1) { |
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.
I agree that this check is not necessary if we check the requests in the right order above.
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.
Looks absolutely amazing 🤩, also agree with Jochem, test cases added are really fabulous and already covering such an amazingly broad scope of the added functionality!
Some small comments but nothing major to be added from my review here.
packages/util/src/requests.ts
Outdated
|
||
export class CLRequest implements CLRequestType { | ||
type: number | ||
bytes: Uint8Array = new Uint8Array() |
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.
Short nit: I guess new Uint8Array()
is not needed here?
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.
Probably not. It was just easier than logging out random bytes to the console and then putting it in. Will adjust.
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.
Guess comment is misplaced here? 😅
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.
Indeed, meant to put that one on your question about randomBytes
. This is why I shouldn't respond to code reviews on mobile.
@@ -417,6 +472,7 @@ export class Block { | |||
uncleHeaders: BlockHeader[] = [], | |||
withdrawals?: Withdrawal[], | |||
opts: BlockOptions = {}, | |||
requests?: CLRequest[], | |||
executionWitness?: VerkleExecutionWitness | null | |||
) { |
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.
Just to note here that we need to be a bit careful with such parameter
order switches (so: putting requests
before executionWitness
) for backwards compatibility reasons (we already have released a block library version with executionWitness
included. Guess in this case it should be ok though and does make sense to have this in the "correct" order from the beginning.
@@ -140,6 +140,8 @@ const jsonRpcBlock = async ( | |||
blobGasUsed: header.blobGasUsed, | |||
excessBlobGas: header.excessBlobGas, | |||
parentBeaconBlockRoot: header.parentBeaconBlockRoot, | |||
requestsRoot: header.requestsRoot, | |||
requests: block.requests?.map((req) => bytesToHex(req.serialize())), |
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.
Side note: I do not see executionWitness
in here? Is this forgotten as well?
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.
(in doubt not for this PR)
packages/common/src/eips.ts
Outdated
status: Status.Draft, | ||
// TODO: Set correct minimum hardfork | ||
minimumHardfork: Hardfork.Cancun, | ||
requiredEIPs: [], |
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.
Guess we can (minimally) add 3675 (consensus to PoS Upgrade) here if we want to.
Yeah, but also not so relevant eventually.
|
||
// TODO: Add in code to accumulate deposits (EIP-6110) | ||
|
||
// TODO: Add in code to accumulate partial withdrawals (EIP-7002) |
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.
Simply for my understand: so here a call into read_withdrawal_requests()
from https://eips.ethereum.org/EIPS/eip-7002#execution-layer ("System Call" section) would take place, right?
Side question for @acolytec3, since you likely have better imagination on this: how does this affect execution with e.g. RPCStateManager? Does this still work (do not yet get the pieces together in my head)?
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.
To the question for me, I don't "think" this should have any impact. We already track contract state updates in a local cache in the RPCStateManager so it should keep track of any changes we make in the processing of requests.
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.
@holgerd77 Yes exactly here the call to read_withdrawal_requests
is made. For 6110 I am not sure if all the logic is in here or not (but I am not super deep into 6110, @scorbajio might have better insights here)
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.
For 6110, deposits are retrieved from the block receipt logs for any logs whose address is DEPOSIT_CONTRACT_ADDRESS
and also from the block body requests field for any requests that are typed as deposit requests.
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.
Will take this in now to "break the PR dependency cascade", guess we can eventually fine tune last things along both practical integrations.
Implements EIP-7685