Skip to content

feat(simapp): Wire rate limitting middleware to v2 in simapp#8919

Open
Eric-Warehime wants to merge 2 commits intomainfrom
eric/simapp-wiring
Open

feat(simapp): Wire rate limitting middleware to v2 in simapp#8919
Eric-Warehime wants to merge 2 commits intomainfrom
eric/simapp-wiring

Conversation

@Eric-Warehime
Copy link
Copy Markdown
Contributor

Description

Wire rate limitting into v2 transfer stack within simapp.

closes: #XXXX


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Linked to GitHub issue with discussion and accepted design, OR link to spec that describes this work.
  • Include changelog entry when appropriate (e.g. chores should be omitted from changelog).
  • Wrote unit and integration tests if relevant.
  • Updated documentation (docs/) if anything is changed.
  • Added godoc comments if relevant.
  • Self-reviewed Files changed in the GitHub PR explorer.
  • Provide a conventional commit message to follow the repository standards.

@Eric-Warehime Eric-Warehime requested a review from a team as a code owner April 28, 2026 18:27
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 28, 2026

Greptile Summary

This PR wires the rate-limiting v2 middleware in front of the ICS-20 v2 transfer module within simapp, mirroring the existing v1 middleware stack. A thin v2ToV1Packet adapter bridges v2 payload types to the v1 keeper methods.

  • Outgoing sends on native IBC v2 paths (non-aliased client IDs) will be unconditionally blocked: SendRateLimitedPacket calls channelKeeper.GetNextSequenceSend(ctx, port, sourceClient) where sourceClient is a client ID for pure v2 paths — no channel-sequence entry exists for those identifiers, so the function always returns ErrSequenceSendNotFound and the packet is rejected before reaching the transfer module.
  • The keeper is passed as a value copy (*app.RateLimitKeeper) rather than as a pointer, diverging from the v1 convention and creating a potential for silent state divergence if SetICS4Wrapper is called after this line in the future.

Confidence Score: 3/5

Not safe to merge as-is; native IBC v2 sends on non-aliased paths are unconditionally blocked by the current keeper implementation.

A P1 defect where any outgoing native IBC v2 transfer (non-aliased client ID) triggers ErrSequenceSendNotFound inside SendRateLimitedPacket and is rejected, plus the pre-existing TODO in v2ToV1Packet flagging the conversion as potentially incorrect.

modules/apps/rate-limiting/v2/ibc_middleware.go — the v2ToV1Packet TODO and the OnSendPacket path that calls SendRateLimitedPacket need review before simapp can safely enable this middleware.

Important Files Changed

Filename Overview
simapp/app.go Wires the rate-limiting v2 middleware into the v2 transfer stack; introduces a P1 bug where native (non-aliased) IBC v2 sends are unconditionally blocked by GetNextSequenceSend returning not-found for client IDs, and a P2 value-copy inconsistency vs. the v1 middleware.

Sequence Diagram

sequenceDiagram
    participant Core as IBC Core v2
    participant RL as RateLimiting v2 Middleware
    participant Transfer as Transfer v2 Module
    participant Keeper as RateLimitKeeper

    Note over Core,Transfer: OnSendPacket (v2 path)
    Core->>RL: OnSendPacket(sourceClient, destClient, payload)
    RL->>RL: v2ToV1Packet(payload, sourceClient, destClient)
    RL->>Keeper: SendRateLimitedPacket(sourcePort, sourceClient, ...)
    alt sourceClient is aliased channel-ID
        Keeper->>Keeper: GetNextSequenceSend(port, channelID) ✅
        Keeper->>Keeper: CheckRateLimitAndUpdateFlow
        Keeper-->>RL: nil (allowed)
        RL->>Transfer: OnSendPacket(...)
    else sourceClient is native v2 client-ID
        Keeper->>Keeper: GetNextSequenceSend(port, clientID) ❌ not found
        Keeper-->>RL: ErrSequenceSendNotFound
        RL-->>Core: error (packet blocked)
    end
Loading

Reviews (1): Last reviewed commit: "Add changelog" | Re-trigger Greptile

Comment thread simapp/app.go
// IBC core surfaces the original v1 channel id (e.g. "channel-X") as the
// source/destination client, so v2 transfers on those paths share the same
// (denom, channelOrClientID) rate-limit keys as classic ICS-20 transfers.
transferStackV2 := ratelimitingv2.NewIBCMiddleware(*app.RateLimitKeeper, transferv2.NewIBCModule(app.TransferKeeper))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Native IBC v2 sends blocked for non-aliased client paths

SendRateLimitedPacket begins by calling k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) where sourceChannel is the sourceClient string from the v2 packet. For native IBC v2 paths that use actual client IDs (e.g. "07-tendermint-0") rather than aliased channel IDs, no channel-sequence entry is stored, so GetNextSequenceSend returns !found and the function immediately returns ErrSequenceSendNotFound — blocking the outgoing transfer entirely, regardless of whether any rate-limit quota is configured for that path.

The existing comment acknowledges this works for aliased v1 channels, but any native v2 client path will be unconditionally rejected by OnSendPacket. The v2 middleware should check whether the identifier corresponds to an aliased channel and skip the GetNextSequenceSend path (or skip the pending-packet tracking entirely) for native v2 client IDs.

Comment thread simapp/app.go
// IBC core surfaces the original v1 channel id (e.g. "channel-X") as the
// source/destination client, so v2 transfers on those paths share the same
// (denom, channelOrClientID) rate-limit keys as classic ICS-20 transfers.
transferStackV2 := ratelimitingv2.NewIBCMiddleware(*app.RateLimitKeeper, transferv2.NewIBCModule(app.TransferKeeper))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Value copy of keeper may drift from the singleton

*app.RateLimitKeeper dereferences the pointer and passes a shallow value copy of the keeper to NewIBCMiddleware. The v2 IBCMiddleware stores this copy by value (keeper keeper.Keeper). Any future call to app.RateLimitKeeper.SetICS4Wrapper(...) — e.g. added during stack-wiring refactors — would update only the original pointer and not the copy inside the v2 middleware. The v1 stack avoids this by passing the pointer directly. Consider accepting *keeper.Keeper in NewIBCMiddleware (mirroring the v1 signature) to keep both stacks consistent and resilient to future wiring changes.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.52%. Comparing base (41bc2d4) to head (e8b38aa).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8919   +/-   ##
=======================================
  Coverage   66.52%   66.52%           
=======================================
  Files         327      327           
  Lines       17143    17143           
=======================================
  Hits        11404    11404           
  Misses       5048     5048           
  Partials      691      691           
Flag Coverage Δ
08-wasm 65.04% <ø> (ø)
ibc-go 66.57% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread simapp/app.go
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you also wire this in testing/simapp/app.go

Comment thread simapp/app.go
// IBC core surfaces the original v1 channel id (e.g. "channel-X") as the
// source/destination client, so v2 transfers on those paths share the same
// (denom, channelOrClientID) rate-limit keys as classic ICS-20 transfers.
transferStackV2 := ratelimitingv2.NewIBCMiddleware(*app.RateLimitKeeper, transferv2.NewIBCModule(app.TransferKeeper))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think there is a problem in the rate limit v2, this keeper should have taken a pointer rather than a copy. So that we can have:

Suggested change
transferStackV2 := ratelimitingv2.NewIBCMiddleware(*app.RateLimitKeeper, transferv2.NewIBCModule(app.TransferKeeper))
transferStackV2 := ratelimitingv2.NewIBCMiddleware(app.RateLimitKeeper, transferv2.NewIBCModule(app.TransferKeeper))

This should be a simple change in ratelimitingv2.

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