peter-scroll
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Sequencer The sequencer is one of the core components in the Scroll protocol: it is responsible for maintaining the L2 blockchain. The sequencer also ensures that the user and developer experience on Scroll closely resemble those on Ethereum. It achieves this by maintaining EVM and RPC behaviour that is directly inherited from Ethereum, with very few modifications. The primary functions of Scroll's sequencer are: - Collect transactions from L2 and L1. - Validate transactions and pack them into L2 blocks. - Execute blocks and maintain the L2 blockchain state. - Pack blocks into chunks for zkEVM proving. - Pack chunks into batches for aggregate proving. - Submit batches onto L1 (Ethereum), providing Data Availability. It is worth highlighting that bridging messages and tokens from L1 to L2 (deposits) is also the sequencer's responsibility. Messages from L2 to L1 (withdraws), on the other hand, can be executed by any user on L1. The secondary functions of Scroll's sequencer are: - Offer standard Ethereum RPC APIs and some Scroll extension APIs. - Allow peers (follower nodes) to sync the blockchain using Ethereum's peer-to-peer protocol. The sequencer, being a fork of [go-ethereum](https://github.com/ethereum/go-ethereum), inherits most of its functionality from Ethereum. This includes transaction and block data structures, EVM execution, RPC and p2p protocols. As these were not reimplemented but were directly inherited from [go-ethereum](https://github.com/ethereum/go-ethereum)'s original code, we can have a very high certainty of Scroll's compatibility with Ethereum. The following sections will introduce the main components of the sequencer, the end-to-end sequencing workflow, and some design details. *In the remainder of this article, L1 will refer to Ethereum, while L2 will refer to Scroll.* ## Sequencer Components The Scroll sequencer has two main components: `l2geth` and `rollup-relayer`. [`l2geth`](https://github.com/scroll-tech/go-ethereum) is Scroll's fork of [go-ethereum](https://github.com/ethereum/go-ethereum). It is responsible for building and executing blocks and maintaining the blockchain state. `l2geth` inherits most of its functionality from Ethereum, with some notable differences listed below. `l2geth` has the following submodules (not exhaustive list): - **Storage**: Ledger and state storage implemented using LevelDB. - **EVM**: The state transition rules of Ethereum. - **Worker:** Responsible for creating new L2 blocks. - **L1 `SyncService`**: Sync and store L1 messages in `l2geth` local database. - **API layer**: Standard Ethereum RPC and p2p interfaces. - **Transaction pool**: mempool for L2 transactions. `rollup-relayer` is responsible for splitting up the Scroll blockchain into sections that are suitable for proving and commitment on L1. The two main units of this are *chunks* and *batches*. A chunk is simply a contiguous section of the L2 ledger, it is a collection of L2 blocks, and chunks are the unit of zkEVM proving. `Batches`, on the other hand, are collections of chunks that are submitted to L1, along with an aggregate proof. `rollup-relayer` has the following submodules: - `chunk-proposer`: Collect L2 blocks, propose chunks while enforcing certain limits (see below). - `batch-proposer`: Collect chunks, propose batches while enforcing certain limits (see below). - `relayer`: Submit batches and batch proofs to L1. Furthermore, the following two Scroll contracts are closely related to the sequencer: - `L1MessageQueue` maintains a queue of messages that the sequencer must relay to L2. These messages are either submitted through the bridge (`L1ScrollMessenger`) as deposit transactions or through `EnforcedTxGateway` as enforced transactions. - `ScrollChain` maintains batches and their finalization status. Each batch is submitted through the `commitBatch` function, which stores its `batchHash` in this contract. The ZK proofs are submitted through the `finalizeBatchWithProof` function. ## Lifecycle of a transaction We will now present the end-to-end sequencing workflow from the perspective of a transaction. Transactions can originate either from L2 or from L1, but during sequencing these two types are processed mostly the same way. Most Scroll transactions originate on L2: 1. After signing the transaction, the user submits it to a Scroll node through the standard `eth_sendRawTransaction` API. 2. The transaction is broadcast through the Scroll peer-to-peer network until it eventually reaches the sequencer. Note that submitting transactions to the sequencer directly is not allowed. 3. The sequencer validates the transaction and stores it in its local transaction pool. Some transactions (deposit and enforced transactions) originate on L1: 1. The user submits the transaction on Ethereum. For deposit transactions, the user can use the `ScrollGatewayRouter` contract, one of the specific gateways like `StandardERC20Gateway`, or they can also submit the deposit to the `L1ScrollMessenger` contract directly. Enforced transactions are initiated through the `EnforcedTxGateway` contract. 2. The transaction is validated and appended to the `L1MessageQueue`, which then emits a `QueueTransaction` event. 3. Once the corresponding blocks on L1 are finalized, the sequencer `SyncService` then collects all new `QueueTransaction` events. For each `QueueTransaction` event, the sequencer constructs a special transaction (`L1MessageTx`) and stores it in its local database. The block creation and commit steps are shared for the two transaction types: 4. **Blocks:** The `l2geth` worker periodically starts a new mining job. It first selects a number of L1 messages from its local database, then a number of L2 transactions from its transaction pool for inclusion. The transactions are executed one by one and appended to the block. Once the worker has collected enough transactions, it seals the block, stores it in its local database and `l2geth` broadcasts it into the Scroll peer-to-peer network. 5. **Chunks, batches:** The `rollup-relayer` collects the new L2 block. Eventually, this block is included in a chunk. Eventually, that chunk is included in a batch. 6. **Commit:** The `rollup-relayer` commits the batch by calling `commitBatch` on the `ScrollChain` contract on L1. The data submitted with the commit transaction contains block headers and L2 transactions. (The submitted data does not contain L1 transactions, since these are already available in the `L1MessageQueue` contract on L1.) The batch hash is calculated by `ScrollChain` and stored in its contract storage. The finalization steps are as follows: 7. **Chunk proof:** The chunk is proven by a chunk prover (zkEVM prover). 8. **Batch proof:** For each chunk in the batch, the chunk proofs are aggregated into a single batch proof by the batch prover (aggregation prover). 9. **Finalization:** The batch proof is submitted to L1 by the `rollup-relayer`, along with the updated state root and withdraw root. `ScrollChain` verifies the submitted proof using an on-chain verifier contract. If verification passes, the batch is marked as finalized, and L1 messages processed in this batch are deleted from `L1MessageQueue`. At this point, the transactions included in the finalized batch are considered finalized. ## `l2geth`: Summary of modifications `l2geth` is a fork of `[go-ethereum](https://github.com/ethereum/go-ethereum)`. As such, it inherits most of Ethereum's behaviours. However, we needed to make some breaking changes to `l2geth` to enable more efficient proving. This section provides a non-exhaustive list of the modifications, along with their rationale. **zktrie** - Ethereum uses the MPT (Merkle-Partricia Trie) as its state storage data structure. This trie's structure and the fact that it uses keccak hash would make it prohibitively expensive for ZK circuits. l2geth instead uses zktrie: a binary trie with Poseidon hash for its state storage. **Opcodes**: - The `BASEFEE` opcode are disabled and behaves the same way as `INVALID`. The reason is that Scroll diabled EIP-1559. - The `SELFDESTRUCT` opcode is disabled and behaves the same way as `INVALID`. The reason is that this opcode would be prohibitively expensive to prove, and it is already deprecated in Ethereum. - `DIFFICULTY`/`PREVRANDAO` returns `0` since l2geth does not run PoW or PoS. - `BLOCKHASH` returns `keccak(chainId || height)`. The reason is that the full block hash cannot be verified by the zkEVM with reasonable cost, since one would need to provide all the receipts and the bloom filter to verify these fields. As a result, `BLOCKHASH` will be unique for each block but it will not correspond to the actual L2 blockhash and it cannot be used as a source of randomness. - The Shanghai EIPs: EIP-3860 (Limit and meter initcode), EIP-3651 (warm coinbase), PUSH0 are enabled on Scroll. That means that you can safely target the latest EVM version when compiling your contracts. **Precompiles** - The hashing precompile `sha256`, `ripemd-160`, and `blake2f` cannot be verified by the current zkEVM version and thus they are disabled. Calling these precompiles will revert. We plan to support these precompiles in the future in the form of a network upgrade. - `modexp` works but only supports inputs of 32 bytes (`uint256`) or shorter. `ecPairing` works but only allows up to 4 inputs. This limitations make proving these precompiles much more manageable. We believe that the majority of existing use cases fit into these limits. **Fees** - All fees collected on L2 are sent to a Scroll-maintained L2 fee vault contract. - L1 fee: In addition to the L2 gas fee that covers L2 block space and execution costs, we also collect an L1 fee that covers the costs of committing the transaction to L1. This fee is proportional to the size of the RLP-encoded transaction. The actual cost depends on the current settings stored in the `L1GasOracle` contract on L2. This fee is deducted from the sender balance directly (and not from the gas allowance). **L1MessageTx** - We added a new transaction type `L1MessageTx`. - We also added DB interfaces for storing such transactions and related metadata. - Finally, we implemented `SyncService` that monitors finalized blocks on L1 and collects L1 messages from these. **StateAccount** - Add `PoseidonCodeHash` to `StateAccount`. The zkEVM uses this code hash to verify the contract code when it's loaded. - Maintain `KeccakCodeHash` in `StateAccount`. The zkEVM only needs to verify this one (when the contract is created). The `EXTCODEHASH` opcode returns the `KeccakCodeHash`, maintaining compatibility with Ethereum. - Add `CodeSize` to `StateAccount`. The `EXTCODESIZE` opcode returns `CodeSize`. This way, we can verify that the correct result is returned without loading the contract code into the zkEVM. **New validation rules** - We added a number of new block validity rules to l2geth that correspond to the "chunk and batch constraints" outlined above: Number of l2 transactions, block payload size, circuit row consumption. - Other rules are related to L1 messages. L1 messages in a block must form a contiguous block at the front of the block. L1 messages in a block must be included following their order in `L1MessageQueue`, i.e. they must be included with increasing `QueueIndex`. L1 messages in a block must match those in `L1MessageQueue`. - Most of these rules are considered both during block creation (worker.go) and block validation (block_validation.go). As a result, if the sequencer violates any of these rules, follower nodes will reject its blocks. **Other changes** - Disable EIP1559. - Offer a trace api `scroll_traceBlockByNumberOrHash` to provers. ## `l2geth`: Skipping & circuit capacity checker With Scroll's current zkEVM circuits, it is possible to construct transactions and blocks that cannot be proven because they "do not fit into the zkEVM". We call this *proof overflow*. To avoid this, we implemented a *circuit capacity checker* module as part of l2geth. The circuit capacity checker is used both during block creation (`worker.go`) and block validation (`block_validation.go`). During block creation, if the next transaction would lead to proof overflow, then we seal the block and leave the transaction for the next block. If a single transaction leads to proof overflow, l2geth discards it. We call this mechanism *skipping*. Skipping L2 transactions means simply discarding them. In this case, the user needs to submit another transaction with the same nonce that does not lead to proof overflow in order to proceed. Skipping L1 messages is a more explicit process. Both the `ScrollChain` contract on L1 and the zkEVM verifies that each L1 transaction in `L1MessageQueue` was either included and executed, or skipped. While the batch encoding does not contain L1 transactions, it does include a *skip bitmap* that indicates to `ScrollChain` which L1 messages were skipped. If an L1 deposit message is skipped, the user can get their tokens refunded on L1. Note: Proof overflow and thus skipping suggests malicious activity; for normal deposit transactions, this will never happen. As the unit of zkEVM proving is the chunk, proof overflow must be avoided for chunks as well. This is achieved by incorporating the circuit capacity checker into the rollup-relayer to make sure that it never proposes unprovable chunks. ## `rollup-relayer`: Chunk and batch constraints Compared to `l2geth`, the `rollup-relayer` is a much more straightforward and simple component. It collects L2 blocks, creates chunks and batches, and submits these to L1. In this section we outline the main limits that `rollup-relayer` must enforce during chunk and batch creation. Constraints on chunks: - **No proof overflow:** Using the circuit capacity checker, we make sure to include as many blocks in a chunk that it would still not lead to proof overflow. Constraints on batches: - **L1 payload:** Ethereum has a hardcoded 128KB limit on transaction payload size. - **L1 commit gas:** The gas cost of committing a batch is proportional to the number of blocks and transactions in it. We must make sure that this cost does not exceed the L1 block gas limit. - **Number of chunks:** `rollup-relayer` includes a number of chunks that is optimal for the aggregation prover. ## Notes on decentralizing the sequencer As it stands, Scroll's current sequencer is centralized. In this section, we consider 4 threats related to centralized sequencers: arbitrary state transitions, censorship risk, regulatory risk, liveness risk. A centralized sequencer cannot execute arbitrary state transitions. If, for example, the sequencer tried to move funds from a user's account to its own account, that would constitute an invalid state transition according to the EVM's rules. While the sequencer could certainly create such a block, it could not be proven in the zkEVM and thus the funds could never be withdrawn to L1. A centralized sequencer could choose to censor transactions from certain senders, rendering their funds on L2 frozen. We added the enforced transaction mechanism to mitigate this risk. Through this mechanism, users can submit transaction on L1 directly and the sequencer is forced to include such messages in its blocks. Unfortunately, the problem of proof overflow forces us to allow the sequencer to skip such messages. This kind of censorship is very explicit and easy to detect. Scroll is working actively to eliminate the proof overflow problem through upgrades to our proving system. Once proof overflow does not necessitate skipping anymore, the enforced transaction mechanism can fully solve censorship. Since the centralized sequencer must be deployed in some specific jurisdiction, it is subject to regulatory risk. Regulators can force Scroll to enforce KYC requirements, or potentially event take over the sequencer. While this is certainly a possibility, it is possible in such scenarios to quickly migrate the sequencer to other jurisdictions. The long-term solution to this risk is decentralizing the sequencer. If the centralized sequencer is down for any reason, the L2 ledger cannot progress and users cannot withdraw their funds. The long-term solution to this risk is decentralizing the sequencer. Decentralizing the sequencer helps prevent both malicious acts from the sequencer, as well as Single-Point-of-Failure issues. Scroll is actively working on upgrading the protocol to allow multiple sequencers. We will share the progress with the community shortly.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully