Skip to content

Conversation

@sudo-shashank
Copy link
Contributor

@sudo-shashank sudo-shashank commented Aug 12, 2025

Summary of changes

Changes introduced in this pull request:

  • Added evm actor support in state decode params with tests.

Reference issue to close (if applicable)

Closes #5721

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Summary by CodeRabbit

  • New Features

    • Added EVM RPC methods: GetBytecode, GetBytecodeHash, GetStorageAt; enabled InvokeContract and InvokeContractDelegate parameter support.
  • Refactor

    • Reorganized EVM parameter Lotus JSON representations across actor versions and consolidated constructor/delegate parameter handling; added validated (de)serialization for GetStorageAt.
  • Tests

    • Added state-decode API tests and seven new EVM snapshot entries.

@sudo-shashank sudo-shashank added the RPC requires calibnet RPC checks to run on CI label Aug 12, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 12, 2025

Walkthrough

Consolidates EVM Lotus JSON mappings into a single module, adds Lotus JSON structs for constructor/delegate-call and GetStorageAt params, implements HasLotusJson conversions for EVM v10..v16, registers new EVM RPC methods (GetBytecode, GetBytecodeHash, GetStorageAt, InvokeContract, InvokeContractDelegate, Constructor, Resurrect), and refactors tests and snapshots.

Changes

Cohort / File(s) Summary
Lotus JSON EVM actor params
src/lotus_json/actor_states/methods/evm_actor_params.rs
Adds EVMConstructorParamsLotusJson, EVMDelegateCallParamsLotusJson, GetStorageAtParamsLotusJson; implements HasLotusJson conversions for ConstructorParams and DelegateCallParams across v10..v16 and for GetStorageAtParams; includes serde/JsonSchema attributes and test snapshots.
Removed old constructor module
src/lotus_json/actor_states/methods/evm_constructor_params.rs (removed)
Deleted previous file that defined constructor Lotus JSON struct, macro and per-version HasLotusJson impls; functionality consolidated into evm_actor_params.rs.
Module inclusion update
src/lotus_json/actor_states/methods/mod.rs
Replaced mod evm_constructor_params; with mod evm_actor_params;.
EVM RPC registry updates
src/rpc/registry/actors/evm.rs
Registers EVM methods and param types: Constructor/Resurrect (ConstructorParams), InvokeContract (RawBytes), InvokeContractDelegate (DelegateCallParams), GetStorageAt (GetStorageAtParams), and GetBytecode/GetBytecodeHash (empty params); imports adjusted accordingly.
GetStorageAt params (RPC types)
src/rpc/methods/eth/types.rs
GetStorageAtParams now derives Serialize/Deserialize; introduces module-level CBOR length prefix constant and GetStorageAtParams::deserialize_params with prefix validation and CBOR decoding.
API compare tests refactor
src/tool/subcommands/api_cmd/api_compare_tests.rs
Extracts EVM state-decode param tests into evm_actor_state_decode_params_tests, adds v16 tests for Constructor, Resurrect, GetBytecode, GetBytecodeHash, InvokeContract, InvokeContractDelegate, GetStorageAt; marshals params accordingly.
Snapshot list updated
src/tool/subcommands/api_cmd/test_snapshots.txt
Adds seven EVM state-decode snapshot entries for the newly covered methods and several verified_reg snapshot entries.

Sequence Diagram(s)

%%{init: {"themeVariables":{"actorBorder":"#1f77b4","noteBackground":"#f7f7f7"}}}%%
sequenceDiagram
  participant Client
  participant StateDecodeAPI as StateDecodeParams API
  participant RPCRegistry as EVM RPC Registry
  participant LotusJSON as Lotus JSON Mappers
  participant CBOR as CBOR (GetStorageAt)

  Client->>StateDecodeAPI: Request decode (actor=EVM, method, params, tipset)
  StateDecodeAPI->>RPCRegistry: Resolve method -> param type
  RPCRegistry-->>StateDecodeAPI: Param type (Constructor/Delegate/RawBytes/GetStorageAt/empty)
  alt GetStorageAt
    StateDecodeAPI->>CBOR: GetStorageAtParams::deserialize_params(bytes)
    CBOR-->>StateDecodeAPI: GetStorageAtParams (validated)
    StateDecodeAPI->>LotusJSON: into_lotus_json(GetStorageAtParams)
  else Other params
    StateDecodeAPI->>LotusJSON: into_lotus_json(params)
  end
  LotusJSON-->>StateDecodeAPI: Lotus JSON (v10..v16 aware)
  StateDecodeAPI-->>Client: Decoded params JSON
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Add EVM support to StateDecodeParams for v10–v16 [#5721]
Implement Constructor and Resurrect methods [#5721]
Implement GetBytecode and GetBytecodeHash [#5721]
Implement InvokeContract, InvokeContractDelegate and GetStorageAt [#5721]

Out-of-scope changes

Code Change Explanation
Added multiple filecoin_verified_reg_statedecodeparams_* snapshot entries (src/tool/subcommands/api_cmd/test_snapshots.txt) The linked issue targets EVM StateDecodeParams; these verified_reg snapshot additions pertain to a different actor's snapshots and are not referenced by the issue objectives.

Possibly related issues

Suggested reviewers

  • akaladarshi
  • LesnyRumcajs
  • elmattic

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch shashank/evm-state-decode-params

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sudo-shashank sudo-shashank marked this pull request as ready for review August 14, 2025 09:54
@sudo-shashank sudo-shashank requested a review from a team as a code owner August 14, 2025 09:54
@sudo-shashank sudo-shashank requested review from LesnyRumcajs and hanabi1224 and removed request for a team August 14, 2025 09:54
Copy link
Contributor

@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

🧹 Nitpick comments (4)
src/rpc/registry/actors/evm.rs (1)

29-31: Pending: Add GetStorageAt when implementing it

You’ve registered GetBytecode and GetBytecodeHash (empty params). Once GetStorageAt lands, remember to register it here with its correct params type.

I can draft the registration snippet and tests when you pick up GetStorageAt. Want me to open a follow-up issue/PR checklist for the remaining EVM methods?

src/lotus_json/actor_states/methods/evm_actor_params.rs (1)

7-11: Prefer serde::Serialize import for clarity and consistency

Avoid importing Serialize from jsonrpsee. Derive macros expand to serde::Serialize anyway; importing from serde is clearer and consistent with Deserialize.

Apply:

-use jsonrpsee::core::Serialize;
-use paste::paste;
-use schemars::JsonSchema;
-use serde::Deserialize;
+use paste::paste;
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
src/tool/subcommands/api_cmd/api_compare_tests.rs (2)

2182-2219: DRY: Reuse parsed EVM address to avoid repeated parsing

Minor cleanup to avoid multiple Address::from_str calls.

Apply:

 fn evm_actor_state_decode_params_tests(tipset: &Tipset) -> anyhow::Result<Vec<RpcTest>> {
+    let evm_address = Address::from_str(EVM_ADDRESS).unwrap();
@@
-        RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+        RpcTest::identity(StateDecodeParams::request((
+            evm_address,
             fil_actor_evm_state::v16::Method::Constructor as u64,
             to_vec(&evm_constructor_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_address,
             fil_actor_evm_state::v16::Method::Resurrect as u64,
             to_vec(&evm_constructor_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_address,
             fil_actor_evm_state::v16::Method::GetBytecode as u64,
             vec![],
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_address,
             fil_actor_evm_state::v16::Method::GetBytecodeHash as u64,
             vec![],
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_address,
             fil_actor_evm_state::v16::Method::InvokeContract as u64,
             to_vec(&evm_invoke_contract_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_address,
             fil_actor_evm_state::v16::Method::InvokeContractDelegate as u64,
             to_vec(&evm_delegate_call_params)?,
             tipset.key().into(),
         ))?),

2196-2206: Note for future coverage: Add GetStorageAt once implemented

Once GetStorageAt is supported, it’d be good to add a matching StateDecodeParams test here for parity with the registry and snapshots.

I can add a placeholder test and snapshot entry when you tackle GetStorageAt. Want me to queue that up?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d641ead and c984a48.

📒 Files selected for processing (6)
  • src/lotus_json/actor_states/methods/evm_actor_params.rs (1 hunks)
  • src/lotus_json/actor_states/methods/evm_constructor_params.rs (0 hunks)
  • src/lotus_json/actor_states/methods/mod.rs (1 hunks)
  • src/rpc/registry/actors/evm.rs (1 hunks)
  • src/tool/subcommands/api_cmd/api_compare_tests.rs (1 hunks)
  • src/tool/subcommands/api_cmd/test_snapshots.txt (1 hunks)
💤 Files with no reviewable changes (1)
  • src/lotus_json/actor_states/methods/evm_constructor_params.rs
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/rpc/registry/actors/evm.rs (4)
src/rpc/registry/actors/init.rs (1)
  • register_actor_methods (42-55)
src/rpc/registry/actors/power.rs (1)
  • register_actor_methods (117-130)
src/rpc/registry/actors/system.rs (1)
  • register_actor_methods (22-35)
src/shim/actors/builtin/market/mod.rs (1)
  • empty (744-752)
🔇 Additional comments (9)
src/rpc/registry/actors/evm.rs (2)

12-23: Solid method-to-params mapping for Constructor/Resurrect/InvokeContract/InvokeContractDelegate

The registration cleanly wires:

  • Constructor/Resurrect → ConstructorParams
  • InvokeContract → RawBytes
  • InvokeContractDelegate → DelegateCallParams

This aligns with the EVM actor’s API for v10–v16 and keeps things version-agnostic via the macro. Nice separation of typed params vs raw bytes.


20-21: InvokeContract mapping to RawBytes is correct

A search of src/rpc/registry/actors/evm.rs and the wider codebase shows no use of InvokeContractParams or duplicate Lotus JSON mappings for InvokeContract. The tuple

(Method::InvokeContract, RawBytes)

properly captures the opaque CBOR payload across v10–v16. No changes required.

src/lotus_json/actor_states/methods/evm_actor_params.rs (2)

29-43: Ensure json! macro is in scope in test-only snapshots

The snapshots use json!({...}) but this file doesn’t import the macro explicitly. If it isn’t re-exported from a parent module in this context, compilation will fail under tests.

If not already imported via super::*, add:

+#[cfg(test)]
+use serde_json::json;

Also applies to: 88-104


64-79: Lotus JSON mapping for delegate call looks good and reversible

The Lotus JSON representation for DelegateCallParams properly wraps code/input/value and flattens caller. The into/from mappings are consistent with Vec <-> RawBytes conversions and EthAddress newtype handling.

src/lotus_json/actor_states/methods/mod.rs (1)

7-7: Module swap to evm_actor_params is appropriate

Replacing evm_constructor_params with the consolidated evm_actor_params module improves cohesion and keeps EVM-related Lotus JSON types together.

src/tool/subcommands/api_cmd/test_snapshots.txt (1)

180-185: Snapshot coverage added for all registered EVM methods

The new entries cover Constructor, Resurrect, GetBytecode, GetBytecodeHash, InvokeContract, and InvokeContractDelegate, matching the registry changes and tests.

src/tool/subcommands/api_cmd/api_compare_tests.rs (3)

2159-2163: Good: EVM state-decode tests integrated into the main suite

Extending state_decode_params_api_tests with EVM test cases keeps coverage centralized and ensures parity validation alongside other actors.


2165-2181: Test param construction aligns with Lotus JSON mappings

  • ConstructorParams uses RawBytes for initcode.
  • InvokeContractParams uses input_data vector.
  • DelegateCallParams uses Vec for input and TokenAmount::default for value.

These match the Lotus JSON converters introduced in evm_actor_params.rs.


2171-2174: Confirm InvokeContractParams serializes identically to RawBytes

We’ve verified in src/rpc/registry/actors/evm.rs that Method::InvokeContract is decoded as RawBytes, but our tests in api_compare_tests.rs are still serializing the InvokeContractParams struct:

• src/tool/subcommands/api_cmd/api_compare_tests.rs:2171–2174
• src/tool/subcommands/api_cmd/api_compare_tests.rs:2207–2219

Please verify that in every version module (fil_actor_evm_state::v10 through v16), InvokeContractParams is declared as a #[serde(transparent)] wrapper over a byte buffer so its CBOR encoding exactly matches what RawBytes produces. For example, you can run something like:

grep -R "#\\[serde(transparent)\\]" ~/.cargo/registry/src/*/fil_actor_evm_state-*/src/v1{0..6}.rs -n

If any of these versions do not use a transparent wrapper (or if Lotus expects raw bytes), update the tests to send raw bytes directly:

let evm_invoke_contract_params = fvm_ipld_encoding::RawBytes::new(vec![0x11, 0x22, 0x33, 0x44, 0x55]);

@sudo-shashank sudo-shashank marked this pull request as draft August 14, 2025 10:15
@sudo-shashank sudo-shashank marked this pull request as ready for review August 19, 2025 18:15
Copy link
Contributor

@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

🧹 Nitpick comments (5)
src/rpc/methods/eth/types.rs (3)

65-65: Prefer hex literal and document CBOR prefix meaning.

Make the intent explicit that 0x81 is a CBOR array-of-length-1 prefix.

-const LENGTH_BUF_GET_STORAGE_AT_PARAMS: u8 = 129;
+/// CBOR major type 4 (array) with length 1: 0x80 + 1 = 0x81
+const LENGTH_BUF_GET_STORAGE_AT_PARAMS: u8 = 0x81;

83-87: Avoid Vec::insert(0, ...) to prevent O(n) shifting.

Prepending by insertion at index 0 reallocates/moves the entire buffer. Build the vector with capacity and extend instead.

-    pub fn serialize_params(&self) -> anyhow::Result<Vec<u8>> {
-        let mut encoded = fvm_ipld_encoding::to_vec(&RawBytes::new(self.0.to_vec()))?;
-        encoded.insert(0, LENGTH_BUF_GET_STORAGE_AT_PARAMS);
-        Ok(encoded)
-    }
+    pub fn serialize_params(&self) -> anyhow::Result<Vec<u8>> {
+        let encoded = fvm_ipld_encoding::to_vec(&RawBytes::new(self.0.to_vec()))?;
+        let mut with_prefix = Vec::with_capacity(encoded.len() + 1);
+        with_prefix.push(LENGTH_BUF_GET_STORAGE_AT_PARAMS);
+        with_prefix.extend_from_slice(&encoded);
+        Ok(with_prefix)
+    }

89-96: Add a negative test for prefix mismatch and a round-trip test for deserialize_params.

Good addition. To harden it, add tests that:

  • Round-trip via serialize_params -> deserialize_params.
  • Fail with a clear error when the CBOR array-length prefix is not 0x81.

Example tests (place alongside existing tests in this module):

#[test]
fn get_storage_at_params_roundtrip() {
    let original = GetStorageAtParams::new(vec![0xde, 0xad, 0xbe, 0xef]).unwrap();
    let ser = original.serialize_params().unwrap();
    let de = GetStorageAtParams::deserialize_params(&ser).unwrap();
    assert_eq!(original.0, de.0);
}

#[test]
fn get_storage_at_params_bad_prefix() {
    let good = GetStorageAtParams::new(vec![0x0a]).unwrap().serialize_params().unwrap();
    let mut bad = good.clone();
    bad[0] = 0x80; // wrong CBOR array-length (0 not 1)
    let err = GetStorageAtParams::deserialize_params(&bad).unwrap_err();
    assert!(err.to_string().contains("expected CBOR array of length 1"));
}
src/lotus_json/actor_states/methods/evm_actor_params.rs (2)

131-134: Clarify size constraint for StorageKey in JSON schema/docs.

GetStorageAtParams ultimately requires a 32-byte key (left-padded if shorter). Consider documenting this on the JSON field to set expectations for clients.

For example, add a doc comment:
// Must be at most 32 bytes; shorter values are left-padded with zeros to 32 bytes.


155-157: Avoid panic on oversized storage_key during JSON -> params conversion.

GetStorageAtParams::new(..) errors on >32 bytes; unwrap() will panic, potentially taking down the request handler on bad input. Since HasLotusJson::from_lotus_json is infallible, defensively clamp to the last 32 bytes to avoid panics while matching the “right-aligned” behavior.

-    fn from_lotus_json(lotus_json: Self::LotusJson) -> Self {
-        GetStorageAtParams::new(lotus_json.storage_key).unwrap()
-    }
+    fn from_lotus_json(lotus_json: Self::LotusJson) -> Self {
+        // Clamp to last 32 bytes to avoid panic on oversized input;
+        // shorter inputs are left-padded by `GetStorageAtParams::new`.
+        let key = if lotus_json.storage_key.len() > 32 {
+            lotus_json.storage_key[lotus_json.storage_key.len() - 32..].to_vec()
+        } else {
+            lotus_json.storage_key
+        };
+        // `new` only fails if input > 32 bytes, which we prevent above.
+        GetStorageAtParams::new(key).expect("validated length <= 32")
+    }

If strict rejection is desired instead of clamping, the alternative is to validate earlier in the request decoding path and return a structured error (but HasLotusJson’s signature doesn’t allow that here).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c984a48 and b14e1d5.

📒 Files selected for processing (6)
  • src/lotus_json/actor_states/methods/evm_actor_params.rs (1 hunks)
  • src/lotus_json/actor_states/methods/mod.rs (1 hunks)
  • src/rpc/methods/eth/types.rs (2 hunks)
  • src/rpc/registry/actors/evm.rs (1 hunks)
  • src/tool/subcommands/api_cmd/api_compare_tests.rs (2 hunks)
  • src/tool/subcommands/api_cmd/test_snapshots.txt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/tool/subcommands/api_cmd/test_snapshots.txt
  • src/lotus_json/actor_states/methods/mod.rs
  • src/tool/subcommands/api_cmd/api_compare_tests.rs
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/rpc/methods/eth/types.rs (1)
src/rpc/methods/eth.rs (1)
  • fvm_ipld_encoding (2212-2212)
src/lotus_json/actor_states/methods/evm_actor_params.rs (1)
src/rpc/methods/eth/types.rs (3)
  • new (71-81)
  • new (413-418)
  • new (425-427)
⏰ 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-release
  • GitHub Check: tests
  • GitHub Check: Build forest binaries on Linux AMD64
🔇 Additional comments (6)
src/rpc/methods/eth/types.rs (1)

67-69: Deriving Serialize/Deserialize for GetStorageAtParams looks good.

This aligns with the added Lotus JSON conversion and simplifies testing and (de)serialization paths.

src/rpc/registry/actors/evm.rs (3)

17-23: Confirm Resurrect params are ConstructorParams across v10–v16.

Registration assumes Resurrect’s params mirror ConstructorParams. Please confirm this matches the actors’ state API for all listed versions.

If it differs for any version, split the registration by version to use the correct param type(s).


25-29: Good: custom GetStorageAt registration uses validated deserializer.

Directly wiring GetStorageAtParams::deserialize_params ensures the CBOR prefix and payload are validated. This matches the serialization path added in eth/types.rs.


31-37: No action needed: empty is supported by register_actor_methods!
The macro definition in src/rpc/registry/methods_reg.rs explicitly handles (…, empty), and it’s already used elsewhere (in methods_reg.rs tests, reward.rs, cron.rs). You can safely use empty for zero-parameter methods here.

src/lotus_json/actor_states/methods/evm_actor_params.rs (2)

22-65: Constructor Lotus-JSON mapping is consistent across v10–v16.

Field shapes and the snapshots look correct; base64 for RawBytes is aligned with the project’s lotus_json wrapper.


81-128: Delegate-call Lotus-JSON mapping LGTM.

Types and conversions (Cid/RawBytes/EthAddress/TokenAmount) are wired properly with lotus_json wrappers. The snapshot covers the shape and expected encoding.

hanabi1224
hanabi1224 previously approved these changes Aug 20, 2025
@LesnyRumcajs LesnyRumcajs requested review from akaladarshi and removed request for LesnyRumcajs August 21, 2025 09:34
@LesnyRumcajs
Copy link
Member

I'll let the decode params expert review it: @akaladarshi

Copy link
Contributor

@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

🧹 Nitpick comments (2)
src/tool/subcommands/api_cmd/api_compare_tests.rs (2)

1900-1904: Add a quick CBOR equivalence check for GetStorageAt to guard against divergence

GetStorageAtParams in v16 is a tuple with a single U256 field. You’re using a bespoke serialize_params() that constructs the CBOR array header and encodes a RawBytes payload. It’s fine, but worth asserting that it equals the canonical to_vec encoding of the actor’s GetStorageAtParams to avoid subtle regressions if either side changes.

Apply this diff within the function to add a sanity assertion:

@@
-    let evm_get_storage_at_params = GetStorageAtParams::new(vec![0xa])?;
+    let evm_get_storage_at_params = GetStorageAtParams::new(vec![0xa])?;
+    // Sanity: our bespoke encoder matches the actor's canonical CBOR for v16
+    {
+        use fil_actor_evm_state::evm_shared::v16::uints::U256;
+        let mut key = [0u8; 32];
+        key[31] = 0x0a; // same storage position as above
+        let canonical = to_vec(&fil_actor_evm_state::v16::GetStorageAtParams {
+            storage_key: U256::from_big_endian(&key),
+        })?;
+        assert_eq!(
+            evm_get_storage_at_params.serialize_params()?,
+            canonical,
+            "GetStorageAt params CBOR mismatch"
+        );
+    }

Citations: v16 GetStorageAtParams { storage_key: U256 }. (docs.rs)


1904-1944: Nit: avoid repeated parsing of EVM address

You repeatedly call Address::from_str(EVM_ADDRESS).unwrap(). Parse once and reuse; it reduces noise and removes the unwrap() in test assembly code.

Apply this refactor inside evm_actor_state_decode_params_tests:

@@
-    let tests = vec![
+    let evm_addr = Address::from_str(EVM_ADDRESS)?;
+    let tests = vec![
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::Constructor as u64,
             to_vec(&evm_constructor_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::Resurrect as u64,
             to_vec(&evm_constructor_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::GetBytecode as u64,
             vec![],
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::GetBytecodeHash as u64,
             vec![],
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::InvokeContract as u64,
             to_vec(&evm_invoke_contract_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::InvokeContractDelegate as u64,
             to_vec(&evm_delegate_call_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::GetStorageAt as u64,
             evm_get_storage_at_params.serialize_params()?,
             tipset.key().into(),
         ))?),
     ];
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 13a687f and 529531a.

📒 Files selected for processing (2)
  • src/tool/subcommands/api_cmd/api_compare_tests.rs (2 hunks)
  • src/tool/subcommands/api_cmd/test_snapshots.txt (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/tool/subcommands/api_cmd/api_compare_tests.rs (2)
src/rpc/methods/eth/types.rs (4)
  • new (71-81)
  • new (413-418)
  • new (425-427)
  • serialize_params (83-87)
src/blocks/tipset.rs (4)
  • new (242-260)
  • new (494-511)
  • key (336-339)
  • key (530-533)
⏰ 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: Build Ubuntu
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Build MacOS
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: All lint checks
  • GitHub Check: tests
  • GitHub Check: tests-release
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (go)
🔇 Additional comments (6)
src/tool/subcommands/api_cmd/api_compare_tests.rs (4)

1873-1873: Good split: EVM state-decode tests are now isolated and discoverable

Wiring evm_actor_state_decode_params_tests(tipset)? into the main state_decode_params_api_tests keeps concerns separated and makes future EVM additions easier to maintain. Nice.


1883-1899: Param types for Constructor/Invoke/Delegate are correct for v16

  • ConstructorParams { creator, initcode } matches the spec.
  • InvokeContractParams { input_data } is correct.
  • DelegateCallParams { code, input, caller, value } matches the v16 schema.

No issues spotted here.

Citations: fil_actor_evm_state v16 types show these exact structs. (docs.rs)


1910-1914: Resurrect params are correctly reusing ConstructorParams

In v16, ResurrectParams is a type alias to ConstructorParams, so reusing evm_constructor_params here is correct.

Citations: pub type ResurrectParams = ConstructorParams; in v16. (docs.rs)


1916-1944: Method coverage for EVM decode looks complete for v16

Constructor, Resurrect, GetBytecode, GetBytecodeHash, InvokeContract, InvokeContractDelegate, and GetStorageAt are all exercised with plausible params. Good coverage for the stated objective.

Citations: v16 exposes these methods/params in fil_actor_evm_state. (docs.rs)

src/tool/subcommands/api_cmd/test_snapshots.txt (2)

181-187: Snapshots added for all new EVM state-decode cases

The seven EVM snapshots align with the new tests and should stabilize cross-impl compatibility checks.


187-187: Nice: GetStorageAt snapshot included

Including filecoin_evm_getstorageat_statedecodeparams_*.rpcsnap.json.zst ensures the custom serialization path is guarded by golden data.

Copy link
Contributor

@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)
src/rpc/methods/eth/types.rs (1)

89-97: Import anyhow::Context; current .context(..) calls won’t compile

.context(..) is used here (and elsewhere in this file) but anyhow::Context isn’t in scope. Bring the trait into scope to fix the compile error. This was flagged earlier and still applies.

Apply this diff (outside the selected range) to the imports:

- use anyhow::ensure;
+ use anyhow::{ensure, Context};
🧹 Nitpick comments (2)
src/rpc/methods/eth/types.rs (2)

65-65: Clarify magic number: prefer 0x81 and a short doc comment

129 is 0x81 (CBOR array length = 1). Encoding this as hex with a brief comment makes intent obvious.

-const LENGTH_BUF_GET_STORAGE_AT_PARAMS: u8 = 129;
+/// 0x81 == CBOR major type 4 (array) with length = 1
+const LENGTH_BUF_GET_STORAGE_AT_PARAMS: u8 = 0x81;

89-97: Make the prefix-mismatch error actionable

Including the actual prefix helps diagnose malformed inputs quickly.

-        ensure!(
-            prefix == LENGTH_BUF_GET_STORAGE_AT_PARAMS,
-            "expected CBOR array of length 1"
-        );
+        ensure!(
+            prefix == LENGTH_BUF_GET_STORAGE_AT_PARAMS,
+            "expected CBOR array of length 1 (0x81), got 0x{:02x}",
+            prefix
+        );

If useful, I can also add unit tests covering:

  • EOF (empty slice) -> “unexpected EOF”
  • Wrong prefix -> the updated error with the observed byte
  • Valid payload -> roundtrip via serialize_params/deserialize_params
    Want me to push those tests?
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fe0cb6a and 20e52b4.

📒 Files selected for processing (1)
  • src/rpc/methods/eth/types.rs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/rpc/methods/eth/types.rs (2)
src/rpc/methods/eth.rs (3)
  • fvm_ipld_encoding (2212-2212)
  • new (508-520)
  • new (673-678)
src/utils/encoding/fallback_de_ipld_dagcbor.rs (1)
  • from_slice (86-95)
⏰ 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: Build Ubuntu
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Build MacOS
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: tests-release
  • GitHub Check: tests
  • GitHub Check: All lint checks
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (2)
src/rpc/methods/eth/types.rs (2)

83-86: Good perf fix: write CBOR directly instead of insert(0, …)

Pre-sizing with the prefix and using to_writer avoids an extra allocation and memmove. Looks good.


67-69: Deriving Deserialize/Serialize for GetStorageAtParams looks good

This aligns with its usage in RPC plumbing and doesn’t change the CBOR encoding path.

Copy link
Contributor

@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

🧹 Nitpick comments (3)
src/tool/subcommands/api_cmd/api_compare_tests.rs (3)

1883-1899: Param scaffolding for EVM methods looks sensible.

  • ConstructorParams zero-creator and dummy initcode are fine for decode tests.
  • InvokeContractParams and DelegateCallParams shapes look correct; using a default CID and zero TokenAmount is acceptable here since we only validate decoding.

If you want to reduce churn in future edits, consider hoisting common dummy values (e.g., input bytes, initcode) into small consts right above the function to de-duplicate magic literals.


1902-1945: DRY: parse the EVM address once and reuse it.

You repeatedly call Address::from_str(EVM_ADDRESS).unwrap() for each test case. Parse once to a local evm_addr and reuse to avoid repeated fallible parsing and improve readability.

Apply this diff inside the function:

@@
-    let tests = vec![
-        RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+    let evm_addr = Address::from_str(EVM_ADDRESS).expect("valid EVM actor address");
+    let tests = vec![
+        RpcTest::identity(StateDecodeParams::request((
+            evm_addr,
             fil_actor_evm_state::v16::Method::Constructor as u64,
             to_vec(&evm_constructor_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::Resurrect as u64,
             to_vec(&evm_constructor_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::GetBytecode as u64,
             vec![],
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::GetBytecodeHash as u64,
             vec![],
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::InvokeContract as u64,
             to_vec(&evm_invoke_contract_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::InvokeContractDelegate as u64,
             to_vec(&evm_delegate_call_params)?,
             tipset.key().into(),
         ))?),
         RpcTest::identity(StateDecodeParams::request((
-            Address::from_str(EVM_ADDRESS).unwrap(),
+            evm_addr,
             fil_actor_evm_state::v16::Method::GetStorageAt as u64,
             evm_get_storage_at_params.serialize_params()?,
             tipset.key().into(),
         ))?),
     ];

1883-1949: Optional: make tests resilient across protocol versions.

Given EVM methods are only available from v10 onward, you could optionally gate this block based on StateNetworkVersion from tipset and skip when < v10. Not strictly necessary for Calibnet snapshots, but it avoids accidental failures when running against older snapshots.

I can draft a small helper that fetches the network version for tipset and returns Vec<RpcTest> empty if < v10. Want me to add it?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 20e52b4 and f37dca4.

📒 Files selected for processing (1)
  • src/tool/subcommands/api_cmd/api_compare_tests.rs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/tool/subcommands/api_cmd/api_compare_tests.rs (1)
src/rpc/methods/eth/types.rs (4)
  • new (71-81)
  • new (414-419)
  • new (426-428)
  • serialize_params (83-87)
⏰ 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: cargo-publish-dry-run
  • GitHub Check: Build MacOS
  • GitHub Check: Build Ubuntu
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: tests
  • GitHub Check: tests-release
  • GitHub Check: All lint checks
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
src/tool/subcommands/api_cmd/api_compare_tests.rs (3)

1873-1873: Good call: wire EVM state-decode tests into the suite.

This plugs the new EVM cases into the existing StateDecodeParams test assembly at the right place. No functional concerns.


1909-1914: Resurrect using ConstructorParams is correct.

In the EVM actor API, ResurrectParams is an alias of ConstructorParams for v10+; using the same CBOR for both is expected. (docs.rs)


1940-1944: Correct encoding for GetStorageAt params.

Using GetStorageAtParams::serialize_params() is the right choice here – it prefixes the sentinel length byte and CBOR-encodes the RawBytes payload as expected by the EVM actor’s decode path. This should keep Forest/Lotus parity for these tests.

If you want to harden this further, we can add an additional negative test with a position > 32 bytes and assert both nodes reject with the same error.

Copy link
Collaborator

@akaladarshi akaladarshi left a comment

Choose a reason for hiding this comment

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

LGTM

@sudo-shashank sudo-shashank added this pull request to the merge queue Aug 25, 2025
Merged via the queue into main with commit e770f5b Aug 25, 2025
44 checks passed
@sudo-shashank sudo-shashank deleted the shashank/evm-state-decode-params branch August 25, 2025 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RPC requires calibnet RPC checks to run on CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for the EVM actor state in Filecoin.StateDecodeParams API

5 participants