Skip to content

Rough prototype for architectural changes needed to introduce execution proofs #7755

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

Draft
wants to merge 116 commits into
base: unstable
Choose a base branch
from

Conversation

kevaundray
Copy link
Contributor

This PR is not meant to be merged. It's mainly to discover all of the architectural changes needed

Issue Addressed

The addition of zkEVMs to Ethereum L1 allows the CL to no longer need an EL to verify execution payloads, the execution payload content is moreover replaced with a cryptographic proof that does not scale linearly with the size of the execution payload proof. We will still need the execution payload header.

The current idea for rolling out the changes for zkEVMs is to iteratively add the changes needed such that we can safely test them and uncover edge cases, blockers, etc. safely here means that it should not affect the existing CL logic.

Proposed Changes

Proof generating nodes

Someone must create the execution proofs for the execution payloads. Long term, when proofs are mandatory, we believe this will be the builders, since they are incentivised to not have their blocks be re-orged for being invalid.

While we are in the interim stage where proofs are not mandatory, there is no incentive to create proofs. The idea here is that these proofs will be subsidised until then.

Proof generating nodes are the nodes whom will generate these proofs in the protocol.

new_payload

Nodes can opt to be proof generating nodes which means that whenever they receive a beacon block and need to verify the execution payload via engine_new_payload, they will also generate proofs and submit these proofs over the new proof subnets.

get_payload

These nodes can also opt to generate proofs for blocks they have proposed. I believe we could just have proof generation only in new_payload and omit it in get_payload -- the idea behind not doing it this way was that if you're the proposer, you can start generating proofs as soon as you receive the payload from the EL.

Stateless attestor

new_payload

Stateless nodes do not have an EL attached (in practice) and will wait for proofs to be received on whichever proof subnets they have subscribed to, in order to validate the execution payload.

The way it has been implemented in this PR is that if the node is a stateless validator, they will mark all payloads as optimistic, moreover, since fork choice is never modified, the node currently will always be in optimistic sync mode.

get_payload

Stateless nodes cannot locally build blocks because they have no EL state, they must use mev-boost. This PR does not add the mev-boost functionality, so stateless nodes cannot build blocks.

Proof generation

Currently proof generation has been stubbed out since it is not needed for running local testnets. The main feature we need here is determinstic output wrt the execution payload.

Proof chain

This code deliberately does not modify fork choice to incorporate proof verification. We instead have a structure that keeps track of what blocks have been proven alongside the beacon chain. This means that one could run a stateless validator alongside mainnet/testnet.

Additional Info

  • Ran some preliminary tests using kurtosis by running ./scripts/local_testnet/start_local_testnet.sh

@kevaundray
Copy link
Contributor Author

A lot of the invasive changes were due to adding new gossipsub topics/subnets -- I've tried to put most of the new code into new files so that they don't touch the existing code, making the diff easier to see

Comment on lines +155 to +156
/// Timestamp when this proof was generated (Unix timestamp)
pub timestamp: u64,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was removed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This file is mainly here for notetaking, so can ignore

Comment on lines +141 to +142
// Note: That if we were to modify fork choice, it would likely be here, where we know what set of
// beacon blocks have valid execution payloads.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As the comment mentions, one could trigger head recomputation here based on the proven blocks

Comment on lines +3913 to +3919
// Register optimistic blocks for proof validation in stateless validation mode
if payload_verification_status.is_optimistic() {
if let Ok(execution_payload) = block.execution_payload() {
let execution_block_hash = execution_payload.block_hash().into();
self.register_optimistic_block_for_proof(block_root, execution_block_hash);
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is where the beacon block is registered in the proof store and we start listening for proofs of the particular execution_block_hash

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Proof generation and verification are essentially the two exported methods in here that have been stubbed out

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is likely the bulk of the PR, it is a "Proof Store" that keeps track of the blocks that we've proven, the proofs that we've received and general proof management

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This file is in charge of broadcasting proofs, it speaks with the proof store in order to know what exactly needs broadcasting

@@ -3167,4 +3167,124 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
write_file(error_path, error.to_string().as_bytes());
}
}

/// Process a gossip execution proof message.
pub async fn process_gossip_execution_proof(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Logic for handling gossip proof messages; the subnet ID lets us know the proof type/proving system

.display_order(0)
)
.arg(
Arg::new("stateless-min-proofs-required")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

stateless-min-proofs-required -- There will be more than one proof for a particular execution payload. This number essentially says how many proofs you want to receive before you deem the block to be valid. So its like a k-out-of-n

///
/// Note: bounds here relates to the fact that there is a maximum number of subnets
/// that we can have; it is the number of maximum number of proofs that we will accept.
pub fn new(id: u64) -> Result<Self, InvalidSubnetId> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Main difference between this subnet wrapper type and others, like the ones for columns, is the fact that it has this validation check.

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.

1 participant