Skip to content

Conversation

@luiz-lvj
Copy link
Collaborator

@luiz-lvj luiz-lvj commented Jan 23, 2026

This PR changes the pushHashes function signatures on IPusher in order to receive the buffer as a parameter. This change allows for removal of the Ownable dependency on the Buffers.

Summary by CodeRabbit

  • Documentation

    • Updated usage examples in README to reflect revised API signatures.
  • Refactor

    • Modified pushHashes() to require explicit buffer address as first parameter across all pusher implementations.
    • Updated constructor signatures to initialize pusher address at deployment time.
    • Removed bufferAddress() getter function across pusher contracts.

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

@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

This PR refactors the block-hash-pusher architecture by making the buffer address a dynamic parameter in pushHashes() calls rather than stored at deployment. It eliminates Ownable-based initialization in buffer contracts, replacing the setPusherAddress() setter pattern with direct constructor injection of the pusher address.

Changes

Cohort / File(s) Summary
Interface Update
src/contracts/block-hash-pusher/interfaces/IPusher.sol
Added InvalidBuffer error; updated pushHashes() signature to include buffer as first parameter; removed bufferAddress() getter.
Buffer Contracts
src/contracts/block-hash-pusher/{zksync,scroll,linea}/.*Buffer.sol
Removed Ownable inheritance and setPusherAddress() setter; updated constructor to accept pusher directly; replaced _pusherAddress with _pusher; removed PusherAddressNotSet error and PusherAddressSet event; added InvalidPusherAddress error.
Pusher Contracts
src/contracts/block-hash-pusher/{zksync,scroll,linea}/.*Pusher.sol
Removed internal buffer storage and constructor parameter; added buffer parameter to pushHashes() signature as first argument; removed bufferAddress() getter; added zero-address validation with InvalidBuffer revert.
README Documentation
src/contracts/block-hash-pusher/README.md
Updated usage examples to reflect new pushHashes signature with explicit buffer parameter and constructor-based pusher initialization.
Buffer Tests
test/block-hash-pusher/{zksync,scroll,linea}/.*Buffer.t.sol
Removed owner-related state and setter invocations; updated constructor calls to pass pusher directly; removed tests for ownership and dynamic pusher configuration.
Pusher Tests
test/block-hash-pusher/{zksync,scroll,linea}/.*Pusher.t.sol
Updated constructor calls to remove buffer parameter; modified pushHashes() invocations to pass buffer as first argument; removed bufferAddress() getter assertions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • frangio
  • pepebndc
  • nahimterrazas

Poem

🐰 A buffer hops through function calls,

No longer bound by ownership walls,

Parameters dance where storage once stayed,

Constructor whispers the pusher's cascades! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: modifying pushHashes function signatures to accept buffer as a parameter, which is the primary objective across all affected files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

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

🤖 Fix all issues with AI agents
In `@src/contracts/block-hash-pusher/linea/LineaBuffer.sol`:
- Around line 35-42: The constructor currently validates l2MessageService_ but
not pusher_, which allows a zero-address _pusher and breaks the contract; add a
check in the constructor to revert if pusher_ == address(0) (introduce a new
error like InvalidPusherAddress() if one doesn't exist) and ensure both
l2MessageService_ and pusher_ are validated before assigning to
_l2MessageService and _pusher in the constructor of LineaBuffer.sol.

In `@src/contracts/block-hash-pusher/scroll/ScrollBuffer.sol`:
- Around line 32-39: The constructor currently validates l2ScrollMessenger_ but
not pusher_, so a zero pusher address can be stored and later cause
receiveHashes to revert with InvalidPusherAddress(); add a zero-address check
for pusher_ in the ScrollBuffer constructor (similar to ZkSyncBuffer) and revert
InvalidPusherAddress() when pusher_ == address(0) before assigning _pusher to
ensure the contract cannot be deployed with an invalid pusher; update the
constructor logic around _pusher and _l2ScrollMessenger accordingly.
🧹 Nitpick comments (4)
src/contracts/block-hash-pusher/zksync/ZkSyncBuffer.sol (1)

43-48: Note: Redundant zero check (defensive coding).

The zero check in aliasedPusher() is redundant since the constructor already prevents a zero pusher_. This is harmless defensive coding, so no change needed unless you prefer to remove it for consistency with the constructor-guaranteed invariant.

src/contracts/block-hash-pusher/zksync/ZkSyncPusher.sol (1)

43-45: Consider guarding against a zero zkSync Diamond address.
A zero address would make the mailbox call fail opaquely at runtime; a constructor guard makes misconfiguration explicit.

♻️ Suggested guard
 contract ZkSyncPusher is BlockHashArrayBuilder, IPusher {
     /// `@dev` The address of the ZkSync Diamond proxy contract on L1.
     address private immutable _zkSyncDiamond;

     /// `@notice` Thrown when the L2 transaction request fails.
     error FailedToPushHashes();
+    /// `@notice` Thrown when the zkSync Diamond address is zero.
+    error InvalidZkSyncDiamond(address diamond);
@@
-    constructor(address zkSyncDiamond_) {
-        _zkSyncDiamond = zkSyncDiamond_;
-    }
+    constructor(address zkSyncDiamond_) {
+        if (zkSyncDiamond_ == address(0)) {
+            revert InvalidZkSyncDiamond(zkSyncDiamond_);
+        }
+        _zkSyncDiamond = zkSyncDiamond_;
+    }
test/block-hash-pusher/zksync/ZkSyncPusher.t.sol (1)

64-99: Add a regression test for InvalidBuffer.
Now that buffer is user-supplied, a simple zero-address revert check would lock in the new guard.

🧪 Suggested test
@@
     function testFuzz_pushHashes_invalidBatchSize(uint16 batchSize) public {
         vm.assume(batchSize == 0 || batchSize > 8191);
         vm.roll(uint32(batchSize) + 1); // uint32 to avoid overflow
@@
         vm.expectRevert(abi.encodeWithSelector(IPusher.InvalidBatch.selector, block.number - batchSize, batchSize));
         zkSyncPusher.pushHashes(buffer, block.number - batchSize, batchSize, l2TransactionData);
     }
+
+    function test_pushHashes_reverts_if_buffer_zero() public {
+        vm.roll(2);
+        ZkSyncPusher zkSyncPusher = new ZkSyncPusher(mockZkSyncMailbox);
+
+        bytes memory l2TransactionData = abi.encode(
+            ZkSyncPusher.ZkSyncL2Transaction({
+                l2GasLimit: 1000000,
+                l2GasPerPubdataByteLimit: REQUIRED_L2_GAS_PRICE_PER_PUBDATA,
+                refundRecipient: address(0)
+            })
+        );
+
+        vm.expectRevert(abi.encodeWithSelector(IPusher.InvalidBuffer.selector, address(0)));
+        zkSyncPusher.pushHashes(address(0), block.number - 1, 1, l2TransactionData);
+    }
test/block-hash-pusher/linea/LineaBuffer.t.sol (1)

6-6: Remove unused Ownable import.

The Ownable import is no longer used in this test file since owner-related tests were removed as part of the refactor.

Suggested fix
 import {Test} from "forge-std/Test.sol";
 import {LineaBuffer} from "../../../src/contracts/block-hash-pusher/linea/LineaBuffer.sol";
-import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
 import {IBuffer} from "../../../src/contracts/block-hash-pusher/interfaces/IBuffer.sol";
 import {MockLineaMessageService} from "../mocks/MockLineaMessageService.sol";
 import {IMessageService} from "@linea-contracts/messaging/interfaces/IMessageService.sol";

Comment on lines +35 to 42
constructor(address l2MessageService_, address pusher_) {
_l2MessageService = l2MessageService_;
_pusher = pusher_;

if (l2MessageService_ == address(0)) {
revert InvalidL2MessageServiceAddress();
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add constructor validation for pusher_ parameter.

Same issue as in ScrollBuffer: the constructor validates l2MessageService_ but not pusher_. A zero-address pusher creates a permanently broken contract.

Proposed fix
 constructor(address l2MessageService_, address pusher_) {
     _l2MessageService = l2MessageService_;
     _pusher = pusher_;

     if (l2MessageService_ == address(0)) {
         revert InvalidL2MessageServiceAddress();
     }
+    if (pusher_ == address(0)) {
+        revert InvalidPusherAddress();
+    }
 }
🤖 Prompt for AI Agents
In `@src/contracts/block-hash-pusher/linea/LineaBuffer.sol` around lines 35 - 42,
The constructor currently validates l2MessageService_ but not pusher_, which
allows a zero-address _pusher and breaks the contract; add a check in the
constructor to revert if pusher_ == address(0) (introduce a new error like
InvalidPusherAddress() if one doesn't exist) and ensure both l2MessageService_
and pusher_ are validated before assigning to _l2MessageService and _pusher in
the constructor of LineaBuffer.sol.

Comment on lines +32 to 39
constructor(address l2ScrollMessenger_, address pusher_) {
_l2ScrollMessenger = l2ScrollMessenger_;
_pusher = pusher_;

if (l2ScrollMessenger_ == address(0)) {
revert InvalidL2ScrollMessengerAddress();
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add constructor validation for pusher_ parameter.

The constructor validates l2ScrollMessenger_ but not pusher_. If a zero address is passed for pusher_, the contract deploys successfully but receiveHashes will always revert with InvalidPusherAddress(). This is inconsistent with ZkSyncBuffer, which validates pusher_ in its constructor.

Proposed fix
 constructor(address l2ScrollMessenger_, address pusher_) {
     _l2ScrollMessenger = l2ScrollMessenger_;
     _pusher = pusher_;

     if (l2ScrollMessenger_ == address(0)) {
         revert InvalidL2ScrollMessengerAddress();
     }
+    if (pusher_ == address(0)) {
+        revert InvalidPusherAddress();
+    }
 }
🤖 Prompt for AI Agents
In `@src/contracts/block-hash-pusher/scroll/ScrollBuffer.sol` around lines 32 -
39, The constructor currently validates l2ScrollMessenger_ but not pusher_, so a
zero pusher address can be stored and later cause receiveHashes to revert with
InvalidPusherAddress(); add a zero-address check for pusher_ in the ScrollBuffer
constructor (similar to ZkSyncBuffer) and revert InvalidPusherAddress() when
pusher_ == address(0) before assigning _pusher to ensure the contract cannot be
deployed with an invalid pusher; update the constructor logic around _pusher and
_l2ScrollMessenger accordingly.

Copy link
Collaborator

@frangio frangio left a comment

Choose a reason for hiding this comment

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

Can Buffer state variables be made immutable?

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.

3 participants