-
Notifications
You must be signed in to change notification settings - Fork 20.9k
Add initial FOCIL implementation #30914
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
base: master
Are you sure you want to change the base?
Conversation
33efbee
to
78f8ad9
Compare
9f5db6f
to
bbdaa45
Compare
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.
Pointing out Engine API has incorrect type for inclusion list. Current implementation expects base64 strings whereas the convention and the specs demand hex strings.
I suggest either define inclusion list type and its marshal type in beacon/engine/types.go
and let gencodec
handles the conversion similar to how ExecutableData
is handled. Or manually marshal/unmarshal like how convertRequests
handles incoming executionRequests
in NewPayloadV4
I've addressed comments. Thank you very much for spotting out the issue and suggesting solutions! @ensi321 |
eb46040
to
d5c724b
Compare
9e1f361
to
29b805d
Compare
@jwasinger Applied your suggestion and rebased, thanks! |
eth/catalyst/api.go
Outdated
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague): | ||
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun or prague payloads") | ||
if params.Withdrawals == nil { | ||
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals")) |
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.
The latest rebase removed the refactors that were recently merged into this file.
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.
Current implementation expects fcuv3 be called in eip7805 fork as well, which will be absorbed into some canonical fork in future.
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.
The review wasn't about this line in particular, sorry for the confusion. We refactored a lot of if
/else if
/else if
/... into switch statements.
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.
Oh right, the last commit reverts all of those changes without causing any conflict. My bad, let me reflect the refactors.
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.
By the way, it seems the refactor can be extended a bit. e.g, replacing engine.PayloadStatusV1{Status: engine.INVALID}
with invalidStatus
, and declaring a common variable for engine.StatelessPayloadStatusV1{Status: engine.INVALID}
. Also, some comments are off. L609 should be return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague payloads")
. Same with L686 and L763. (Line numbers are based on the latest master branch)
… on eip7805 fork
pendingInclusionListTxs = append(pendingInclusionListTxs, tx) | ||
} | ||
|
||
// Append any valid inclusion list transactions at the end of the block. |
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.
We should sort IL+pool transactions by how many fees they pay and use this to prioritize inclusion. It's possible there could be high-paying txs in the IL that aren't in our pool.
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.
Absolutely. Current implementation is a naive one, prioritized easier implementation and testing. Do you think we need to adapt the inclusion strategy in this PR?
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.
It's not absolutely vital, but we will want to make the change before this goes into production.
Is there anything else that you omitted in this PR to keep the diff easier to read/test?
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.
Nothing comes to my mind at the moment. Whether to use engine_updatePayloadWithInclusionListV1
or engine_forkchoiceUpdatedV4
could be changed in future as it's not decided yet.
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've come up with another one. It takes a naive approach when building an IL, too. It doesn't use any heuristic algorithm such as taking the time spent in the mempool into account, and so on.
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.
Like I wrote on the call: because it's unlikely that we will simultaneously be an IL committee member and the proposer for the same block, maybe we can afford to have a more altruistic default strategy than just building the most profitable IL.
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.
and also to build the most profitable IL, we would have to do full transaction execution here. and even then, it's still speculative because we are not building the IL on top of the state that it will be applied.
@@ -769,7 +865,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData, | |||
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, requests, opaqueWitness) | |||
} | |||
|
|||
func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, witness bool) (engine.PayloadStatusV1, error) { | |||
func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, inclusionList engine.InclusionList, witness bool) (engine.PayloadStatusV1, error) { |
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.
The parameters here become quite clunky. Maybe we should create a struct here to pass the data, makes it easier to add fields in the future
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. But until we get into this implementation seriously, I'd like to keep it simple and naive as master
can be refactored. I believe applying these changes into master
when the time comes would be cleaner.
return nil, err | ||
} | ||
|
||
if err := miner.fillTransactions(nil, env); err != nil { |
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.
We will fill with as many transactions as possible, but only the first 8 will actually be included in the inclusion list, right? Maybe we should limit the transactions to 8 in that case to not spend too much extra time on this
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.
The IL size of 8kb is the limit per proposer in the committee. The aggregated IL that's passed to the EL for block production can be 8*16 kb max.
At the call with Geth team, there was feedback that I haven't given much thought about where is the best location from the Geth codebase perspective, but from the spec perspective, the IL constraints should be checked after executing all transactions and before processing withdrawal requests. This is to prevent such situations that some withdrawal address become availble to cover some IL transaction that they couldn't. That missing IL transaction can reorg the block, which it shouldn't. In current implementation, it would be between L106-L107 of As this would change the core part of Geth, I would wait until I can get more feedback from the Geth team before proceeding. |
This PR implements initial FOCIL specifications. For more information, please refer to EIP-7805 and this PR.