Skip to content
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

Refactor rollup into a consumable library #75

Draft
wants to merge 72 commits into
base: main
Choose a base branch
from

Conversation

ernestognw
Copy link
Member

Over the development of the project, I've felt we've been working on multiple tightly related topics without properly gluing them together into the correct abstractions.

Some code smells like comparing commitment to its hashes in the PublicationFeed, or multiple functions permissioned to addresses that seemed to be similar (e.g. checkpoint tracker, signal service) convinced me to experiment building a modular L1Rollup using language features.

By "language features", I mean that the Solidity compiler should guide the developer in how to get started with a simple minimal rollup and then add functionalities as they see fit.

Rationale

I decided to aim for having a single contract on the L1 that is just a "rollup".

I had the gut that multiple concepts were duplicated across the implementations. For example, the current PublicationFeed only defines the PublicationHeader struct and tracks its hashes, where the publications include a commitment that's up to the L2 inbox to understand.

It seems to me that there's a general concept of a single commitment of a publication, and whatever the publication means is left to the implementation. However, for developers to build their own publication formats, they must compose all these implementations and understand where/how to insert their logic.

Minimal Implementation

I'm proposing a minimal implementation of a rollup with the following interface:

interface IL1Rollup {
    event Proposed(bytes32 indexed commitment, bytes publication);
    event Proven(bytes32 indexed commitment);

    event SignalSent(bytes32 indexed value);

    error InvalidProof();
    error UnknownCommitment();
    error UnprovenCommitment();

    function latestCommitment() external view returns (bytes32);
    function nextCommitment(bytes32 commitment) external view returns (bytes32);
    function proposed(bytes calldata publication) external view returns (bool);
    function proven(bytes calldata publication) external view returns (bool);
    function signalSent(bytes32 value) external view returns (bool);
    function isValidTransition(bytes32 from, bytes32 target, bytes memory proof) external view returns (bool);
    function toCommitment(bytes memory publication) external view returns (bytes32);
    function propose(bytes memory publication) external;
    function prove(bytes32 from, bytes32 target, bytes memory proof) external;
    function sendSignal(bytes32 value) external returns (bytes32);
}

Extending to other features

So far, the features we've been discussing like delayed inclusion, preconfirmations (i.e. permissioned proposer) or proving markets (i.e. who can prove) can build on top of these interfaces as overrides to a base implementation. It's up to the developer how they want to handle those cases, and if they want to prove with a simple ECDSA that should be ok.

Though, the library should offer the building blocks to deploy the most decentralized version of a rollup since the beginning. Here are some ideas of how the L1Rollup contract can be extended:

L1RollupDepositable

Multiple use cases to design a rollup involve economic incentives. For those, an extension that allows depositing and withdrawing ETH would be a good extension that is compatible with those use cases

L1RollupProverMarket

An extension that implements @ggonzalez94 work on an ahead-of-time auction for provers. Instead of being a manager contract, the proving market is held within the same rollup instance.

Preconfirmations

Teams can use the L1Rollup contract to override the propose function and set mechanisms to give the proposer rights dynamically.

ggonzalez94 and others added 30 commits February 24, 2025 09:17
@ernestognw ernestognw marked this pull request as draft March 14, 2025 07:09
nikeshnazareth and others added 23 commits March 17, 2025 17:40
I think we can still get in a weird situation where a prover exits
after the liveness window has passed. This means the actual largest
window is livenessWindow + exitDelay + provingDeadline, but that is
probably fine
The CheckpointTracker only saves a hash of the last proven checkpoint.
I add a parameter so the caller can provide the actual checkpoint to be
checked against the hash. I did not update the tests, because I think we
should actually update the CheckpointTracker to save the whole checkpoint,
but I did not want to edit it until the merge conflicts are resolved.
It represents a time window. The period.deadline remains unchanged
(which is the actual deadline after the proving window)
At the moment, a publication on the boundary is not considered part
of either period. We need it to fall on one side or the other.
I have arbitrarily chosen period.end to be an inclusive bound, so
publications on that timestamp are within the period
The first publication of every new period will call `getCurrentFees` before the currentPeriodId
is updated, but will pay the fees after it is updated. This means it will pay the wrong fee.
In the case the fee goes up, the publication will fail unless the proposer already has
enough of a deposit to make up the difference
The function comments should explain the rationale
It is possible for a period to end without the prover getting their stake.
This could occur if they forget to include nextPublicationHeaderBytes but also:
- the last publication for a while might occur in their proving window, so they
  cannot wait for another publication, or
- they might prove some publications during their window before they realise
  that there will be no new publications in their window.

In either case, we want a mechanism to recognise that the prover has completed
their task but has not receive their stake. This PR clears the fees and stake
when the funds are distributed so any non-zero values are still to be distributed.
Co-authored-by: Gustavo Gonzalez <[email protected]>
Base automatically changed from ahead-of-time-prover to main March 26, 2025 13:13
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.

4 participants