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 README usage examples to reflect the revised push API.
  • Refactor

    • Push API now requires an explicit buffer address on each call and validates it.
    • Pusher/buffer wiring is established at deployment (pusher address provided at construction).
    • Removed implicit buffer getter; callers must supply the buffer per push.

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

@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Pusher contracts now take an explicit buffer address in pushHashes() and no longer store a buffer; buffer contracts remove Ownable/setter flows and require the pusher address at construction. IPusher and README updated accordingly; tests adjusted to the new constructor and call-site signatures.

Changes

Cohort / File(s) Summary
Interface
src/contracts/block-hash-pusher/interfaces/IPusher.sol
Added InvalidBuffer(address) error; changed pushHashes() to pushHashes(address buffer, uint256 firstBlockNumber, uint256 batchSize, bytes calldata l2TransactionData) external payable; removed bufferAddress() getter.
Buffers (constructor-set pusher)
src/contracts/block-hash-pusher/zksync/ZkSyncBuffer.sol, src/contracts/block-hash-pusher/scroll/ScrollBuffer.sol, src/contracts/block-hash-pusher/linea/LineaBuffer.sol
Removed Ownable and setPusherAddress(); introduced immutable _pusher set in constructor; replaced _pusherAddress with _pusher; removed PusherAddressNotSet/PusherAddressSet; added InvalidPusherAddress/InvalidSender as applicable.
Pushers (buffer param)
src/contracts/block-hash-pusher/zksync/ZkSyncPusher.sol, src/contracts/block-hash-pusher/scroll/ScrollPusher.sol, src/contracts/block-hash-pusher/linea/LineaPusher.sol
Removed stored buffer state and constructor buffer parameter; updated constructors to drop buffer arg; changed pushHashes() to accept address buffer as first parameter and validate non-zero buffer (revert InvalidBuffer(buffer)); removed bufferAddress() getters; replaced internal buffer references with the provided buffer.
Tests — Buffers
test/block-hash-pusher/{zksync,scroll,linea}/*Buffer.t.sol
Tests updated to construct buffers with pusher (instead of owner) and removed owner/setter-related test cases and assertions.
Tests — Pushers
test/block-hash-pusher/{zksync,scroll,linea}/*Pusher.t.sol
Constructors updated to remove buffer arg; all pushHashes call sites updated to pass buffer as first parameter; removed bufferAddress() assertions.
Docs
src/contracts/block-hash-pusher/README.md
Usage examples updated to show pushHashes(buffer, ...) and constructor-based pusher provisioning.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant Operator
    end
    rect rgba(200,255,200,0.5)
    participant Pusher
    end
    rect rgba(255,200,200,0.5)
    participant L1Messenger
    end
    rect rgba(255,255,200,0.5)
    participant Buffer
    end
    Operator->>Pusher: call pushHashes(buffer, firstBlock, batchSize, l2Data) payable
    Pusher->>L1Messenger: sendMessage{value: msg.value}(buffer, encodedPayload)
    L1Messenger->>Buffer: deliver L1->L2 message to buffer
    Buffer->>Buffer: receiveHashes(fromBlock, toBlock, hashedData)
    Buffer-->>Pusher: (no direct state write) emit/ack events (BlockHashesReceived)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • pepebndc
  • nahimterrazas

Poem

🐰 I hop from code to rolling fence,

Buffers freed from owner sense,
Params now carry where they roam,
Constructors whisper: "this is home",
A tiny hop — a cleaner comb. 🥕

🚥 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 describes the main change: updating the pushHashes function signature to accept buffer as a parameter, which is the primary change across all pusher and buffer implementations.
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?

@luiz-lvj luiz-lvj requested a review from frangio January 26, 2026 12:00
@luiz-lvj luiz-lvj merged commit 2d9d9df into main Jan 26, 2026
3 checks passed
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.

2 participants