Skip to content

Conversation

@Thegaram
Copy link
Contributor

@Thegaram Thegaram commented Nov 26, 2025

Purpose or design rationale of this PR

Describe your change. Make sure to answer these three questions: What does this PR do? Why does it do it? How does it do it?

Add more logs.

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:

  • fix: A bug fix

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

  • Chores

    • Bumped release version to v4.7.6 and updated dependencies.
    • Switched several components to use raw RPC clients alongside typed clients; test helpers and call sites updated for the new return values.
  • New Features

    • Added configurable L1 base fee and blob base fee limits in config and enforcement to cap excessive values.
    • Added a Prometheus counter tracking fee-over-limit occurrences.
  • Bug Fixes / Diagnostics

    • Improved error logging around gas estimation and fee retrieval for better troubleshooting.
  • Tests

    • Updated tests to accommodate RPC-based flows and new client signatures.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

Adds raw RPC client wiring across sender, watcher, and tests; switches blob base-fee retrieval to eth_blobBaseFee RPC; bumps internal version tag to v4.7.6; enhances gas estimate error logging to include the full message payload; updates tests and consumers to return/accept *rpc.Client alongside *ethclient.Client.

Changes

Cohort / File(s) Summary
Version bump
common/version/version.go
Updated internal tag from "v4.7.5" to "v4.7.6", changing the exported Version.
Sender — RPC wiring & blob fee
rollup/internal/controller/sender/sender.go
Added rpcClient *rpc.Client field and initialization in NewSender; retrieve blob base fee via eth_blobBaseFee RPC (hexutil.Big) instead of local calc; retained gethClient for access-list creation; import adjustments.
Gas estimation logging
rollup/internal/controller/sender/estimategas.go
Added fmt import; enhanced EstimateGas error logging to include the full message payload via fmt.Sprintf("%+v", msg).
Testcontainers — return raw RPC client
common/testcontainers/testcontainers.go, common/testcontainers/testcontainers_test.go
GetPoSL1Client and GetL2GethClient signatures changed to return (*rpc.Client, *ethclient.Client, error); callsites updated to accept or ignore the new raw RPC client.
L1 watcher — RPC-based blob fee
rollup/internal/controller/watcher/l1_watcher.go, .../l1_watcher_test.go
NewL1WatcherClient now accepts *rpc.Client; L1WatcherClient stores rpcClient and derives ethclient.NewClient(rpcClient); blob base fee retrieved via eth_blobBaseFee RPC.
Gas oracle app & CLI wiring
rollup/cmd/gas_oracle/app/app.go
Dial L1 with rpc.Dial(...) and wrap via ethclient.NewClient(...); pass raw RPC client to watcher.
Relayer config & caps
rollup/internal/config/relayer.go, rollup/internal/controller/relayer/l1_relayer.go, .../l1_relayer_metrics.go
Added L1BaseFeeLimit and L1BlobBaseFeeLimit config fields; relayer caps baseFee/blobBaseFee to those limits and increments a new Prometheus counter rollup_layer1_gas_price_oracle_fee_over_limit_total.
Tests — adapt to raw RPC returns
rollup/internal/controller/*/*_test.go, rollup/tests/*, tests/integration-test/*
Many tests updated to accept or ignore the additional *rpc.Client return values; some pass raw RPC client into watcher constructors.
Module deps
rollup/go.mod
Added direct dependency github.com/ethereum/go-ethereum v1.10.26; bumped indirect github.com/deckarep/golang-set to v1.8.0.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Sender
  participant Geth as gethclient (ethclient)
  participant RPC as Raw RPC (rpc.Client)
  participant Est as Estimator

  Note over Sender,Geth: Header fetch unchanged (baseFee from header)
  Sender->>Geth: Fetch header (blockNumber, timestamp, baseFee)
  Geth-->>Sender: Header

  Note over Sender,RPC: New: blob base-fee via RPC call
  Sender->>RPC: eth_blobBaseFee (blockNumber / pending)
  RPC-->>Sender: blobBaseFee (hexutil.Big)

  Sender->>Est: EstimateGas(msg, baseFee, blobBaseFee)
  Est-->>Sender: gasEstimate / error
  Note right of Est: Errors are logged with full msg via fmt.Sprintf("%+v", msg)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas needing attention:
    • Correct parsing/usage of hexutil.Big returned by eth_blobBaseFee.
    • Proper lifecycle (dial/close) and propagation of *rpc.Client across constructors and tests.
    • Verify new config caps logic and metric increments in relayer (edge cases and bounds).
    • Ensure enhanced logging does not leak sensitive payloads in production logs.

Possibly related PRs

Suggested labels

bump-version

Suggested reviewers

  • georgehao
  • yiweichi
  • jonastheis

Poem

🐰 I hopped through RPC pipes, a fee to find,
Asked eth_blobBaseFee to ease my mind.
Version bumped, logs gleam bright,
Tests adapted — code feels light.
The rabbit nods, and munches a byte. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'fix(sender): log msg on error' is a valid conventional commit that partially captures the main change — enhanced error logging in the sender module — but fails to reflect the broader scope of this PR. Update title to accurately capture the primary changes: refactoring sender and watcher to use raw RPC clients instead of direct ethclient instances for blob base fee retrieval, version bump, and config extensions. Consider: 'fix(sender/watcher): retrieve blob base fee via RPC client'
Description check ⚠️ Warning The PR description is incomplete, containing only a vague statement 'Add more logs' without addressing the template's requirement to explain what the PR does, why, and how. Provide comprehensive details: (1) What: the PR refactors sender/watcher to use raw RPC clients for blob base fee retrieval and adds config limits; (2) Why: to improve robustness and monitoring; (3) How: by introducing rpc.Client dependencies and RPC-based eth_blobBaseFee calls. Verify version bump was applied.
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-sender-log-msg-on-error

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

yiweichi
yiweichi previously approved these changes Nov 26, 2025
frisitano
frisitano previously approved these changes Nov 26, 2025
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ecc42e and cfe6fd2.

📒 Files selected for processing (2)
  • common/version/version.go (1 hunks)
  • rollup/internal/controller/sender/estimategas.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: tests
  • GitHub Check: check
  • GitHub Check: tests
🔇 Additional comments (2)
rollup/internal/controller/sender/estimategas.go (1)

5-5: LGTM!

The fmt import is necessary for the enhanced logging on line 122.

common/version/version.go (1)

8-8: LGTM!

Version bump from v4.7.5 to v4.7.6 is appropriate for this fix.

@codecov-commenter
Copy link

codecov-commenter commented Nov 26, 2025

Codecov Report

❌ Patch coverage is 45.45455% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 36.54%. Comparing base (2ecc42e) to head (a20959c).

Files with missing lines Patch % Lines
common/testcontainers/testcontainers.go 50.00% 4 Missing and 1 partial ⚠️
rollup/internal/controller/sender/estimategas.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #1769   +/-   ##
========================================
  Coverage    36.53%   36.54%           
========================================
  Files          247      247           
  Lines        21188    21180    -8     
========================================
- Hits          7742     7741    -1     
+ Misses       12616    12610    -6     
+ Partials       830      829    -1     
Flag Coverage Δ
common 29.62% <50.00%> (-0.07%) ⬇️
coordinator 32.77% <ø> (+0.18%) ⬆️
database 42.05% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Thegaram Thegaram dismissed stale reviews from frisitano and yiweichi via 2880bd5 November 26, 2025 19:43
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: 0

♻️ Duplicate comments (1)
rollup/internal/controller/sender/estimategas.go (1)

123-123: Reconsider logging the full message payload.

Logging the complete msg structure with fmt.Sprintf("%+v", msg) introduces significant concerns:

  1. Privacy/Compliance Risk: The Data field may contain sensitive transaction payloads or user identifiers. Logging full calldata violates best practices for handling potentially sensitive data.
  2. Log Volume: Transaction calldata can be extremely large, especially for blob transactions, which will bloat logs significantly during error conditions.

Per the previous review, consider logging only essential fields that aren't already covered by caller logs (From, nonce, To are already logged elsewhere). If debugging requires the Data field, log its length or a truncated version.

Apply this diff to log selective fields:

-		log.Error("estimateGasLimit EstimateGas failure without access list", "error", err, "msg", fmt.Sprintf("%+v", msg))
+		log.Error("estimateGasLimit EstimateGas failure without access list", "error", err, 
+			"gasPrice", msg.GasPrice, "gasTipCap", msg.GasTipCap, "gasFeeCap", msg.GasFeeCap, 
+			"blobGasFeeCap", msg.BlobGasFeeCap, "dataLen", len(msg.Data), "blobHashCount", len(msg.BlobHashes))
🧹 Nitpick comments (4)
rollup/internal/controller/sender/sender.go (3)

837-838: Use appropriate log level for informational data.

This log uses Warn level to record routine operational data (block number). Since this function is called frequently in normal operation, warning-level logs will create noise and obscure genuine issues. Use log.Debug or log.Info instead, and consider removing the redundant function name from the message.

Apply this diff:

-	log.Warn("getBlockNumberAndTimestampAndBaseFeeAndBlobFee", "number", header.Number.Uint64())
+	log.Debug("retrieved block header", "number", header.Number.Uint64())

842-842: Use appropriate log level and avoid redundant value logging.

This log uses Warn level for routine base fee data and logs the same value in both string and uint64 formats. Use log.Debug or log.Info instead, and choose one representation to reduce log volume.

Apply this diff:

-		log.Warn("getBlockNumberAndTimestampAndBaseFeeAndBlobFee", "baseFee", header.BaseFee.String(), "baseFeeUint64", baseFee)
+		log.Debug("retrieved base fee", "baseFee", baseFee)

848-848: Use appropriate log level and avoid redundant value logging.

This log uses Warn level for routine blob base fee data and logs the same value in both string and uint64 formats. Use log.Debug or log.Info instead, and choose one representation to reduce log volume.

Apply this diff:

-		log.Warn("getBlockNumberAndTimestampAndBaseFeeAndBlobFee", "blobBaseFee", misc.CalcBlobFee(*excess).String(), "blobBaseFeeUint64", blobBaseFee)
+		log.Debug("retrieved blob base fee", "blobBaseFee", blobBaseFee)
rollup/internal/controller/sender/estimategas.go (1)

85-85: Use appropriate log level for gas estimation data.

This log uses Warn level to record routine gas estimation parameters. Warning-level logs should be reserved for conditions that require attention. Use log.Debug or log.Info for normal operational data.

Apply this diff:

-	log.Warn("estimateBlobGas", "blobBaseFee", blobBaseFee, "blobGasFeeCap", blobGasFeeCap.String())
+	log.Debug("estimated blob gas fees", "blobBaseFee", blobBaseFee, "blobGasFeeCap", blobGasFeeCap.String())
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfe6fd2 and 2880bd5.

📒 Files selected for processing (2)
  • rollup/internal/controller/sender/estimategas.go (3 hunks)
  • rollup/internal/controller/sender/sender.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-18T06:49:24.796Z
Learnt from: Thegaram
Repo: scroll-tech/scroll PR: 1746
File: rollup/internal/controller/sender/sender.go:637-640
Timestamp: 2025-10-18T06:49:24.796Z
Learning: In the file `rollup/internal/controller/sender/sender.go`, the resubmission logic in `createReplacingTransaction` does not convert V0 blob sidecars to V1 when resubmitting transactions after the Fusaka upgrade. This is an accepted edge case because it's unlikely to occur, geth is expected to handle it gracefully, and manual recovery is available if needed.

Applied to files:

  • rollup/internal/controller/sender/sender.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: bridgehistoryapi-db-cli
  • GitHub Check: rollup-db-cli
  • GitHub Check: bridgehistoryapi-api
  • GitHub Check: coordinator-cron
  • GitHub Check: coordinator-api
  • GitHub Check: bridgehistoryapi-fetcher
  • GitHub Check: blob_uploader
  • GitHub Check: gas_oracle
  • GitHub Check: rollup_relayer
  • GitHub Check: check
  • GitHub Check: tests
  • GitHub Check: tests

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2880bd5 and 93604d9.

📒 Files selected for processing (1)
  • rollup/internal/controller/sender/sender.go (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-18T06:49:24.796Z
Learnt from: Thegaram
Repo: scroll-tech/scroll PR: 1746
File: rollup/internal/controller/sender/sender.go:637-640
Timestamp: 2025-10-18T06:49:24.796Z
Learning: In the file `rollup/internal/controller/sender/sender.go`, the resubmission logic in `createReplacingTransaction` does not convert V0 blob sidecars to V1 when resubmitting transactions after the Fusaka upgrade. This is an accepted edge case because it's unlikely to occur, geth is expected to handle it gracefully, and manual recovery is available if needed.

Applied to files:

  • rollup/internal/controller/sender/sender.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: rollup-db-cli
  • GitHub Check: bridgehistoryapi-api
  • GitHub Check: bridgehistoryapi-fetcher
  • GitHub Check: blob_uploader
  • GitHub Check: rollup_relayer
  • GitHub Check: gas_oracle
  • GitHub Check: coordinator-cron
  • GitHub Check: bridgehistoryapi-db-cli
  • GitHub Check: coordinator-api
  • GitHub Check: tests
  • GitHub Check: check
  • GitHub Check: tests

frisitano
frisitano previously approved these changes Nov 26, 2025
yiweichi
yiweichi previously approved these changes Nov 26, 2025
@Thegaram Thegaram dismissed stale reviews from yiweichi and frisitano via 692fd0f November 26, 2025 20:52
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: 1

♻️ Duplicate comments (1)
rollup/internal/controller/sender/estimategas.go (1)

122-122: Reconsider logging the full message payload.

This change logs the complete msg structure, which raises the same concerns previously identified:

  1. Privacy/Compliance Risk: The Data field may contain sensitive transaction payloads or user identifiers that should not be logged per compliance best practices.
  2. Log Volume: Transaction calldata can be extremely large, especially for blob transactions, potentially bloating logs significantly during error conditions.

Consider logging only non-sensitive, essential fields (gas parameters, data length, blob hash count) instead of the full message dump.

Based on the existing review comment and coding best practices.

🧹 Nitpick comments (4)
rollup/tests/bridge_test.go (1)

41-44: Unused RPC clients declared at package level.

l1RawClient and l2RawClient are captured from the new triple-return API but appear unused in this file. If these are intentionally reserved for future use, consider adding a brief comment. Otherwise, use blank identifiers (_) as done in other test files to avoid confusion.

 	// clients
-	l1RawClient *rpc.Client
-	l1Client    *ethclient.Client
-	l2RawClient *rpc.Client
-	l2Client    *ethclient.Client
+	l1Client *ethclient.Client
+	l2Client *ethclient.Client

And in setupEnv:

-	l1RawClient, l1Client, err = testApps.GetPoSL1Client()
+	_, l1Client, err = testApps.GetPoSL1Client()
 	assert.NoError(t, err)
-	l2RawClient, l2Client, err = testApps.GetL2GethClient()
+	_, l2Client, err = testApps.GetL2GethClient()

Also applies to: 97-99

rollup/internal/controller/watcher/l1_watcher.go (3)

23-33: Consider naming the eth client field more explicitly

Storing both rpcClient *rpc.Client and client *ethclient.Client on L1WatcherClient is reasonable. For readability, you might consider renaming clientethClient to make it obvious at call sites which client is being used, especially now that both live on the struct.


35-56: Constructor wiring from raw RPC client looks correct; optionally guard/document nil

The updated constructor that accepts *rpc.Client and derives an *ethclient.Client via ethclient.NewClient(rpcClient) is a clean way to centralize wiring. Behavior around a nil rpcClient remains unchecked, similar to the prior *ethclient.Client usage; if this is a programming precondition, consider either:

  • adding a fast if rpcClient == nil { panic(...) } / early return, or
  • documenting the non-nil requirement in a comment.

Otherwise the initialization and persisted height logic look unchanged and correct.


80-95: RPC-based blob base fee retrieval is fine; consider logging and compatibility

Switching from local CalcBlobFee to an eth_blobBaseFee RPC call via w.rpcClient.CallContext(w.ctx, &hex, "eth_blobBaseFee") is reasonable, and the hexutil.Big usage plus Uint64() conversion look correct.

Two things to double-check:

  • Runtime compatibility: ensure all L1 nodes you target actually support eth_blobBaseFee; otherwise this will now hard-fail where the previous local computation would have continued to work.
  • Observability: today, on error you just return fmt.Errorf(...) without logging. Given this is watcher infra, adding a log.Warn (with method name and maybe height context) before returning could make debugging much easier.

If you’re confident about node support and have higher-level logging, this can stay as-is.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 93604d9 and 692fd0f.

⛔ Files ignored due to path filters (1)
  • rollup/go.sum is excluded by !**/*.sum
📒 Files selected for processing (14)
  • common/testcontainers/testcontainers.go (2 hunks)
  • common/testcontainers/testcontainers_test.go (1 hunks)
  • rollup/cmd/gas_oracle/app/app.go (1 hunks)
  • rollup/go.mod (2 hunks)
  • rollup/internal/controller/relayer/relayer_test.go (1 hunks)
  • rollup/internal/controller/sender/estimategas.go (2 hunks)
  • rollup/internal/controller/sender/sender.go (4 hunks)
  • rollup/internal/controller/sender/sender_test.go (1 hunks)
  • rollup/internal/controller/watcher/l1_watcher.go (5 hunks)
  • rollup/internal/controller/watcher/l1_watcher_test.go (1 hunks)
  • rollup/tests/bridge_test.go (3 hunks)
  • rollup/tests/gas_oracle_test.go (2 hunks)
  • tests/integration-test/contracts_test.go (2 hunks)
  • tests/integration-test/integration_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-18T06:49:24.796Z
Learnt from: Thegaram
Repo: scroll-tech/scroll PR: 1746
File: rollup/internal/controller/sender/sender.go:637-640
Timestamp: 2025-10-18T06:49:24.796Z
Learning: In the file `rollup/internal/controller/sender/sender.go`, the resubmission logic in `createReplacingTransaction` does not convert V0 blob sidecars to V1 when resubmitting transactions after the Fusaka upgrade. This is an accepted edge case because it's unlikely to occur, geth is expected to handle it gracefully, and manual recovery is available if needed.

Applied to files:

  • rollup/internal/controller/sender/sender_test.go
  • rollup/internal/controller/sender/sender.go
  • rollup/internal/controller/relayer/relayer_test.go
🧬 Code graph analysis (3)
rollup/tests/gas_oracle_test.go (1)
rollup/internal/controller/watcher/l1_watcher.go (1)
  • NewL1WatcherClient (36-56)
rollup/cmd/gas_oracle/app/app.go (2)
rollup/internal/config/l1.go (1)
  • L1Config (4-14)
rollup/internal/controller/watcher/l1_watcher.go (1)
  • NewL1WatcherClient (36-56)
rollup/internal/controller/watcher/l1_watcher_test.go (2)
rollup/internal/config/l1.go (1)
  • L1Config (4-14)
rollup/internal/controller/watcher/l1_watcher.go (1)
  • NewL1WatcherClient (36-56)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: tests
  • GitHub Check: check
  • GitHub Check: tests
  • GitHub Check: tests
  • GitHub Check: tests
  • GitHub Check: tests
  • GitHub Check: goimports-lint
  • GitHub Check: check
  • GitHub Check: check
🔇 Additional comments (16)
rollup/internal/controller/sender/estimategas.go (1)

5-5: Import added for enhanced logging.

The fmt import supports the new logging format at Line 122.

rollup/go.mod (1)

55-55: Dependency upgrade noted.

The upgrade of github.com/deckarep/golang-set from a pseudo-version to v1.8.0 is a standard version resolution.

rollup/cmd/gas_oracle/app/app.go (1)

69-76: RPC client wiring updated correctly.

The changes properly introduce raw RPC client dialing and pass it to the L1 watcher, aligning with the broader RPC-based flow in this PR. The error message accurately reflects the change from Eth client to raw RPC endpoint.

common/testcontainers/testcontainers.go (2)

171-180: Public API signature change handled correctly.

GetPoSL1Client now returns both the raw RPC client and the wrapped ethclient, following a consistent pattern. The error handling properly returns nil, nil, err on failure.

Note: This is a breaking change for all callers, but the PR shows that dependent test files have been updated accordingly.


227-233: Public API signature change handled correctly.

GetL2GethClient now returns both the raw RPC client and the wrapped ethclient, mirroring the pattern used in GetPoSL1Client. The implementation correctly leverages the existing GetL2Client() method.

rollup/tests/gas_oracle_test.go (2)

113-113: L1 watcher instantiation updated correctly.

Consistent with the change at Line 39, properly passing l1RawClient to the constructor.


39-39: Perfect! I found the complete flow. The gas oracle test functions are called from TestFunction in bridge_test.go, which explicitly calls setupEnv(t) at the beginning. This ensures that l1RawClient and other package-level variables are properly initialized before the gas oracle tests execute.

Verification complete: l1RawClient is properly initialized.

The test execution flow is:

  1. TestFunction() calls setupEnv(t) (line 203 in bridge_test.go)
  2. setupEnv() initializes l1RawClient via testApps.GetPoSL1Client() (line 63 in bridge_test.go)
  3. Test subtests run via t.Run(), including testImportL1GasPrice and testImportDefaultL1GasPriceDueToL1GasPriceSpike
  4. Both gas oracle tests can now safely use the initialized l1RawClient package-level variable

The review comment's approval of the code changes is justified.

rollup/internal/controller/watcher/l1_watcher_test.go (1)

24-28: Test setup updated for new API signature.

The test correctly unpacks the three return values from GetPoSL1Client, capturing the RPC client and discarding the ethclient (which the watcher internally creates). The RPC client is properly passed to NewL1WatcherClient.

rollup/internal/controller/sender/sender_test.go (1)

97-98: Test updated for new API signature.

The test correctly unpacks the three return values from GetPoSL1Client, appropriately discarding the RPC client (first return value) since only the ethclient is needed for the test operations.

tests/integration-test/integration_test.go (1)

82-85: Test updated for new API signature.

The test correctly unpacks the three return values from GetL2GethClient, discarding the RPC client since only the ethclient is required for header retrieval and subsequent operations.

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

77-78: LGTM!

The update correctly adapts to the new GetL2GethClient() triple-return signature by discarding the unused RPC client.

tests/integration-test/contracts_test.go (1)

27-28: LGTM!

Both calls correctly adapt to the new GetL2GethClient() API signature.

Also applies to: 66-67

common/testcontainers/testcontainers_test.go (1)

35-37: LGTM!

The test correctly adapts to the updated API signatures for both GetL2GethClient() and GetPoSL1Client().

Also applies to: 43-45

rollup/internal/controller/sender/sender.go (2)

70-71: LGTM!

The new rpcClient field is properly initialized in NewSender and correctly wired to the gethClient via gethclient.New(rpcClient). This enables the RPC-based blob base fee retrieval.

Also applies to: 145-146


844-856: Good rationale for switching to RPC-based blob base fee retrieval.

The comment clearly documents why the RPC call is preferred over local CalcBlobFee calculation (L1 node configuration sync issues) and acknowledges the acceptable timing mismatch. The implementation correctly handles the eth_blobBaseFee response using hexutil.Big.

rollup/internal/controller/watcher/l1_watcher.go (1)

3-20: Confirm mixed go-ethereum import paths are intentional

This file now pulls hexutil from github.com/ethereum/go-ethereum/common/hexutil while using the scroll-tech fork for core/types, ethclient, and rpc. Please confirm this mix is deliberate and you don’t instead want github.com/scroll-tech/go-ethereum/common/hexutil for consistency and to avoid potential version skew.

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 692fd0f and a20959c.

📒 Files selected for processing (7)
  • common/testcontainers/testcontainers.go (2 hunks)
  • rollup/internal/config/relayer.go (1 hunks)
  • rollup/internal/controller/relayer/l1_relayer.go (1 hunks)
  • rollup/internal/controller/relayer/l1_relayer_metrics.go (2 hunks)
  • rollup/internal/controller/sender/sender.go (4 hunks)
  • rollup/internal/controller/watcher/l1_watcher.go (5 hunks)
  • rollup/tests/bridge_test.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • rollup/tests/bridge_test.go
  • rollup/internal/controller/sender/sender.go
  • common/testcontainers/testcontainers.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-18T06:49:24.796Z
Learnt from: Thegaram
Repo: scroll-tech/scroll PR: 1746
File: rollup/internal/controller/sender/sender.go:637-640
Timestamp: 2025-10-18T06:49:24.796Z
Learning: In the file `rollup/internal/controller/sender/sender.go`, the resubmission logic in `createReplacingTransaction` does not convert V0 blob sidecars to V1 when resubmitting transactions after the Fusaka upgrade. This is an accepted edge case because it's unlikely to occur, geth is expected to handle it gracefully, and manual recovery is available if needed.

Applied to files:

  • rollup/internal/controller/relayer/l1_relayer.go
🧬 Code graph analysis (2)
rollup/internal/controller/relayer/l1_relayer.go (1)
rollup/internal/config/relayer.go (1)
  • GasOracleConfig (99-118)
rollup/internal/controller/relayer/l1_relayer_metrics.go (1)
common/observability/ginmetrics/types.go (2)
  • Counter (18-18)
  • Gauge (20-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: tests
  • GitHub Check: check
  • GitHub Check: tests
  • GitHub Check: tests
  • GitHub Check: check
  • GitHub Check: tests
  • GitHub Check: tests
  • GitHub Check: check
🔇 Additional comments (6)
rollup/internal/controller/relayer/l1_relayer_metrics.go (1)

16-16: LGTM! Metric addition is well-structured.

The new counter metric follows the established naming convention and is properly initialized. The metric will correctly track when gas oracle fees exceed configured limits.

Also applies to: 47-50

rollup/internal/controller/watcher/l1_watcher.go (5)

6-6: LGTM!

The import additions are necessary and correctly support the RPC-based blob base fee retrieval.

Also applies to: 10-10, 14-14


25-26: LGTM!

Maintaining both the raw RPC client and the typed SDK client is a sound design pattern that enables flexibility for both low-level RPC calls (like eth_blobBaseFee) and high-level typed operations.


49-50: LGTM!

The constructor implementation correctly stores the raw RPC client and derives the typed client using the standard ethclient.NewClient pattern.


85-95: eth_blobBaseFee is a valid standard RPC method; overflow concern is mitigated by documented assumption.

The RPC method is confirmed as part of EIP-4844 and is supported by mainstream Ethereum clients (Geth, Besu, reth).

Regarding overflow handling: the code explicitly documents via comment that "A correct L1 node could not return a value that overflows uint64". While the suggested overflow check would be more defensive, the pattern is consistent with the identical implementation in sender.go:854 and reflects an intentional design decision. The blob base fee is economically bounded in practice, making overflow unlikely to occur in production scenarios.

If you prefer defensive programming over trusting node behavior, the suggested overflow check remains valid:

 	// A correct L1 node could not return a value that overflows uint64
-	blobBaseFee := blobBaseFeeHex.ToInt().Uint64()
+	blobBaseFeeInt := blobBaseFeeHex.ToInt()
+	if !blobBaseFeeInt.IsUint64() {
+		return fmt.Errorf("blob base fee %s exceeds uint64 max", blobBaseFeeInt.String())
+	}
+	blobBaseFee := blobBaseFeeInt.Uint64()

36-36: All callers of NewL1WatcherClient have been properly updated to pass *rpc.Client.

Verification confirms that all five call sites correctly pass the raw RPC client:

  1. rollup/cmd/gas_oracle/app/app.go:75 — passes l1RpcClient created via rpc.Dial()*rpc.Client
  2. rollup/internal/controller/watcher/l1_watcher_test.go:27 — passes rawClient from testApps.GetPoSL1Client() (first return) → *rpc.Client
  3. rollup/tests/gas_oracle_test.go:39, 113 — pass l1RawClient from testApps.GetPoSL1Client() (first return) → *rpc.Client

The test infrastructure method GetPoSL1Client() in common/testcontainers/testcontainers.go:171 explicitly returns (*rpc.Client, *ethclient.Client, error), and all callers correctly extract and use the first return value.

Comment on lines +176 to +186
// set limit
if baseFee > r.cfg.GasOracleConfig.L1BaseFeeLimit {
log.Error("L1 base fee exceed max limit, set to max limit", "baseFee", baseFee, "maxLimit", r.cfg.GasOracleConfig.L1BaseFeeLimit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
baseFee = r.cfg.GasOracleConfig.L1BaseFeeLimit
}
if blobBaseFee > r.cfg.GasOracleConfig.L1BlobBaseFeeLimit {
log.Error("L1 blob base fee exceed max limit, set to max limit", "blobBaseFee", blobBaseFee, "maxLimit", r.cfg.GasOracleConfig.L1BlobBaseFeeLimit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
blobBaseFee = r.cfg.GasOracleConfig.L1BlobBaseFeeLimit
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Fee capping logic requires validation of limit values.

This enforcement logic unconditionally compares fees against configured limits without checking if the limits are valid (non-zero). As noted in the config file review, if L1BaseFeeLimit or L1BlobBaseFeeLimit are 0 (their default values when unconfigured), this code will cap all non-zero fees to 0, breaking the gas oracle.

Add validation before the comparison:

 		}
+		// Only enforce limits if they are configured (non-zero)
+		if r.cfg.GasOracleConfig.L1BaseFeeLimit > 0 && baseFee > r.cfg.GasOracleConfig.L1BaseFeeLimit {
-		if baseFee > r.cfg.GasOracleConfig.L1BaseFeeLimit {
 			log.Error("L1 base fee exceed max limit, set to max limit", "baseFee", baseFee, "maxLimit", r.cfg.GasOracleConfig.L1BaseFeeLimit)
 			r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
 			baseFee = r.cfg.GasOracleConfig.L1BaseFeeLimit
 		}
+		if r.cfg.GasOracleConfig.L1BlobBaseFeeLimit > 0 && blobBaseFee > r.cfg.GasOracleConfig.L1BlobBaseFeeLimit {
-		if blobBaseFee > r.cfg.GasOracleConfig.L1BlobBaseFeeLimit {
 			log.Error("L1 blob base fee exceed max limit, set to max limit", "blobBaseFee", blobBaseFee, "maxLimit", r.cfg.GasOracleConfig.L1BlobBaseFeeLimit)
 			r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
 			blobBaseFee = r.cfg.GasOracleConfig.L1BlobBaseFeeLimit
 		}

Alternative: Validate limits at initialization time in NewLayer1Relayer (line 50) to ensure they're configured with sensible values before the relayer starts.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// set limit
if baseFee > r.cfg.GasOracleConfig.L1BaseFeeLimit {
log.Error("L1 base fee exceed max limit, set to max limit", "baseFee", baseFee, "maxLimit", r.cfg.GasOracleConfig.L1BaseFeeLimit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
baseFee = r.cfg.GasOracleConfig.L1BaseFeeLimit
}
if blobBaseFee > r.cfg.GasOracleConfig.L1BlobBaseFeeLimit {
log.Error("L1 blob base fee exceed max limit, set to max limit", "blobBaseFee", blobBaseFee, "maxLimit", r.cfg.GasOracleConfig.L1BlobBaseFeeLimit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
blobBaseFee = r.cfg.GasOracleConfig.L1BlobBaseFeeLimit
}
// set limit
// Only enforce limits if they are configured (non-zero)
if r.cfg.GasOracleConfig.L1BaseFeeLimit > 0 && baseFee > r.cfg.GasOracleConfig.L1BaseFeeLimit {
log.Error("L1 base fee exceed max limit, set to max limit", "baseFee", baseFee, "maxLimit", r.cfg.GasOracleConfig.L1BaseFeeLimit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
baseFee = r.cfg.GasOracleConfig.L1BaseFeeLimit
}
if r.cfg.GasOracleConfig.L1BlobBaseFeeLimit > 0 && blobBaseFee > r.cfg.GasOracleConfig.L1BlobBaseFeeLimit {
log.Error("L1 blob base fee exceed max limit, set to max limit", "blobBaseFee", blobBaseFee, "maxLimit", r.cfg.GasOracleConfig.L1BlobBaseFeeLimit)
r.metrics.rollupL1RelayerGasPriceOracleFeeOverLimitTotal.Inc()
blobBaseFee = r.cfg.GasOracleConfig.L1BlobBaseFeeLimit
}
🤖 Prompt for AI Agents
In rollup/internal/controller/relayer/l1_relayer.go around lines 176 to 186, the
fee capping compares baseFee and blobBaseFee against configured limits without
validating those limits, so a zero (unset) limit will incorrectly cap fees to 0;
update the logic to first check that r.cfg.GasOracleConfig.L1BaseFeeLimit and
L1BlobBaseFeeLimit are > 0 before applying the cap (skip capping and avoid
incrementing the over-limit metric when the limit is non-positive), and/or add
validation in NewLayer1Relayer (around line 50) to enforce sensible, non-zero
defaults or return an error if limits are unset so the relayer never runs with
zero limits.

@Thegaram
Copy link
Contributor Author

Closing in favor of #1772.

@Thegaram Thegaram closed this Nov 27, 2025
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.

5 participants