-
Notifications
You must be signed in to change notification settings - Fork 975
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
Use engine_newPayloadV3
to pass versioned_hashes
to EL for validation
#3359
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.
+1, I think we can just remove verify_kzg_commitments_against_transactions
specs/deneb/validator.md
Outdated
@@ -98,8 +98,8 @@ def validate_blobs_and_kzg_commitments(execution_payload: ExecutionPayload, | |||
blobs: Sequence[Blob], | |||
blob_kzg_commitments: Sequence[KZGCommitment], | |||
blob_kzg_proofs: Sequence[KZGProof]) -> None: | |||
# Optionally sanity-check that the KZG commitments match the versioned hashes in the transactions | |||
assert verify_kzg_commitments_against_transactions(execution_payload.transactions, blob_kzg_commitments) | |||
# TODO: can we just remove it? |
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 am not sure if this sanity check does make sense on CL side. If a CL client was given with inconsistent blobs data and a payload what can be done to overcome this situation? I think that EL should be checking this during the build process, otherwise, this inconsistency will likely result in a missed proposal. Even if the build process would be triggered once again there is a chance that the outcome will remain the same
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.
Actually this can't be done anymore unless CL implements RLP, and also as mentioned above the proposal with eventually fail if this is inconsistent via new_payload EL calls. So better to just remove them
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.
Btw, my comment was about validate_blobs_and_kzg_commitments
function in general
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.
yeah I agree with @mkalinin here, im not sure what value this adds
the assumption is that the engine API is trusted so it seems a bit redundant to have the CL check what should be "good" data from the EL
d163bef
to
0b2f604
Compare
specs/deneb/beacon-chain.md
Outdated
assert execution_engine.notify_new_payload(payload) | ||
# [Modified in Deneb] | ||
versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] | ||
assert execution_engine.notify_new_payload( |
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.
another strategy is to keep notify_new_payload()
as the same and to insert another function execution_engine.verify_versioned_hashes(versioned_hashes, payload.transactions)
. This would be divergent from the engine API but is very explicit.
In fact if we went that path, I would also break out the verification of the block_hash
-- e.g.
assert execution_engine.is_valid_block_hash(payload)
assert execution_engine.is_valid_versioned_hashes(versioned_hashes, payload.transactions)
assert execution_engine.notify_new_payload(payload)
and i would maybe keep it in process_blob_kzg_commitments
along with the length check discussed in #3338
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.
cc: @mkalinin
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 really like this strategy as making these checks explicit brings more clarity to the spec. Can't see anything that could be broken by doing it this way, I was thinking about optimistic sync tests but they shouldn't be affected afaics
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.
But in client implementations, the validation will still use the one Engine API call response, correct? Aren't different API abstractions make it more difficult to test? e.g., we already yield execution_valid
in test vectors, if we want to add what's proposed in #3359 (comment) + add execution_engine.is_valid_versioned_hashes()
helper in specs, we have to yield an is_valid_versioned_hashes
field in test vectors.
I'd like to confirm if clients indeed prefer parsing this themselves. 🤔
/cc @terencechain
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.
my view: we would just like it as a single call with length check before the call (check should come before versioned hashes computation but suggested here for the conversation context)
assert execution_engine.notify_new_payload( | |
asset len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK | |
assert execution_engine.notify_new_payload( |
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.
Given this is a specification to show complete state transition validation and mutation logic and not an implementation guide that knows or cares about the engine api (Engine API is just one architecture of a valid full client), I very much like explicitly calling out the various groupings of validations instead of just hiding it behind one.
That said, at this point in the process, if it is going to cause too much additional overhead (e.g. with changing test formats), I'm not going to push too hard for it.
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.
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 the explicitness is good, but CL is just the caller and has no control over executing the validation. I support @ppopth's proposal of renaming the API name or creating a new API to replace the old one in Deneb.
Another way is to make it clear in the abstract API:
def verify_and_notify_new_payload(self: ExecutionEngine,
new_payload_request: NewPayloadRequest) -> bool:
"""
Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``.
"""
assert self.is_valid_block_hash(new_payload_request.execution_payload)
assert self.is_valid_versioned_hashes(new_payload_request)
assert self.notify_new_payload(new_payload_request.execution_payload)
And we stick to using the single execution_valid
return value of notify_new_payload_and_verify_versioned_hashes
in testing.
Note: we override this API in setup.py
, so the content doesn't matter for pyspec itself.
Does it make sense to rename the Engine API side as well?
Edited: verify_and_notify_new_payload
approach https://github.com/ethereum/consensus-specs/compare/engine-versioned-hashes-explicit
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 extra length check is unnecessary since the SSZ container has defined field
blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK]
.
It will be changed in this PR #3338
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.
|
||
|
||
@with_deneb_and_later | ||
@spec_state_test | ||
def test_invalid_incorrect_transaction_length_1_byte(spec, state): | ||
def test_incorrect_transaction_length_1_byte(spec, state): |
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.
Should we do a version of this that has executionengine return invalid?
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.
Essentially, the execution_valid
result is fully up to what we set in the testing script. So I think only the "the input is correct, but execution_valid
returns False" is valuable here. I added test case test_invalid_correct_input__execution_invalid
for it.
Things to check
|
@hwwhww I like the approach of having the higher level function encapsulate and make explicit the three high level things the call is performing. Why deneb instead of a Bellatrix modification? This won't affect test vectors and brings the explicit nature of the block-hash verification to the prior spec as well. I'm fine to do this here or in a subsequent cleanup |
As for the removal of But note that this does not preclude the CL from following the |
Would you like to add a note in the validator guide? |
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.
a couple of tiny things.
approved!
specs/bellatrix/beacon-chain.md
Outdated
""" | ||
assert self.is_valid_block_hash(new_payload_request.execution_payload) | ||
assert self.notify_new_payload(new_payload_request.execution_payload) | ||
... |
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.
What does the ... imply 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 wanted to imply that this is a pseudo-code-like function and is client implementation dependent. 😅
specs/deneb/beacon-chain.md
Outdated
Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. | ||
""" | ||
assert self.is_valid_block_hash(new_payload_request.execution_payload) | ||
assert self.is_valid_versioned_hashes(new_payload_request) # [Modified in Deneb] |
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.
Thank you 🙏
It's really nice to see this validation land explicitly in the spec, but at the same time to hide this behind one function that we can call out as the direct mapping for the engine api!
Replace #3345
Require ethereum/EIPs#6985 and ethereum/execution-apis#407
Changes
NewPayloadRequest
and theExecutionEngine.verify_and_notify_new_payload
wrappers in Bellatrix so that we can add new arguments cleanlyversioned_hash
to EL, we change the arguments ofprocess_execution_payload
in Bellatrix. Now we passbody: BeaconBlockBody
instead ofpayload: ExecutionPayload
.process_blob_kzg_commitments
validator.md
: Removedvalidate_blobs_and_kzg_commitments
TODO
BeaconBody
toprocess_execution_payload
.