Skip to content

fix(bridge): fix bridge invocation hook#393

Merged
dmitry123 merged 2 commits into
develfrom
fix/fix-bridge-hook
Apr 16, 2026
Merged

fix(bridge): fix bridge invocation hook#393
dmitry123 merged 2 commits into
develfrom
fix/fix-bridge-hook

Conversation

@dmitry123

@dmitry123 dmitry123 commented Apr 16, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of malformed bridge transactions on testnet.
    • Enhanced support for nested function calls within bridge operations.
  • Tests

    • Added test coverage for nested calls in bridge precompile execution.
    • Added test fixtures for bridge malformed parameter scenarios.

Signed-off-by: Dmitry Savonin <github@dmitry123.xyz>
@coderabbitai

coderabbitai Bot commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@dmitry123 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 44 minutes and 56 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 44 minutes and 56 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4668ee5b-77a9-487e-a04f-a65aeca3c334

📥 Commits

Reviewing files that changed from the base of the PR and between 6a732d7 and de2a332.

📒 Files selected for processing (1)
  • crates/revm/src/bridge.rs
📝 Walkthrough

Walkthrough

The PR refactors bridge hook invocation patterns by moving the pre-invocation hook from inspect_frame_run and frame_run to frame_init, and updates both hook signatures to accept frame/inputs objects for direct parameter access instead of context-only derivation. It adds malformed testnet transaction handling and test coverage for nested bridge calls.

Changes

Cohort / File(s) Summary
Bridge Hook Refactoring
crates/revm/src/bridge.rs
Updated apply_bridge_pre_invocation_hook to accept inputs: &Box<CallInputs> and derive calldata via inputs.input.bytes(ctx); updated apply_bridge_post_invocation_hook to accept frame: &mut RwasmFrame, added special-case handling for corrupted testnet transactions, and switched journal access to ctx.journal(). Replaced hardcoded message decoders with generic try_decode_receive_message_value and added try_decode_send_message_value helper.
Hook Invocation Relocation
crates/revm/src/evm.rs
Relocated pre-invocation hook call from inspect_frame_run and frame_run to frame_init (FrameInput::Call branch); updated all post-invocation hook calls to pass frame parameter instead of ctx only.
Test Coverage
e2e/src/bridge.rs
Added test_nested_call_inside_bridge_cant_fail_execution test to validate bridge processing with nested CALL frames and message emission.
E2E Test Fixtures
evm-e2e/src/fixtures.rs
Added three new fluent testnet E2E test fixtures for malformed bridge parameter scenarios (testnet_24293147_bridge_malformed_params_[1-3]).

Sequence Diagram(s)

sequenceDiagram
    participant FrameInit as frame_init()
    participant PreHook as apply_bridge_pre_invocation_hook
    participant FrameRun as frame_run()
    participant PostHook as apply_bridge_post_invocation_hook
    participant Execution as Interpreter Execution

    rect rgba(100, 150, 200, 0.5)
    Note over FrameInit,PostHook: Old Flow (Pre-Hook in frame_run)
    FrameInit->>FrameRun: initialize frame
    FrameRun->>PreHook: call with ctx
    PreHook->>FrameRun: return
    FrameRun->>Execution: execute
    Execution->>PostHook: call with ctx
    end

    rect rgba(150, 200, 100, 0.5)
    Note over FrameInit,PostHook: New Flow (Pre-Hook in frame_init)
    FrameInit->>FrameInit: match FrameInput::Call(inputs)
    FrameInit->>PreHook: call with inputs
    PreHook->>FrameInit: return
    FrameInit->>FrameRun: initialize frame
    FrameRun->>Execution: execute
    Execution->>PostHook: call with frame
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hooks hop from run to init with care,
Pre-invocation moves with flair,
Frames now know their inputs true,
Bridge messages decode anew,
Malformed txns caught with might! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(bridge): fix bridge invocation hook' directly relates to the main changes in the pull request, which involve refactoring and fixing the bridge invocation hooks (both pre and post) across multiple files to correct their timing, parameters, and logic.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/fix-bridge-hook

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (2)
crates/revm/src/bridge.rs (1)

266-277: Consider returning meaningful data from try_decode_send_message_value.

The function currently returns Option<()> which just indicates presence. While functional, consider returning Option<sendMessageCall> to match the pattern of try_decode_receive_message_value which returns the decoded value. This would provide consistency and allow future use of the decoded data without re-decoding.

♻️ Suggested improvement
-fn try_decode_send_message_value<T: AsRef<[u8]>>(input: T) -> Option<()> {
+fn try_decode_send_message_value<T: AsRef<[u8]>>(input: T) -> Option<sendMessageCall> {
     let input = input.as_ref();
 
     if input.starts_with(&sendMessageCall::SELECTOR) {
-        // Decode an ABI message (it should be correct)
-        if let Ok(_message) = sendMessageCall::abi_decode(input) {
-            return Some(());
-        };
+        if let Ok(message) = sendMessageCall::abi_decode(input) {
+            return Some(message);
+        }
     }
 
     None
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/revm/src/bridge.rs` around lines 266 - 277, Change
try_decode_send_message_value to return Option<sendMessageCall> instead of
Option<()>: in function try_decode_send_message_value<T: AsRef<[u8]>>(input: T)
-> Option<sendMessageCall>, call sendMessageCall::abi_decode(input.as_ref()),
bind the result to a variable (e.g., message) and return Some(message) on Ok,
otherwise return None; update the internal branch that currently uses if let
Ok(_message) to capture and return the decoded value so it matches the pattern
of try_decode_receive_message_value and avoids re-decoding at call sites.
evm-e2e/src/fixtures.rs (1)

19-21: Test names don't match fixture file block numbers.

The test function names all use 24293147 but the fixture paths reference different block numbers (24293144, 24293146, 24293147). This creates confusion when debugging test failures. All fixture files exist and are correctly referenced, but the naming inconsistency should be resolved.

Consider aligning the test names with their fixture file names for clarity:

♻️ Suggested fix
-        fn testnet_24293147_bridge_malformed_params_1("fixtures/testnet_24293144_bridge_malformed_params_1.json");
-        fn testnet_24293147_bridge_malformed_params_2("fixtures/testnet_24293146_bridge_malformed_params_2.json");
-        fn testnet_24293147_bridge_malformed_params_3("fixtures/testnet_24293147_bridge_malformed_params_3.json");
+        fn testnet_24293144_bridge_malformed_params_1("fixtures/testnet_24293144_bridge_malformed_params_1.json");
+        fn testnet_24293146_bridge_malformed_params_2("fixtures/testnet_24293146_bridge_malformed_params_2.json");
+        fn testnet_24293147_bridge_malformed_params_3("fixtures/testnet_24293147_bridge_malformed_params_3.json");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@evm-e2e/src/fixtures.rs` around lines 19 - 21, Rename the test functions so
their names match the fixture file block numbers to avoid confusion: change
testnet_24293147_bridge_malformed_params_1 to
testnet_24293144_bridge_malformed_params_1 (for
"fixtures/testnet_24293144_bridge_malformed_params_1.json"), change
testnet_24293147_bridge_malformed_params_2 to
testnet_24293146_bridge_malformed_params_2 (for
"fixtures/testnet_24293146_bridge_malformed_params_2.json"), and ensure
testnet_24293147_bridge_malformed_params_3 remains or is explicitly named
testnet_24293147_bridge_malformed_params_3 to match
"fixtures/testnet_24293147_bridge_malformed_params_3.json"; update any
references/imports to these function names accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/revm/src/bridge.rs`:
- Around line 84-96: The special-case branch that checks ctx.tx().chain_id() ==
Some(0x5202), ctx.tx().caller() ==
address!("0x1C92DffBCe76670F69007F22A54e31ff3Ab45d5E"),
[537u64,538u64,539u64].contains(&ctx.tx().nonce()), and ctx.journal().depth() ==
3 before setting *next_action = malformed_interpreter_action() is fragile and
silent; confirm the journal depth is correct for all three nonces (adjust or
broaden the depth check on ctx.journal().depth() if necessary) and add a warning
log (e.g., warn! or trace!) inside this branch that includes chain id, caller,
nonce and journal depth so you can observe when the workaround triggers. Ensure
the log call is placed immediately before assigning
malformed_interpreter_action() to next_action.

---

Nitpick comments:
In `@crates/revm/src/bridge.rs`:
- Around line 266-277: Change try_decode_send_message_value to return
Option<sendMessageCall> instead of Option<()>: in function
try_decode_send_message_value<T: AsRef<[u8]>>(input: T) ->
Option<sendMessageCall>, call sendMessageCall::abi_decode(input.as_ref()), bind
the result to a variable (e.g., message) and return Some(message) on Ok,
otherwise return None; update the internal branch that currently uses if let
Ok(_message) to capture and return the decoded value so it matches the pattern
of try_decode_receive_message_value and avoids re-decoding at call sites.

In `@evm-e2e/src/fixtures.rs`:
- Around line 19-21: Rename the test functions so their names match the fixture
file block numbers to avoid confusion: change
testnet_24293147_bridge_malformed_params_1 to
testnet_24293144_bridge_malformed_params_1 (for
"fixtures/testnet_24293144_bridge_malformed_params_1.json"), change
testnet_24293147_bridge_malformed_params_2 to
testnet_24293146_bridge_malformed_params_2 (for
"fixtures/testnet_24293146_bridge_malformed_params_2.json"), and ensure
testnet_24293147_bridge_malformed_params_3 remains or is explicitly named
testnet_24293147_bridge_malformed_params_3 to match
"fixtures/testnet_24293147_bridge_malformed_params_3.json"; update any
references/imports to these function names accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3c4e1728-3ea1-4444-b1cf-c7dca6f4af24

📥 Commits

Reviewing files that changed from the base of the PR and between ea4b224 and 6a732d7.

📒 Files selected for processing (7)
  • crates/revm/src/bridge.rs
  • crates/revm/src/evm.rs
  • e2e/src/bridge.rs
  • evm-e2e/fixtures/testnet_24293144_bridge_malformed_params_1.json
  • evm-e2e/fixtures/testnet_24293146_bridge_malformed_params_2.json
  • evm-e2e/fixtures/testnet_24293147_bridge_malformed_params_3.json
  • evm-e2e/src/fixtures.rs

Comment thread crates/revm/src/bridge.rs
Comment on lines +84 to +96
// A special case for corrupted bridge transaction on testnet, where we issued 3
// transactions from relayer that caused execution failure. We keep it here only to
// make blockchain syncable for testnet.
//
// Note: it can be removed once we have new snapshot for testnet
if ctx.tx().chain_id() == Some(0x5202)
&& ctx.tx().caller() == address!("0x1C92DffBCe76670F69007F22A54e31ff3Ab45d5E")
&& [537u64, 538u64, 539u64].contains(&ctx.tx().nonce())
&& ctx.journal().depth() == 3
{
*next_action = malformed_interpreter_action();
return Ok(());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if there are any related tests or documentation for the malformed transactions
rg -n "537|538|539" --type rust -C3 | grep -i "nonce\|bridge\|malformed" | head -40

Repository: fluentlabs-xyz/fluentbase

Length of output: 633


🏁 Script executed:

# Search for malformed_interpreter_action function and its usage
rg -n "malformed_interpreter_action" --type rust -B2 -A2

Repository: fluentlabs-xyz/fluentbase

Length of output: 2440


🏁 Script executed:

# Look for tests related to bridge or malformed transactions
fd -name "*.rs" -type f | xargs grep -l "malformed\|corrupted" | head -10

Repository: fluentlabs-xyz/fluentbase

Length of output: 299


🏁 Script executed:

# Check the context around the bridge.rs file for related functions or test modules
cat -n crates/revm/src/bridge.rs | head -100

Repository: fluentlabs-xyz/fluentbase

Length of output: 3965


🏁 Script executed:

# Search for journal.depth() usage patterns in the codebase
rg -n "journal.*depth\(\)" --type rust -B2 -A2 | head -50

Repository: fluentlabs-xyz/fluentbase

Length of output: 463


Testnet special case for corrupted bridge transactions.

The hardcoded conditions (chain ID 0x5202, specific caller, nonces 537-539, journal depth 3) create a narrow workaround for known corrupted transactions. The comment correctly notes this is temporary until a new testnet snapshot is available.

Two points worth addressing:

  1. The journal depth check (depth() == 3) is uniquely specific to this workaround and appears nowhere else in the codebase. If these transactions ever create nested frames differently, the condition will silently fail to trigger. Verify this depth is correct for all three corrupted nonces.
  2. No logging occurs when this branch executes, making it difficult to debug if the workaround is triggered unexpectedly or not at all. Consider adding a warn! or trace! log statement when this condition matches.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/revm/src/bridge.rs` around lines 84 - 96, The special-case branch that
checks ctx.tx().chain_id() == Some(0x5202), ctx.tx().caller() ==
address!("0x1C92DffBCe76670F69007F22A54e31ff3Ab45d5E"),
[537u64,538u64,539u64].contains(&ctx.tx().nonce()), and ctx.journal().depth() ==
3 before setting *next_action = malformed_interpreter_action() is fragile and
silent; confirm the journal depth is correct for all three nonces (adjust or
broaden the depth check on ctx.journal().depth() if necessary) and add a warning
log (e.g., warn! or trace!) inside this branch that includes chain id, caller,
nonce and journal depth so you can observe when the workaround triggers. Ensure
the log call is placed immediately before assigning
malformed_interpreter_action() to next_action.

@github-actions

github-actions Bot commented Apr 16, 2026

Copy link
Copy Markdown

Criterion results (vs baseline)


running 102 tests


deployment gas used: 878183
Tokens Transfer Comparison/1_Original_EVM_ERC20
                        time:   [7.6575 µs 7.8123 µs 7.9845 µs]
Found 135 outliers among 1000 measurements (13.50%)
  84 (8.40%) high mild
  51 (5.10%) high severe
deployment gas used: 878183
Tokens Transfer Comparison/2_Emulated_EVM_ERC20
                        time:   [27.397 µs 27.612 µs 27.837 µs]
Found 130 outliers among 1000 measurements (13.00%)
  65 (6.50%) high mild
  65 (6.50%) high severe
deployment gas used: 3779298
Tokens Transfer Comparison/3_rWasm_Contract_ERC20
                        time:   [161.18 µs 164.35 µs 167.89 µs]
Found 101 outliers among 1000 measurements (10.10%)
  68 (6.80%) high mild
  33 (3.30%) high severe
deployment gas used: 65479
Tokens Transfer Comparison/4_Precompiled_Universal_token
                        time:   [10.133 µs 10.180 µs 10.234 µs]
Found 119 outliers among 1000 measurements (11.90%)
  60 (6.00%) high mild
  59 (5.90%) high severe

deployment gas used: 359938
Greeting Contract Comparison/Original_Greeting
                        time:   [4.3335 µs 4.4098 µs 4.5027 µs]
Found 10 outliers among 100 measurements (10.00%)
  5 (5.00%) high mild
  5 (5.00%) high severe
deployment gas used: 359938
Greeting Contract Comparison/EVM_Greeting
                        time:   [9.2235 µs 9.3745 µs 9.5300 µs]
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
deployment gas used: 67635
Greeting Contract Comparison/WASM_Greeting
                        time:   [17.592 µs 17.798 µs 18.006 µs]
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

Heads-up: runner perf is noisy; treat deltas as a smoke check.

Signed-off-by: Dmitry Savonin <github@dmitry123.xyz>
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