Skip to content

Design Provable Derivation Pipeline #2

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

Closed
Tracked by #9
frisitano opened this issue Dec 24, 2024 · 2 comments · Fixed by #41 or #48
Closed
Tracked by #9

Design Provable Derivation Pipeline #2

frisitano opened this issue Dec 24, 2024 · 2 comments · Fixed by #41 or #48
Assignees
Milestone

Comments

@frisitano
Copy link
Collaborator

Overview

We must design the different stages that will be required in the provable derivation pipeline. In the first instance, it is fine to define these stages in human language but as we converge on a final design we should define some initial traits that define the interfaces for the stages that will be implemented using kona.

@frisitano frisitano added this to Reth Dec 27, 2024
@frisitano frisitano mentioned this issue Dec 30, 2024
8 tasks
@Thegaram
Copy link
Contributor

Thegaram commented Jan 2, 2025

I think we can also start by adopting the current L1 follower node logic (ref scroll-tech/go-ethereum#1098) with suitable interface definitions. Then it will be fairly easy to upgrade this into a more sophisticated provable derivation pipeline.

@greged93
Copy link
Collaborator

greged93 commented Feb 21, 2025

I wrote down a couple of the requirements I found for the pipeline and defined the below interfaces:

Requirements

  • The derivation pipeline yields all Scroll payload attributes associated with a L1 block hash.
  • The derived payload attributes can be used to build a L2 block.
  • The derived payload attributes include a list of ordered transactions to execute and any system configuration update (e.g. signer auth).
  • The derivation pipeline can source any required DA for the block (i.e. blobs).
  • The derivation pipeline is implemented in a modular way, where additional blocks can be plugged in with minimal effort.

I propose the below set of traits in order to define the interface to interact with the pipeline. The interface stays generic and provides a very simple API which we can extend with queues, Chunks or Batch provider, etc.

pub trait DerivationPipeline: Stream<Item = ScrollPayloadAttributes> + Cursor<Head = B256> {
    fn flush(&mut self);
}

pub trait PayloadAttributesProvider: Cursor<Head = B256> {
    type Error: Into<PipelineError>;
    async fn next_attributes(&mut self) -> Result<Option<ScrollPayloadAttributes>>, Self::Error>;
}

pub trait L1BlockProvider {
    async fn block_by_id(&self, block_id: BlockId) -> Option<Block>;
}

pub trait L1DAProvider {
    type Error: Into<PipelineError>;
    async fn get_blobs(&self, block_id: BlockId, hashes: &[B256]) -> Result<Vec<Blob>, Self::Error>;
}

pub trait Cursor {
    type Head;
    fn head(&self) -> Self::Head;
    fn set(&mut self, at: Self::Head);
}

Below as well the interaction of the node manager with the provided pipeline interface. Note that we don't really have to flush the pipeline if we decide to handle all attributes at once. This could however lead to some starvation if a L1 block contains a large amount of L2 attributes. The RollupNodeManager could implement logic where it assigns different budgets to each future it needs to handle and polls these until a budget is depleted. If we don't decide to implement the above, flush can be removed.

impl Future for RollupNodeManager {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // poll other futures
        ...
        // match the l1 notification
        match notification {
            L1Notification::Reorg(_) => {
                this.pipeline.flush();
                ...
            }
            L1Notification::Block(block) => {
                // set target hash for the pipeline
                this.pipeline.set(block.hash());
                while let Poll::Ready(Some(attributes)) = this.pipeline.poll_next_unpin() {
                    // handle the attributes
                    ...
                }
            }
            ...
    }
}
sequenceDiagram
    Caller->>DerivationPipeline: Cursor::set(hash)
    DerivationPipeline->>PayloadAttributesProvider: Cursor::set(hash)
    loop 
        Caller->> DerivationPipeline: Stream::next
    end
Loading
sequenceDiagram
    Caller->> DerivationPipeline: Stream::next
    DerivationPipeline->>PayloadAttributesProvider: next_attributes
    PayloadAttributesProvider->>L1BlockProvider: block_by_bash
    L1BlockProvider-->>PayloadAttributesProvider: Block
    PayloadAttributesProvider->>L1DaProvider: get_blobs
    L1DaProvider-->>PayloadAttributesProvider: blobs
    PayloadAttributesProvider-->>DerivationPipeline: ScrollPayloadAttributes
    DerivationPipeline-->>Caller: ScrollPayloadAttributes
Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
3 participants