Skip to content

fix(payload): serialize nextL1MessageIndex as bare uint64, not hex string#73

Open
panos-xyz wants to merge 2 commits intomainfrom
fix/engine-api-gaps
Open

fix(payload): serialize nextL1MessageIndex as bare uint64, not hex string#73
panos-xyz wants to merge 2 commits intomainfrom
fix/engine-api-gaps

Conversation

@panos-xyz
Copy link
Copy Markdown
Contributor

@panos-xyz panos-xyz commented Mar 31, 2026

Summary

  • ExecutableL2Data.nextL1MessageIndex was decorated with #[serde(with = "alloy_serde::quantity")], causing it to serialize as a hex string ("0xa")
  • morph-geth's gen_l2_ed.go declares NextL1MessageIndex as bare uint64 (not hexutil.Uint64), so it expects a plain JSON number (10)
  • morphnode would fail with: json: cannot unmarshal string into Go struct field ExecutableL2Data.nextL1MessageIndex of type uint64

Fix: Remove the quantity serde attribute. All other numeric fields (number, gasLimit, gasUsed, timestamp) correctly use hex encoding because morph-geth uses hexutil.Uint64 for those — NextL1MessageIndex is the sole exception.

Reference: morph/go-ethereum/eth/catalyst/gen_l2_ed.go line 31

Test plan

  • Existing serde round-trip test updated: "nextL1MessageIndex": "0xa""nextL1MessageIndex": 10
  • cargo test -p morph-payload-types passes

Summary by CodeRabbit

  • Bug Fixes

    • Numeric message index values now serialize/deserialize as standard JSON numbers instead of hexadecimal strings.
  • Documentation

    • Clarified field-level documentation describing the message index serialization format.
  • Tests

    • Updated serialization tests/fixtures to use numeric literals for message index values.

…ring

morph-geth's gen_l2_ed.go declares NextL1MessageIndex as bare `uint64`
(not `hexutil.Uint64`), so it expects a JSON number like `10`, not a hex
quantity string like `"0xa"`.

Remove the `#[serde(with = "alloy_serde::quantity")]` attribute to match
the Go side. All other numeric fields (number, gasLimit, etc.) correctly
use hex because morph-geth uses `hexutil.Uint64` for those —
NextL1MessageIndex is the sole exception.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b800d64d-b026-4b19-ae8c-d360b840e970

📥 Commits

Reviewing files that changed from the base of the PR and between 4160111 and 7cf1999.

📒 Files selected for processing (1)
  • crates/payload/types/src/executable_l2_data.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/payload/types/src/executable_l2_data.rs

📝 Walkthrough

Walkthrough

Removed hex-quantity serde for ExecutableL2Data.next_l1_message_index, so it now serializes/deserializes as a plain JSON u64. Updated tests' camelCase fixture to use numeric literal and added field-level documentation noting morph-geth format. No public API signatures changed.

Changes

Cohort / File(s) Summary
ExecutableL2Data Serde & Tests
crates/payload/types/src/executable_l2_data.rs
Removed #[serde(with = "alloy_serde::quantity")] from next_l1_message_index, making it a bare JSON u64; updated camelCase serde test fixture from hex string to numeric literal; added field documentation referencing morph-geth serialization.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 I swapped a hex for plain delight,
Numbers now wake in morning light,
Tests adjusted, docs sing true,
A cleaner field, a clearer view,
Hoppity code — small change, big bite!

🚥 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 directly and accurately describes the main change: removing hex-quantity serialization from nextL1MessageIndex and making it serialize as a bare uint64 number instead.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/engine-api-gaps

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.

@panos-xyz panos-xyz requested a review from chengwenxi March 31, 2026 08:56
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
crates/payload/types/src/executable_l2_data.rs (2)

68-72: Avoid hardcoded external line numbers in docs.

gen_l2_ed.go line 31 can drift quickly. Prefer symbol/path-only reference or a permalink to a specific commit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/payload/types/src/executable_l2_data.rs` around lines 68 - 72, The doc
comment references an external file by a hardcoded line number ("gen_l2_ed.go
line 31") which can drift; update the comment on the next_l1_message_index field
to remove the line number and instead point to a stable identifier — e.g.,
reference the source file and symbol or a commit permalink (for example
"morph/go-ethereum/eth/catalyst/gen_l2_ed.go, see the GenL2ED
function/serialization logic" or a specific commit URL) so readers can locate
the exact code without relying on a line number.

191-253: Add explicit test to verify nextL1MessageIndex serializes as a JSON number.

The code comment (lines 68-71) emphasizes that nextL1MessageIndex must serialize as a bare JSON number, unlike other numeric fields. Current tests verify deserialization and roundtrip equality but do not explicitly assert the serialization format using is_number(). The proposed test would protect against accidental changes that could introduce hex serialization.

Proposed test addition
+#[test]
+fn test_next_l1_message_index_serializes_as_number() {
+    let data = ExecutableL2Data {
+        next_l1_message_index: 10,
+        ..Default::default()
+    };
+
+    let json = serde_json::to_value(&data).expect("serialize");
+    assert_eq!(json["nextL1MessageIndex"], serde_json::json!(10));
+    assert!(json["nextL1MessageIndex"].is_number());
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/payload/types/src/executable_l2_data.rs` around lines 191 - 253, Add a
unit test that builds an ExecutableL2Data with a known next_l1_message_index
value, serializes it with serde_json::to_value or to_string, parses to
serde_json::Value and asserts the nextL1MessageIndex field exists and
value.is_number() is true; place the test near the other serde tests (e.g., name
it test_next_l1_message_index_serializes_as_number) and reference
ExecutableL2Data and the JSON key "nextL1MessageIndex" to ensure the field is
not emitted as a hex/string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/payload/types/src/executable_l2_data.rs`:
- Around line 68-72: The doc comment references an external file by a hardcoded
line number ("gen_l2_ed.go line 31") which can drift; update the comment on the
next_l1_message_index field to remove the line number and instead point to a
stable identifier — e.g., reference the source file and symbol or a commit
permalink (for example "morph/go-ethereum/eth/catalyst/gen_l2_ed.go, see the
GenL2ED function/serialization logic" or a specific commit URL) so readers can
locate the exact code without relying on a line number.
- Around line 191-253: Add a unit test that builds an ExecutableL2Data with a
known next_l1_message_index value, serializes it with serde_json::to_value or
to_string, parses to serde_json::Value and asserts the nextL1MessageIndex field
exists and value.is_number() is true; place the test near the other serde tests
(e.g., name it test_next_l1_message_index_serializes_as_number) and reference
ExecutableL2Data and the JSON key "nextL1MessageIndex" to ensure the field is
not emitted as a hex/string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 84a4d90f-7521-466f-9280-d9c3830c4f58

📥 Commits

Reviewing files that changed from the base of the PR and between 6ea9660 and 4160111.

📒 Files selected for processing (1)
  • crates/payload/types/src/executable_l2_data.rs

chengwenxi

This comment was marked as duplicate.

chengwenxi

This comment was marked as duplicate.

Copy link
Copy Markdown
Contributor

@chengwenxi chengwenxi left a comment

Choose a reason for hiding this comment

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

LGTM. Correct fix — matches Go's gen_l2_ed.go where NextL1MessageIndex is plain uint64 (not hexutil.Uint64). Removing alloy_serde::quantity switches serde to bare JSON number, fixing the interop bug. Minor nit: the hardcoded line number in the doc comment (line 31) is brittle — consider a permalink or just the symbol name.

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