Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ Morph provides a custom L2 Engine API (different from the standard Ethereum Engi
| `engine_newL2Block` | Import a new L2 block via `newPayload` + `forkchoiceUpdated` and advance the canonical head |
| `engine_newSafeL2Block` | Rebuild and import a safe L2 block from derivation inputs |
| `engine_setBlockTags` | Update safe/finalized block tags without importing a block |
| `engine_appendBatchSignature` | Accept a BLS batch signature from the consensus layer (no-op for sync nodes) |

## Contributing

Expand Down
16 changes: 15 additions & 1 deletion crates/engine-api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

use crate::EngineApiResult;
use alloy_primitives::B256;
use morph_payload_types::{AssembleL2BlockParams, ExecutableL2Data, GenericResponse, SafeL2Data};
use morph_payload_types::{
AssembleL2BlockParams, BatchSignature, ExecutableL2Data, GenericResponse, SafeL2Data,
};
use morph_primitives::MorphHeader;

/// Morph L2 Engine API trait.
Expand Down Expand Up @@ -107,4 +109,16 @@ pub trait MorphL2EngineApi: Send + Sync {
safe_block_hash: B256,
finalized_block_hash: B256,
) -> EngineApiResult<()>;

/// Append a BLS batch signature for a given batch hash.
///
/// Called by the consensus layer when collecting validator signatures for
/// L1 batch submission. For non-sequencer sync nodes, this is a no-op.
async fn append_batch_signature(
&self,
_batch_hash: B256,
_signature: BatchSignature,
) -> EngineApiResult<()> {
Ok(())
}
}
39 changes: 38 additions & 1 deletion crates/engine-api/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
use crate::{EngineApiResult, api::MorphL2EngineApi};
use alloy_primitives::B256;
use jsonrpsee::{RpcModule, core::RpcResult, proc_macros::rpc};
use morph_payload_types::{AssembleL2BlockParams, ExecutableL2Data, GenericResponse, SafeL2Data};
use morph_payload_types::{
AssembleL2BlockParams, BatchSignature, ExecutableL2Data, GenericResponse, SafeL2Data,
};
use morph_primitives::MorphHeader;
use reth_rpc_api::IntoEngineApiRpcModule;
use std::sync::Arc;
Expand Down Expand Up @@ -61,6 +63,22 @@ pub trait MorphL2EngineRpc {
safe_block_hash: B256,
finalized_block_hash: B256,
) -> RpcResult<()>;

/// Append a BLS batch signature for a given batch hash.
///
/// Called by the consensus layer when collecting validator signatures for
/// L1 batch submission. Non-sequencer sync nodes accept this call but do
/// not persist the signature.
///
/// # JSON-RPC Method
///
/// `engine_appendBatchSignature`
#[method(name = "appendBatchSignature")]
async fn append_batch_signature(
&self,
batch_hash: B256,
signature: BatchSignature,
) -> RpcResult<()>;
}

/// Implementation of the L2 Engine RPC API.
Expand Down Expand Up @@ -164,6 +182,25 @@ where
e.into()
})
}

async fn append_batch_signature(
&self,
batch_hash: B256,
_signature: BatchSignature,
) -> RpcResult<()> {
tracing::debug!(
target: "morph::engine",
%batch_hash,
"RPC appendBatchSignature called (no-op for sync node)"
);
Comment on lines +191 to +195
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Log message is misleading for non-no-op implementations.

Line 194 says this RPC call is a no-op, but Line 197 forwards to self.inner.append_batch_signature(...), which may do real work in overridden implementations.

Suggested logging tweak
         tracing::debug!(
             target: "morph::engine",
             %batch_hash,
-            "RPC appendBatchSignature called (no-op for sync node)"
+            "RPC appendBatchSignature called"
         );
📝 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
tracing::debug!(
target: "morph::engine",
%batch_hash,
"RPC appendBatchSignature called (no-op for sync node)"
);
tracing::debug!(
target: "morph::engine",
%batch_hash,
"RPC appendBatchSignature called"
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/engine-api/src/rpc.rs` around lines 191 - 195, The debug message for
appendBatchSignature is misleading because it claims a "no-op for sync node"
while the method then calls self.inner.append_batch_signature(...); update the
tracing::debug call (the log string tied to %batch_hash) to not assert it's a
no-op — instead log that the RPC was received and is being forwarded to
self.inner.append_batch_signature (or that behavior may vary by implementation),
so the message accurately reflects the actual action performed.

self.inner
.append_batch_signature(batch_hash, _signature)
.await
.map_err(|e| {
tracing::error!(target: "morph::engine", error = %e, "failed to append batch signature");
e.into()
})
}
}

/// Converts an `EngineApiResult` into a `RpcResult`.
Expand Down
2 changes: 1 addition & 1 deletion crates/payload/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use reth_ethereum_primitives as _;
pub use attributes::{MorphPayloadAttributes, MorphPayloadBuilderAttributes};
pub use built::MorphBuiltPayload;
pub use executable_l2_data::ExecutableL2Data;
pub use params::{AssembleL2BlockParams, GenericResponse};
pub use params::{AssembleL2BlockParams, BatchSignature, GenericResponse};
pub use safe_l2_data::SafeL2Data;

// =============================================================================
Expand Down
18 changes: 17 additions & 1 deletion crates/payload/types/src/params.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Request/response types for L2 Engine API methods.

use alloy_primitives::Bytes;
use alloy_primitives::{Address, Bytes};

/// Parameters for engine_assembleL2Block.
///
Expand Down Expand Up @@ -70,6 +70,22 @@ impl GenericResponse {
}
}

/// BLS batch signature from a sequencer validator.
///
/// This is sent by the consensus layer via `engine_appendBatchSignature`
/// when collecting validator signatures for L1 batch submission.
/// For non-sequencer nodes this is accepted but not persisted.
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BatchSignature {
/// Validator address that produced the signature.
pub signer: Address,
/// BLS public key of the signer.
pub signer_pub_key: Bytes,
/// BLS signature over the batch hash.
pub signature: Bytes,
}

impl From<bool> for GenericResponse {
fn from(success: bool) -> Self {
Self { success }
Expand Down
Loading