Skip to content

feat(permissionless batches): batch production toolkit and operator recovery #1555

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 131 commits into
base: develop
Choose a base branch
from

Conversation

jonastheis
Copy link
Contributor

@jonastheis jonastheis commented Oct 24, 2024

Purpose or design rationale of this PR

This PR is part of the permissionless batches (aka enforced batches) feature. It implements the permissionless batch production, operator recovery and provides instructions how to run these in the readme.

permissionless batch production: rollup/cmd/permissionless_batches/app/app.go the main tool in conjunction with permissionless-batches/docker-compose.yml (usage will be explained in readme later) to create batches in a permissionless way and submit them to L1. It requires the recovery and potentially block production without signature in l2geth before.

operator recovery: rollup/cmd/rollup_relayer/app/app.go with cfg.RecoveryConfig.Enable == true. Will
restore all batches between the latest finalized batch in the DB and the latest finalized batch on L1 based on L1 data. It requires the recovery of l2geth before.

Other parts of this feature are implemented in following PRs:

PR title

Your PR title must follow conventional commits (as we are doing squash merge for each PR), so it must start with one of the following types:

  • build: Changes that affect the build system or external dependencies (example scopes: yarn, eslint, typescript)
  • ci: Changes to our CI configuration files and scripts (example scopes: vercel, github, cypress)
  • docs: Documentation-only changes
  • feat: A new feature
  • fix: A bug fix
  • perf: A code change that improves performance
  • refactor: A code change that doesn't fix a bug, or add a feature, or improves performance
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • test: Adding missing tests or correcting existing tests

Deployment tag versioning

Has tag in common/version.go been updated or have you added bump-version label to this PR?

  • No, this PR doesn't involve a new deployment, git tag, docker image tag
  • Yes

Breaking change label

Does this PR have the breaking-change label?

  • No, this PR is not a breaking change
  • Yes

Summary by CodeRabbit

  • New Features

    • Introduced the "Permissionless Batches" feature, enabling users to submit batches with proofs if the operator is unavailable or censoring.
    • Added a comprehensive toolkit and documentation for batch production, proving, submission, and operator recovery.
    • New CLI application for permissionless batch production and recovery.
    • New Docker Compose setup and configuration files for permissionless batch workflows.
  • Bug Fixes

    • Improved error handling and transaction consistency in batch and bundle submissions.
  • Documentation

    • Added detailed README for permissionless batches, including step-by-step guides and troubleshooting.
  • Chores

    • Updated .dockerignore and .gitignore files for improved build context management and source control hygiene.
  • Refactor

    • Enhanced method visibility and naming consistency across ORM and controller layers.
    • Extended configuration structures to support new recovery and permissionless batch features.

Copy link

coderabbitai bot commented Oct 24, 2024

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This change set introduces a comprehensive "permissionless batches" feature for the Scroll rollup system, enabling anyone to submit batches with proofs in scenarios where the operator is unavailable or censoring. It adds new CLI applications, Dockerfiles, configuration files, and a detailed README for permissionless batch production and recovery. The implementation includes controllers for minimal and full recovery, submitter logic for on-chain batch submission, and enhancements to the ORM layer for permissionless operations. Several methods are made public for broader access, and supporting Docker and ignore files are updated or introduced to facilitate new workflows and deployment. Documentation and configuration files ensure reproducibility and clarity for users and operators.

Changes

File(s) Change Summary
permissionless-batches/README.md Added a comprehensive README detailing permissionless batch operation, recovery, and toolkit usage.
permissionless-batches/docker-compose.yml Introduced a new Docker Compose file defining services for permissionless batch production, proving, and database.
permissionless-batches/.gitignore Added a .gitignore to exclude the conf/ directory.
permissionless-batches/conf/coordinator/config.json, .../proving-service/config.json, .../relayer/config.json Introduced new JSON configuration files for coordinator, proving service, and relayer.
permissionless-batches/conf/genesis.json Added a placeholder genesis configuration file.
build/dockerfiles/recovery_permissionless_batches.Dockerfile, .../recovery_permissionless_batches.Dockerfile.dockerignore Added new Dockerfile and dockerignore for building and deploying the permissionless batches recovery tool.
build/dockerfiles/coordinator-api.Dockerfile.dockerignore, .../coordinator-cron.Dockerfile.dockerignore, .../db_cli.Dockerfile.dockerignore, .../gas_oracle.Dockerfile.dockerignore, .../rollup_relayer.Dockerfile.dockerignore Updated dockerignore files to exclude permissionless-batches/conf/ and, in some cases, contracts/ directories.
rollup/cmd/permissionless_batches/app/app.go Introduced a new CLI application for permissionless batch production and recovery, including configuration validation, database setup, observability, and batch/proof submission logic.
rollup/cmd/permissionless_batches/main.go Added a new main entrypoint for the permissionless batches CLI.
rollup/internal/controller/permissionless_batches/minimal_recovery.go Added a MinimalRecovery controller for restoring minimal state and catching up permissionless batches.
rollup/internal/controller/permissionless_batches/submitter.go Added a Submitter for permissionless batch submission to L1, handling proofs and database updates.
rollup/internal/controller/relayer/full_recovery.go Added a FullRecovery controller to restore full previous state from L1, including batch and bundle reproduction.
rollup/internal/config/recovery.go Introduced a new RecoveryConfig struct for recovery-related configuration.
rollup/internal/config/config.go Added a RecoveryConfig pointer field to the main Config struct.
rollup/internal/orm/chunk.go Added InsertPermissionlessChunk method for inserting permissionless chunks based on DA blob payloads.
rollup/internal/orm/batch.go Added methods for inserting permissionless batches and updating batch statuses and hashes.
rollup/internal/orm/bundle.go Renamed getLatestBundle to GetLatestBundle and updated UpdateRollupStatus to accept an optional transaction parameter.
rollup/internal/controller/watcher/chunk_proposer.go Renamed proposeChunk to ProposeChunk and updated call sites for public access.
rollup/internal/controller/watcher/bundle_proposer.go Renamed updateDBBundleInfo to UpdateDBBundleInfo and updated call sites.
rollup/internal/controller/watcher/l2_watcher.go Updated TryFetchRunningMissingBlocks to return an error and renamed getAndStoreBlocks to GetAndStoreBlocks.
rollup/internal/controller/relayer/l2_relayer.go Reordered import statements for clarity.
rollup/cmd/rollup_relayer/app/app.go Added a recovery mode branch for full recovery using the new controller; updated watcher loop to ignore errors from missing block fetches.
rollup/abi/bridge_abi_test.go Added print statements for ABI method and error signatures; reordered imports.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI (permissionless_batches)
    participant DB
    participant L2Watcher
    participant Proposers
    participant Submitter
    participant L1

    User->>CLI (permissionless_batches): Run with config and genesis
    CLI (permissionless_batches)->>DB: Connect and initialize
    CLI (permissionless_batches)->>L2Watcher: Connect to L2
    CLI (permissionless_batches)->>Proposers: Initialize chunk, batch, bundle proposers
    CLI (permissionless_batches)->>CLI (permissionless_batches): Check if recovery needed
    alt Recovery needed
        CLI (permissionless_batches)->>MinimalRecovery: Run recovery
        MinimalRecovery->>DB: Reset and restore minimal state
        MinimalRecovery->>L2Watcher: Fetch missing L2 blocks
        MinimalRecovery->>Proposers: Propose chunks, batch, bundle
    else No recovery needed
        CLI (permissionless_batches)->>Submitter: Submit batch (with/without proof)
        Submitter->>DB: Load latest bundle and batch
        Submitter->>L1: Submit transaction with calldata and blob
        Submitter->>DB: Update batch and bundle statuses
    end
    CLI (permissionless_batches)->>User: Output status and wait for confirmation/exit
Loading

Suggested reviewers

  • jonastheis
  • georgehao
  • omerfirmak

Poem

In burrows deep, a plan was hatched,
For batches permissionless and neatly patched.
With configs, scripts, and Docker’s might,
Recovery’s now a rabbit’s delight!
Chunks and bundles, blocks anew,
On L1 and L2, the magic grew.
🐇 Here’s to open exits and code so bright!


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@georgehao
Copy link
Member

can you add more description about this pr

@jonastheis
Copy link
Contributor Author

can you add more description about this pr

Will do so once it's in a better shape. This is still a draft PR and and such many things are still changing. Once ready, I'll provide a high-level description + how it relates to the changes made in this PR :)

@colinlyguo colinlyguo self-requested a review October 29, 2024 05:05
// 2. Make sure that the specified batch is indeed finalized on the L1 rollup contract and is the latest finalized batch.
// TODO: enable check
//latestFinalizedBatch, err := reader.LatestFinalizedBatch(latestFinalizedL1Block)
//if cfg.RecoveryConfig.LatestFinalizedBatch != latestFinalizedBatch {
Copy link
Member

Choose a reason for hiding this comment

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

curious about why setting cfg.RecoveryConfig.LatestFinalizedBatch instead of using reader.LatestFinalizedBatch as the start point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you're right, can probably remove it and make the configuration a bit easier. initially, I wanted the user to specify L1 block and the latest finalized batch so that the user knows where the (minimal) recovery process is starting from and there's no "magic" happening (e.g. if there's another batch committed in the meantime).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I introduced another config parameter for testing purposes to override this check force_latest_finalized_batch. The user now still needs to specify the L1 block height and latest finalized batch to not have any surprises/magic.

Copy link
Member

Choose a reason for hiding this comment

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

got it.

@@ -149,6 +149,10 @@ func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, chai
return p
}

func (p *BatchProposer) BatchORM() *orm.Batch {
Copy link
Member

Choose a reason for hiding this comment

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

as our layout purpose, the orm instance should be exposed to app layer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done in 5ff6fd0

return db, nil
}

func fetchL2Blocks(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, registry prometheus.Registerer, fromBlock uint64, l2BlockHeightLimit uint64) (uint64, error) {
Copy link
Member

Choose a reason for hiding this comment

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

I suggest that move these logics to controller layer

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done in 5ff6fd0


// TODO: make these parameters -> part of genesis config?
scrollChainAddress := common.HexToAddress("0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0")
l1MessageQueueAddress := common.HexToAddress("0xF0B2293F5D834eAe920c6974D50957A1732de763")
Copy link
Member

Choose a reason for hiding this comment

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

read from config

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done in 5ff6fd0

@jonastheis jonastheis changed the base branch from develop to feat/use-codec-v6 March 10, 2025 23:17
Base automatically changed from feat/use-codec-v6 to develop March 11, 2025 13:05
Comment on lines +444 to +454
// reset and init DB
var v int64
err = migrate.Rollback(sqlDB, &v)
if err != nil {
return fmt.Errorf("failed to rollback db: %w", err)
}

err = migrate.Migrate(sqlDB)
if err != nil {
return fmt.Errorf("failed to migrate db: %w", err)
}
Copy link
Member

Choose a reason for hiding this comment

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

Just implemented in another PR, this can be simplified by migrate.Reset(sqlDB).

@yiweichi yiweichi marked this pull request as ready for review April 24, 2025 07:06
@yiweichi
Copy link
Member

Mark it ready for review temporarily for fixing the ci failing.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 25

🧹 Nitpick comments (19)
rollup/abi/bridge_abi_test.go (2)

177-178: Use testing.T logger instead of fmt.Println
In Go tests, prefer t.Log so that logs are captured by the testing framework (and only shown with -v or on failures).

-    fmt.Println("methods")
+    t.Log("methods")

189-190: Log errors header using t.Log
Replace the direct fmt.Println call with t.Log to avoid polluting standard output.

-    fmt.Println("errors")
+    t.Log("errors")
rollup/internal/config/config.go (1)

21-24: Add validation or defaults for RecoveryConfig
You've introduced RecoveryConfig into the main Config struct. To avoid nil-pointer issues and enforce correct usage:

  • Default RecoveryConfig.Enable to false if omitted (backward compatibility).
  • Validate required fields (e.g., L1 beacon endpoint, latest batch) and error out in NewConfig when Enable == true but config is missing or invalid.
permissionless-batches/conf/proving-service/config.json (2)

6-6: Consider using HTTPS for coordinator communication.

The coordinator URL uses HTTP, which could expose sensitive data if not in an isolated network. Consider using HTTPS for secure communication.

-    "base_url": "http://coordinator:8390",
+    "base_url": "https://coordinator:8390",

18-24: Consider more resilient retry settings for cloud service.

The current retry settings (3 retries with 5 second wait) might not be sufficient for a cloud service that could experience temporary outages. Consider increasing the retry count or implementing exponential backoff.

    "cloud": {
      "base_url": "https://sindri.app/api/v1/",
      "api_key": "<API key>",
-      "retry_count": 3,
-      "retry_wait_time_sec": 5,
+      "retry_count": 5,
+      "retry_wait_time_sec": 10,
      "connection_timeout_sec": 60
    }
rollup/cmd/rollup_relayer/app/app.go (1)

114-124: Consider checking if L1 reader was created successfully.

There's no validation that the L1 reader was created successfully before using it in NewFullRecovery. While there is error handling after the l1.NewReader call, adding a nil check before passing it to NewFullRecovery would be safer.

if err != nil {
  return fmt.Errorf("failed to create L1 reader: %w", err)
}

+if reader == nil {
+  return fmt.Errorf("L1 reader is nil after creation")
+}
+
fullRecovery := relayer.NewFullRecovery(subCtx, cfg, genesis, db, chunkProposer, batchProposer, bundleProposer, l2watcher, l1Client, reader)
permissionless-batches/conf/coordinator/config.json (1)

35-36: Consider shorter token expiration times.

The current challenge and login expiration durations are 3600 seconds (1 hour), which might be longer than necessary for security best practices.

-    "challenge_expire_duration_sec": 3600,
-    "login_expire_duration_sec": 3600
+    "challenge_expire_duration_sec": 1800,
+    "login_expire_duration_sec": 1800
rollup/internal/config/recovery.go (1)

6-7: Consider adding validation for endpoint

The L1BeaconNodeEndpoint field could benefit from validation to ensure it's a valid URL.

Consider adding a validation method to the RecoveryConfig struct:

func (c *RecoveryConfig) Validate() error {
    if c.Enable {
        if c.L1BeaconNodeEndpoint != "" {
            if _, err := url.Parse(c.L1BeaconNodeEndpoint); err != nil {
                return fmt.Errorf("invalid L1BeaconNodeEndpoint URL: %w", err)
            }
        }
        // Add more validations as needed
    }
    return nil
}
build/dockerfiles/recovery_permissionless_batches.Dockerfile (2)

17-19: Confusing binary naming convention

The source code is from /src/rollup/cmd/permissionless_batches/ but the binary is named rollup_relayer. This naming mismatch could lead to confusion.

Consider renaming the binary to match its source directory or add a comment explaining the naming convention:

RUN --mount=target=. \
    --mount=type=cache,target=/root/.cache/go-build \
-    cd /src/rollup/cmd/permissionless_batches/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/rollup_relayer
+    cd /src/rollup/cmd/permissionless_batches/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/permissionless_batches

Then update the entrypoint accordingly:

-COPY --from=builder /bin/rollup_relayer /bin/
+COPY --from=builder /bin/permissionless_batches /bin/
 WORKDIR /app
-ENTRYPOINT ["rollup_relayer"]
+ENTRYPOINT ["permissionless_batches"]

28-30: Missing default arguments or configuration

The ENTRYPOINT is set to the binary name without any CMD or default arguments, which could make it less user-friendly.

Consider adding a default CMD that provides help information:

COPY --from=builder /bin/rollup_relayer /bin/
WORKDIR /app
ENTRYPOINT ["rollup_relayer"]
+CMD ["--help"]

This would make the container more user-friendly by displaying help information when run without arguments.

permissionless-batches/docker-compose.yml (1)

120-121: Missing trailing newline & wrong indentation for volumes

YAML best practice (and many linters) expects a newline at EOF and two-space indentation of the root-level volumes: key. This prevents CI lint failures.

-volumes:
-    db_data:
+volumes:
+  db_data:
+
🧰 Tools
🪛 YAMLlint (1.35.1)

[warning] 121-121: wrong indentation: expected 2 but found 4

(indentation)


[error] 121-121: no new line character at the end of file

(new-line-at-end-of-file)

permissionless-batches/README.md (3)

1-4: Avoid duplicated heading phrase and tighten introduction

# Permissionless Batches Permissionless batches … repeats the phrase “Permissionless batches”. Remove the second occurrence to avoid redundancy and comply with Markdown-lint (PHRASE_REPETITION).

-# Permissionless Batches
-Permissionless batches aka enforced batches is ...
+# Permissionless Batches
+Permissionless (aka “enforced”) batches is ...
🧰 Tools
🪛 LanguageTool

[grammar] ~1-~1: This phrase is duplicated. You should probably use “Permissionless Batches” only once.
Context: # Permissionless Batches Permissionless batches aka enforced batches is a feature that ...

(PHRASE_REPETITION)


26-28: Grammar: use plural agreement

there's no blocksthere are no blocks.

🧰 Tools
🪛 LanguageTool

[grammar] ~26-~26: Did you mean “there are no blocks”?
Context: ...1 Once permissionless mode is activated there's no blocks being produced and propagated on L2. Th...

(THERE_S_MANY)


160-168: Specify language on fenced JSON blocks

markdownlint complains (MD040). Add json after the back-ticks so syntax highlighting and linting work:

-```
+```json
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

160-160: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


168-168: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

rollup/internal/orm/batch.go (1)

406-427: Unconditional timestamp/tx-hash updates may overwrite correct data

UpdateRollupStatusCommitAndFinalizeTxHash sets both commit and finalize timestamps/hashes regardless of status.
If the caller wants to update only one of them (e.g. RollupFinalized after commit), earlier commit information will be silently re-written.

Consider:
• Make the fields optional parameters (pointers) and update only when non-empty,
or
• Split into two focused helpers (UpdateCommit* and UpdateFinalize*) to mirror existing API.

rollup/internal/controller/relayer/full_recovery.go (1)

99-104: Generic container helper may clash with go-ethereum/common import

common.NewHeapMap[...] relies on an extension that is not present in upstream go-ethereum/common.
If your fork defines it, consider aliasing the import to avoid confusion:

import (
    ethcommon "github.com/scroll-tech/go-ethereum/common"
    "github.com/scroll-tech/go-ethereum/log"
    ...
)

Then adjust usages (ethcommon.NewHeapMap[...]) for clarity and to prevent accidental shadowing with the widely-known common package.

rollup/internal/controller/permissionless_batches/minimal_recovery.go (2)

47-61: Constructor name leaks abstraction & complicates test discovery

The exported constructor is called NewRecovery, yet it returns a pointer to MinimalRecovery.
a) From an API-design perspective this is misleading – the consumer does not know which flavour of recovery is being instantiated.
b) It also breaks the common Go idiom New<Type>(), making grepping for constructors or writing table-driven tests harder.

-func NewRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient) *MinimalRecovery {
+func NewMinimalRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB,
+	chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer,
+	bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient) *MinimalRecovery {

Renaming keeps public APIs self-describing and avoids potential clashes with any future “full” recovery constructor.


257-258: Left-over debug print pollutes stdout

fmt.Println(daBatch, daBlobPayload) sneaked into production code. This clutters logs and may dump large binary objects to the console.

-	fmt.Println(daBatch, daBlobPayload)
+	// fmt.Println removed – use structured log if necessary
rollup/internal/controller/permissionless_batches/submitter.go (1)

151-156: Logging raw calldata can expose sensitive data

On failure the error path logs the entire ABI-packed calldata as hex.
Depending on chain configuration this may leak user keys or proof bytes.

Consider trimming or hashing the payload before logging, e.g.:

log.Error("commitAndFinalize failed",
    "err", err,
    "calldataHash", crypto.Keccak256Hash(calldata),
)

[security]

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ac69be and 9d54bc2.

⛔ Files ignored due to path filters (2)
  • go.work is excluded by !**/*.work
  • go.work.sum is excluded by !**/*.sum
📒 Files selected for processing (30)
  • build/dockerfiles/coordinator-api.Dockerfile.dockerignore (1 hunks)
  • build/dockerfiles/coordinator-cron.Dockerfile.dockerignore (1 hunks)
  • build/dockerfiles/db_cli.Dockerfile.dockerignore (1 hunks)
  • build/dockerfiles/gas_oracle.Dockerfile.dockerignore (1 hunks)
  • build/dockerfiles/recovery_permissionless_batches.Dockerfile (1 hunks)
  • build/dockerfiles/recovery_permissionless_batches.Dockerfile.dockerignore (1 hunks)
  • build/dockerfiles/rollup_relayer.Dockerfile.dockerignore (1 hunks)
  • permissionless-batches/.gitignore (1 hunks)
  • permissionless-batches/README.md (1 hunks)
  • permissionless-batches/conf/coordinator/config.json (1 hunks)
  • permissionless-batches/conf/genesis.json (1 hunks)
  • permissionless-batches/conf/proving-service/config.json (1 hunks)
  • permissionless-batches/conf/relayer/config.json (1 hunks)
  • permissionless-batches/docker-compose.yml (1 hunks)
  • rollup/abi/bridge_abi_test.go (3 hunks)
  • rollup/cmd/permissionless_batches/app/app.go (1 hunks)
  • rollup/cmd/permissionless_batches/main.go (1 hunks)
  • rollup/cmd/rollup_relayer/app/app.go (2 hunks)
  • rollup/internal/config/config.go (1 hunks)
  • rollup/internal/config/recovery.go (1 hunks)
  • rollup/internal/controller/permissionless_batches/minimal_recovery.go (1 hunks)
  • rollup/internal/controller/permissionless_batches/submitter.go (1 hunks)
  • rollup/internal/controller/relayer/full_recovery.go (1 hunks)
  • rollup/internal/controller/relayer/l2_relayer.go (1 hunks)
  • rollup/internal/controller/watcher/bundle_proposer.go (4 hunks)
  • rollup/internal/controller/watcher/chunk_proposer.go (2 hunks)
  • rollup/internal/controller/watcher/l2_watcher.go (2 hunks)
  • rollup/internal/orm/batch.go (3 hunks)
  • rollup/internal/orm/bundle.go (4 hunks)
  • rollup/internal/orm/chunk.go (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
rollup/cmd/permissionless_batches/main.go (1)
rollup/cmd/permissionless_batches/app/app.go (1)
  • Run (137-142)
rollup/cmd/rollup_relayer/app/app.go (5)
rollup/internal/config/recovery.go (1)
  • RecoveryConfig (3-13)
rollup/internal/config/config.go (1)
  • Config (20-25)
rollup/internal/controller/relayer/full_recovery.go (1)
  • NewFullRecovery (40-58)
common/utils/utils.go (1)
  • LoopWithContext (34-45)
rollup/internal/utils/confirmation.go (1)
  • GetLatestConfirmedBlockNumber (18-56)
rollup/internal/controller/watcher/bundle_proposer.go (1)
rollup/internal/orm/batch.go (2)
  • Batch (25-75)
  • Batch (83-85)
rollup/internal/orm/bundle.go (3)
coordinator/internal/orm/bundle.go (2)
  • Bundle (17-45)
  • Bundle (53-55)
common/types/db.go (2)
  • RollupStatus (225-225)
  • RollupFinalized (239-239)
common/utils/timezone.go (1)
  • NowUTC (6-9)
rollup/internal/orm/batch.go (5)
coordinator/internal/orm/batch.go (2)
  • Batch (18-72)
  • Batch (80-82)
tests/integration-test/orm/batch.go (2)
  • Batch (17-60)
  • Batch (68-70)
rollup/internal/orm/chunk.go (2)
  • Chunk (23-67)
  • Chunk (75-77)
common/types/db.go (5)
  • ProvingStatus (140-140)
  • ProvingTaskVerified (152-152)
  • RollupStatus (225-225)
  • RollupFinalized (239-239)
  • GasOracleStatus (9-9)
common/utils/timezone.go (1)
  • NowUTC (6-9)
🪛 Biome (1.9.4)
permissionless-batches/conf/genesis.json

[error] 1-1: unexpected character <

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: unexpected character .

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: unexpected character >

(parse)

permissionless-batches/conf/relayer/config.json

[error] 49-49: unexpected character <

(parse)


[error] 49-49: expected , but instead found commit

Remove commit

(parse)


[error] 49-49: expected : but instead found tx

Remove tx

(parse)


[error] 49-49: expected , but instead found of

Remove of

(parse)


[error] 49-49: expected : but instead found last

Remove last

(parse)


[error] 49-49: expected , but instead found finalized

Remove finalized

(parse)


[error] 49-49: expected : but instead found batch

Remove batch

(parse)


[error] 49-49: expected , but instead found on

Remove on

(parse)


[error] 49-49: expected : but instead found L1

Remove L1

(parse)


[error] 49-49: unexpected character >

(parse)


[error] 50-50: unexpected character <

(parse)


[error] 50-50: expected , but instead found last

Remove last

(parse)


[error] 50-50: expected : but instead found finalized

Remove finalized

(parse)


[error] 50-50: expected , but instead found batch

Remove batch

(parse)


[error] 50-50: expected : but instead found on

Remove on

(parse)


[error] 50-50: expected , but instead found L1

Remove L1

(parse)


[error] 50-50: unexpected character >

(parse)


[error] 51-51: unexpected character <

(parse)


[error] 51-51: expected , but instead found L2

Remove L2

(parse)


[error] 51-51: expected : but instead found block

Remove block

(parse)


[error] 51-51: expected , but instead found up

Remove up

(parse)


[error] 51-51: expected : but instead found to

Remove to

(parse)


[error] 51-51: expected , but instead found which

Remove which

(parse)


[error] 51-51: expected : but instead found to

Remove to

(parse)


[error] 51-51: expected , but instead found produce

Remove produce

(parse)


[error] 51-51: expected : but instead found batch

Remove batch

(parse)


[error] 51-51: unexpected character >

(parse)

🪛 golangci-lint (1.64.8)
rollup/cmd/permissionless_batches/app/app.go

120-120: undefined: signal

(typecheck)

🪛 YAMLlint (1.35.1)
permissionless-batches/docker-compose.yml

[warning] 76-76: wrong indentation: expected 6 but found 10

(indentation)


[warning] 121-121: wrong indentation: expected 2 but found 4

(indentation)


[error] 121-121: no new line character at the end of file

(new-line-at-end-of-file)

🪛 GitHub Actions: Rollup
rollup/internal/controller/relayer/full_recovery.go

[error] 83-83: Compilation error: 'f.l1Reader.LatestFinalizedBatchIndex' undefined (type *l1.Reader has no field or method LatestFinalizedBatchIndex)

🪛 LanguageTool
permissionless-batches/README.md

[grammar] ~1-~1: This phrase is duplicated. You should probably use “Permissionless Batches” only once.
Context: # Permissionless Batches Permissionless batches aka enforced batches is a feature that ...

(PHRASE_REPETITION)


[duplication] ~14-~14: Possible typo: you repeated a word.
Context: ... state recovery from L1 2. l2geth block production 3. production, proving and submission of batch with `...

(ENGLISH_WORD_REPEAT_RULE)


[grammar] ~26-~26: Did you mean “there are no blocks”?
Context: ...1 Once permissionless mode is activated there's no blocks being produced and propagated on L2. Th...

(THERE_S_MANY)


[style] ~36-~36: To form a complete sentence, be sure to include a subject.
Context: ...` - batch where to start recovery from. Can be found on [Scrollscan Explorer](https...

(MISSING_IT_THERE)


[typographical] ~55-~55: It seems that a comma is missing.
Context: ... production to work. Once you generated blocks you can safely discard it. Running l2g...

(IF_COMMA)


[uncategorized] ~86-~86: Possible missing comma found.
Context: .... #### Producing a batch To produce a batch you need to run the `batch-production-s...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~95-~95: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...tes that everything is working correctly and the batch is ready to be proven. #### ...

(COMMA_COMPOUND_SENTENCE_2)


[uncategorized] ~98-~98: Possible missing comma found.
Context: ...ve the chunk, batch and bundle you just generated you need to run the proving profile i...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~109-~109: Possible missing comma found.
Context: .... #### Batch submission To submit the batch you need to run the `batch-production-s...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~117-~117: Possible missing comma found.
Context: ...ubleshooting** - in case the submission fails it will print the calldata for the tran...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~118-~118: Loose punctuation mark.
Context: ...0x4df567b9: ErrorNotInEnforcedBatchMode`: permissionless batch mode is not activa...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~119-~119: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... call`, permissionless mode is activated but you didn't provide a blob in the transa...

(COMMA_COMPOUND_SENTENCE)


[grammar] ~121-~121: This phrase is duplicated. You should probably use “Operator recovery” only once.
Context: ... provide a blob in the transaction. ## Operator recovery Operator recovery needs to be run by the rollup operator ...

(PHRASE_REPETITION)


[style] ~142-~142: To form a complete sentence, be sure to include a subject.
Context: ...` - batch where to start recovery from. Can be found on [Scrollscan Explorer](https...

(MISSING_IT_THERE)

🪛 markdownlint-cli2 (0.17.2)
permissionless-batches/README.md

103-103: Bare URL used
null

(MD034, no-bare-urls)


116-116: Emphasis used instead of a heading
null

(MD036, no-emphasis-as-heading)


160-160: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


168-168: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

🔇 Additional comments (31)
rollup/abi/bridge_abi_test.go (1)

8-9: No action required for import reordering
The gorm.io/gorm import was moved but this has no functional impact.

rollup/internal/controller/relayer/l2_relayer.go (1)

15-16: Import reordering only
The change moves the gorm.io/gorm import earlier; no behavioral change.

build/dockerfiles/coordinator-cron.Dockerfile.dockerignore (1)

8-8: Exclude permissionless-batches configuration from coordinator-cron build
Adding permissionless-batches/conf/ to .dockerignore ensures environment-specific configs aren’t sent to the Docker daemon, slimming the build context and avoiding accidental inclusion of sensitive files. This aligns with other Docker ignore patterns in the repo.

build/dockerfiles/coordinator-api.Dockerfile.dockerignore (1)

8-8: Exclude permissionless-batches configuration from coordinator-api build
Adding permissionless-batches/conf/ to .dockerignore prevents the inclusion of configuration files for permissionless batches in the coordinator-api image, reducing context size and potential misconfiguration. This mirrors the change in other service builds.

build/dockerfiles/gas_oracle.Dockerfile.dockerignore (1)

2-2: Exclude unnecessary directories from gas_oracle build context
The updates add contracts/ and permissionless-batches/conf/ to the ignore list (alongside the existing *target/*), which helps shrink the Docker build context by omitting large or irrelevant folders. This is consistent with other service Dockerfiles.

Also applies to: 6-6, 8-8

build/dockerfiles/db_cli.Dockerfile.dockerignore (1)

8-8: Exclude permissionless-batches configuration from db_cli build
Adding permissionless-batches/conf/ to .dockerignore keeps configuration files out of the db_cli Docker context, improving build performance and security. This change is in line with the patterns applied to other components.

build/dockerfiles/rollup_relayer.Dockerfile.dockerignore (1)

2-2: Exclude contracts and permissionless-batches configuration from rollup_relayer build
Ignoring contracts/ and permissionless-batches/conf/ (and existing *target/*) streamlines the Docker context for rollup_relayer, preventing extraneous files from being packaged. This matches updates in the other service Dockerfiles.

Also applies to: 6-6, 8-8

rollup/cmd/permissionless_batches/main.go (1)

1-7: LGTM - Simple and clean entry point for permissionless batches command.

The implementation follows Go's standard pattern for command-line applications by delegating to the app package. This creates a clear separation between the entry point and the actual implementation logic.

build/dockerfiles/recovery_permissionless_batches.Dockerfile.dockerignore (1)

1-8: LGTM - Appropriate Docker ignore patterns.

The file properly excludes unnecessary directories and files from the Docker build context, following best practices to reduce the build context size and speed up the build process.

rollup/internal/controller/watcher/chunk_proposer.go (2)

191-191: Method name changed to be publicly accessible for permissionless batches.

The method proposeChunk was renamed to ProposeChunk (capitalized) to make it publicly accessible, and the call site in TryProposeChunk was updated accordingly. This change enables the new permissionless batch production system to use this method.


271-430: Existing method now exposed as public API.

The method logic remains unchanged, but it's now publicly accessible with the capitalized name ProposeChunk. This is a key component for enabling the permissionless batches feature.

rollup/internal/controller/watcher/bundle_proposer.go (4)

12-13: Import reorganization for consistency.

The import for "gorm.io/gorm" was moved up to group with other imports, improving code organization.


103-127: Method name changed to be publicly accessible for permissionless batches.

The method updateDBBundleInfo was renamed to UpdateDBBundleInfo (capitalized) to make it publicly accessible. This change enables the new permissionless batch production system to update bundle information in the database.


198-198: Call site updated to use new public method name.

Updated to call the newly renamed UpdateDBBundleInfo method.


212-212: Call site updated to use new public method name.

Updated to call the newly renamed UpdateDBBundleInfo method.

rollup/cmd/rollup_relayer/app/app.go (2)

141-142:

✅ Verification successful

Updated code to ignore errors logged internally.

The change to ignore errors from TryFetchRunningMissingBlocks with a clarifying comment is appropriate if the method already handles error logging.

Let's check if the TryFetchRunningMissingBlocks method properly logs errors internally:


🏁 Script executed:

#!/bin/bash
# Check implementation of TryFetchRunningMissingBlocks to verify it logs errors internally

grep -A 25 "func.*TryFetchRunningMissingBlocks" rollup/internal/controller/watcher/l2_watcher.go | grep -B 3 -A 3 "log\.Error"

Length of output: 670


Approve ignoring errors from TryFetchRunningMissingBlocks

TryFetchRunningMissingBlocks already logs all error cases internally, so discarding its returned error here is safe and doesn’t lose any diagnostic information.

  • In rollup/internal/controller/watcher/l2_watcher.go, the method logs failures for both GetL2BlocksLatestHeight and GetAndStoreBlocks before returning an error.

111-132:

✅ Verification successful

Recovery mode implementation looks good.

The recovery mode implementation follows a good pattern, initializing necessary components and exiting early after completion. The error handling is appropriate.

Let's check if the FullRecovery component properly handles all expected recovery scenarios:


🏁 Script executed:

#!/bin/bash
# Check implementation of FullRecovery.RestoreFullPreviousState method

grep -A 30 "func.*RestoreFullPreviousState" rollup/internal/controller/relayer/full_recovery.go

Length of output: 1539


To review the full recovery logic, let’s extract the entire RestoreFullPreviousState implementation:


🏁 Script executed:

#!/bin/bash
grep -A200 "func (f \*FullRecovery) RestoreFullPreviousState" rollup/internal/controller/relayer/full_recovery.go

Length of output: 7709


Recovery mode and FullRecovery logic verified
The RestoreFullPreviousState method comprehensively handles all recovery steps—fetching the latest DB batch, querying finalized L1 blocks and batches, streaming and grouping rollup events, reproducing chunks, replaying L2 blocks, and rebuilding bundles. Error paths at each stage return meaningful errors, and no gaps in the recovery flow were identified.

permissionless-batches/conf/coordinator/config.json (1)

8-22:

❓ Verification inconclusive

Verifier configuration has identical paths for different circuit versions.

Both the low_version_circuit and high_version_circuit configurations point to the same parameter and asset paths. Make sure this is intentional.

If the different circuit versions require different parameters or assets, update the paths to be version-specific.


🏁 Script executed:

#!/bin/bash
# Check if the params and assets directories have version-specific subdirectories

ls -la permissionless-batches/conf/params/
ls -la permissionless-batches/conf/assets/

Length of output: 255


Let’s locate where any params and assets folders actually live and see all usages of those paths:

#!/bin/bash
# Search for any directories named 'params' or 'assets'
find . -type d | sed 's#^\./##' | grep -E 'params|assets'

# Show where and how params_path and assets_path are referenced
rg -n 'params_path' -A1
rg -n 'assets_path' -A1

Let’s locate every params and assets directory in the repo and inspect their contents to see if there are version‐specific subfolders:

#!/usr/bin/env bash
# Find all 'params' and 'assets' dirs
find . -type d \( -name 'params' -o -name 'assets' \) | sed 's#^\./##'

# For each found directory, list its contents
while read -r dir; do
  echo "Contents of $dir:"
  ls -la "$dir"
done < <(find . -type d \( -name 'params' -o -name 'assets' \))

Confirm circuit-specific parameter and asset paths

I wasn’t able to locate conf/params or conf/assets under permissionless-batches/conf. Both low_version_circuit and high_version_circuit reference ./conf/params and ./conf/assets, but these directories don’t seem to exist. Please verify:

  • Are the params and assets folders present at a different path or injected at build/runtime?
  • If each circuit version needs its own files, update the paths to something like ./conf/params/v4.4.55 and ./conf/params/v4.4.56.
rollup/internal/orm/chunk.go (1)

303-303: Good explanation for TotalL1MessagesPoppedInChunk value.

The comment explaining why TotalL1MessagesPoppedInChunk is set to 0 is very helpful and clarifies the intent.

rollup/internal/controller/watcher/l2_watcher.go (4)

62-63: Better error handling and propagation

The changes properly update TryFetchRunningMissingBlocks to return errors instead of silently logging them, which improves error propagation and enables callers to handle failures appropriately.

Also applies to: 67-68


78-81: Method made public and error propagation improved

The method rename from private getAndStoreBlocks to public GetAndStoreBlocks makes this functionality available to other packages, which is essential for the recovery workflows. The error handling is also appropriately improved.


85-87: Explicit return value

Adding an explicit return nil improves code clarity and maintains consistent error-returning behavior.


89-90: Renamed method to public

The method is now correctly exported with a capital letter, maintaining the same functionality while making it accessible to external packages.

permissionless-batches/conf/relayer/config.json (2)

1-47: Configuration structure looks appropriate

The configuration structure for the L1, L2, and database settings is well-organized and includes the necessary parameters for the permissionless batches relayer.


3-4: Document required RPC endpoints

The configuration contains placeholders for RPC endpoints but doesn't provide information about required permissions or capabilities.

Please ensure that the documentation clearly states:

  1. Required API methods that must be exposed by these endpoints
  2. Any specific permissions needed
  3. Performance requirements for these endpoints to handle the expected load

Also applies to: 7-8

rollup/internal/config/recovery.go (1)

3-13: Well-structured recovery configuration

The RecoveryConfig struct is well-defined with appropriate fields and JSON tags. The comments provide good context for the fields' purposes.

build/dockerfiles/recovery_permissionless_batches.Dockerfile (1)

1-30: Well-structured multi-stage Dockerfile

The Dockerfile uses multi-stage builds appropriately to minimize the final image size while including necessary dependencies.

rollup/internal/orm/bundle.go (1)

62-76: Exported name ✔ – implementation looks good

Renaming the method to GetLatestBundle and updating the doc-comment makes the API consistent with Go’s exported-identifier conventions. Query ordering and ErrRecordNotFound handling are both correct.

permissionless-batches/README.md (1)

18-24: Replace remaining TODO placeholders with concrete URLs before merge

The prerequisites list still contains several TODO link list with versions placeholders. Leaving these unresolved blocks readers and automation from locating the correct assets.

Action: supply final links (e.g. specific git-tag or docs permalink) or remove the bullet until ready.

rollup/internal/controller/permissionless_batches/minimal_recovery.go (1)

381-389: Verify that a blob client is always configured

blob_client.NewBlobClients() returns an aggregator with no underlying clients unless AddBlobClient is called.
If L1BeaconNodeEndpoint is empty the subsequent GetBlobByVersionedHashAndBlockTime will likely error out.

Please make sure at least one client is registered or fail fast with a clear message, e.g.:

blobs := blob_client.NewBlobClients()
if r.cfg.RecoveryConfig.L1BeaconNodeEndpoint == "" {
    return nil, nil, fmt.Errorf("no blob client configured – set L1BeaconNodeEndpoint")
}
rollup/internal/controller/permissionless_batches/submitter.go (1)

181-203: Non-proof finalisation updates proving status outside the main DB tx

When withProof == false the code updates proving status in a second transaction.
If the first tx (marking rollup finalising) commits but the second one fails, bundle and batches become stuck in an inconsistent state (finalising but not verified).

Consider merging both updates into the primary transaction or adding a compensation mechanism.

@yiweichi yiweichi marked this pull request as draft April 24, 2025 08:23
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.

7 participants