Skip to content

Remove IBC leftovers and delete retired IBC stores at v6.8 - #4337

Merged
masih merged 7 commits into
mainfrom
masih/1790336853-remove-ibc-leftovers
Oct 1, 2026
Merged

masih merged 7 commits into
mainfrom
masih/1790336853-remove-ibc-leftovers

Conversation

@masih

@masih masih commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

After the IBC modules were unwired, the chain still carried their leftovers: the capability, ibc and transfer stores stayed mounted, app/retiredibc intercepted /store/ibc/* raw queries and kept decode-only codecs for the historical /ibc.core.client.v1.* governance proposals, the transfer module account kept minter/burner permissions, and seidb tooling and docs still listed the IBC stores. IBC is never coming back, so none of this compatibility layer should survive.

This PR removes that layer and cleans the persisted state at the v6.8 boundary. The capability, ibc and transfer stores are unmounted from both app.App and the wasmd test app and are deleted alongside oracle through the v6.8 UpgradeStoreLoader, with their module-version entries dropped by the handler. Mainnet holds four passed IBC governance proposals whose Any content can no longer be decoded once the codecs go, which would break IterateProposals and genesis export, so rewriteRetiredIBCProposals rewrites any proposal with a /ibc. type URL in place as a TextProposal, reading title and description from the raw protobuf bytes with protowire and leaving IDs, status, deposits, votes and queue entries untouched. pruneUpgradedIBCState removes the upgradedIBCState/* keys from the upgrade store. Bank balances and supply are deliberately not touched: the 96 ibc/* voucher denominations on mainnet remain ordinary bank coins. Two things are kept on purpose. The IBC precompile at 0x1009 stays registered, in both the regular and Giga fail-fast engines, as a tombstone that reverts every call, because deleting it would turn the address into an empty account where low-level calls succeed and value gets stranded. The deterministic transfer module address stays in the bank blocked-address set through retiredModuleAccounts, without any module or permissions behind it, so nothing can be sent to an account no key or module can spend from.

This is a consensus-affecting state migration and reviewers should focus on the v6.8 handler and the store loader. Coverage is in app/upgrade_v68_test.go (module versions, proposal rewrite, upgrade-state pruning, second application is a no-op) and the offline v6.8 source/target fixtures, which seed the four deleted stores, an IBC proposal, an upgraded-IBC-state key and an ibc/* voucher, then assert physical tree deletion after reopen, crash/replay hash equality, the rewritten proposal, the pruned keys, a successful post-upgrade bank send of the voucher, and that every other key of the retained bank, gov and upgrade stores is unchanged apart from the entries the upgrade block is specified to touch. make upgrade-test, make upgrade-test-vet, make upgrade-test-offline FROM_REF=release/v6.7 and make lint pass.

The proposal rewrite runs before RunMigrations so no module migration can walk the gov store while the four /ibc.core.client.v1.ClientUpdateProposal records are still undecodable. It keeps title and description and drops the client fields, recorded here so the loss is explicit rather than silent: proposal 52 subject_client_id=07-tendermint-44 substitute_client_id=07-tendermint-112; 81 07-tendermint-120 / 07-tendermint-131; 100 07-tendermint-135 / 07-tendermint-146; 119 07-tendermint-12 / 07-tendermint-168. After this upgrade v6.8 nodes cannot answer gov state queries at pre-v6.8 heights for those four proposals, nor any other pre-retirement IBC history; that is served by v6.6 freeze nodes, and the README states so.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedOct 1, 2026, 9:09 AM

@codecov

codecov Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 47.14286% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.55%. Comparing base (7f94d23) to head (53e21bb).

Files with missing lines Patch % Lines
app/upgrades.go 36.84% 36 Missing ⚠️
app/app.go 75.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4337      +/-   ##
==========================================
- Coverage   55.56%   55.55%   -0.02%     
==========================================
  Files        2173     2170       -3     
  Lines      168616   168610       -6     
==========================================
- Hits        93699    93676      -23     
- Misses      74912    74929      +17     
  Partials        5        5              
Flag Coverage Δ
sei-chain 53.69% <47.14%> (-0.02%) ⬇️
sei-db 74.81% <ø> (-0.25%) ⬇️
sei-db-state-db 78.62% <ø> (+<0.01%) ⬆️

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

Files with missing lines Coverage Δ
app/encoding.go 100.00% <ø> (ø)
evmrpc/tests/utils.go 79.65% <100.00%> (+0.48%) ⬆️
precompiles/gov/handler.go 94.38% <ø> (+1.04%) ⬆️
sei-db/common/keys/store_keys.go 100.00% <ø> (ø)
sei-wasmd/app/app.go 74.51% <100.00%> (-1.29%) ⬇️
tools/utils/helper.go 0.00% <ø> (ø)
app/app.go 51.70% <75.00%> (-0.17%) ⬇️
app/upgrades.go 44.54% <36.84%> (-12.36%) ⬇️

... and 24 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@devin-ai-integration
devin-ai-integration Bot force-pushed the masih/1790336853-remove-ibc-leftovers branch from 2ae54fc to 8db2abe Compare September 25, 2026 14:27
Base automatically changed from masih/1790245567-remove-oracle-blockers to main September 25, 2026 18:09
The transfer module account is no longer created at genesis, so accounts
created by the evmrpc test initializers shift down by one.
@devin-ai-integration
devin-ai-integration Bot force-pushed the masih/1790336853-remove-ibc-leftovers branch from 8db2abe to 6167fce Compare September 25, 2026 20:09
@masih
masih marked this pull request as ready for review September 25, 2026 21:42
@cursor

cursor Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

PR Summary

High Risk
Consensus-affecting v6.8 migration deletes multistore trees and rewrites on-chain governance records; incorrect handler or loader logic could break upgrades or alter gov/historical query semantics.

Overview
v6.8 physically removes the capability, ibc, and transfer KV stores (with oracle) via UpgradeStoreLoader, drops their module-version entries, rewrites any governance proposal whose content type starts with /ibc. into a TextProposal (title/description parsed from raw protobuf before migrations), and prunes upgradedIBCState/* from the upgrade store. IBC voucher bank balances are not migrated or burned.

The post-v6.7 compatibility shim is removed: app/retiredibc (deprecated store-query responses and decode-only IBC gov types), IBC store keys from app/sei-db/tooling, genesis transfer module-account materialization, and the retired IBC gov router. Raw /store/ibc|transfer|capability/* queries now fail with ErrUnknownRequest instead of a custom “deprecated” error. The deterministic transfer module address stays blocked through retiredModuleAccounts so funds cannot be sent to an unspendable account.

README documents v6.8 behavior (including the four mainnet ClientUpdateProposal rewrites and freeze-node guidance). Offline and in-process v6.8 tests cover store tree deletion, proposal rewrite, voucher spendability, and retained-store invariants.

Reviewed by Cursor Bugbot for commit 53e21bb. Bugbot is set up for automated code reviews on this repo. Configure here.

@seidroid seidroid Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The v6.8 migration looks correct, and the tests cover it well. It deletes the capability, ibc and transfer stores alongside oracle, rewrites stored /ibc.* proposals as TextProposals by reading their raw protobuf fields, and prunes the upgradedIBCState keys. The remaining notes are about behaviour visible to users: dropping the 0x1009 precompile, and removing transfer from maccPerms.

Findings: 0 blocking | 3 non-blocking | 2 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • [suggestion] Removing the transfer entry from maccPerms (app/app.go and sei-wasmd/app/app.go) also drops the transfer module address from ModuleAccountAddrs(), so bank no longer blocks sends to it. After v6.8, a user can send coins to the old transfer module account and they are stuck there for good. If that is intended, say so in the PR description; if not, keep the address on the blocked list without Minter/Burner permissions.
  • 2 suggestion(s)/nit(s) flagged inline on specific lines.

Comment thread precompiles/setup.go
Comment thread app/testdata/upgrade_v68_offline_source_test.go
Comment thread app/upgrades.go
// proposal whose type lives under an IBC protobuf package with a TextProposal
// carrying the original title and description. The proposal record, its
// deposits, votes and tally indexes are left untouched.
func (app *App) rewriteRetiredIBCProposals(ctx sdk.Context) {

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.

is this so we can remove the ibc proto type from the chain? do we want to leave retired protobufs in a deprecated folder instead?
i'm thinking through some compatibility scenarios in which this could break (i don't have a concrete scenario in mind)

i'm not particularly opinionated, i'm just thinking aloud there

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.

Yes, that's exactly why. Mainnet has four passed proposals (52, 81, 100, 119) stored as Any{/ibc.core.client.v1.ClientUpdateProposal}. Once the IBC proto types are no longer registered in the interface registry, every code path that unpacks all proposals (gov gRPC/REST Proposals, ExportGenesis, CLI queries, IterateProposals in the gov keeper) panics or errors on those four records. Rewriting them to TextProposal with the original title/description keeps the records readable with no type left behind.

The alternative you describe is what the tree had until this PR: app/retiredibc kept decode-only registrations of the retired proposal types (and a raw-query interceptor) so the stored Anys still resolved. The direction I got for this PR was to remove that layer entirely since IBC will never be re-enabled, hence the one-shot rewrite in the v6.8 handler instead.

Compatibility-wise, the observable differences after v6.8 are: (1) gov queries for those four proposals return @type: /cosmos.gov.v1beta1.TextProposal instead of the IBC type, so an indexer diffing proposal content will see the change once; (2) clients that still send an /ibc.* proposal in MsgSubmitProposal get a codec "unable to resolve type URL" error at decode rather than a gov handler error, which is already the case today for submitting them since no handler is routed. Replay of pre-v6.8 heights is unaffected because that runs the old binary. Nothing else references the types (no txs, no other stores; the upgradedIBCState keys are pruned in the same handler). If you'd rather keep the deprecated-decode-only approach, it's a straightforward revert of the retiredibc deletion plus dropping rewriteRetiredIBCProposals; I'd just want the call made explicitly since it keeps IBC protos compiled into the binary indefinitely.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@philipsu522 taking the approach of doing a one-off conversion was on purpose on my side. It lets us be explicit and never need to carry over the original types again while avoiding panics during decode.

In terms of someone needing this, we are covered by freeze mode on that which makes moving types around a much easier job to reason about in terms of usability.

But I have no strongly held opinions on this one. Happy to revert back to keeping the protos if you think it's worth it.

@masih

masih commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator Author

Holding off merging this until #4328 lands for easier merge mechanics.

@masih

masih commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator Author

@seidroid review

@seidroid seidroid Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The v6.8 migration looks correct. It deletes the capability, ibc and transfer stores together with oracle, rewrites /ibc.* proposals as TextProposals by reading their raw protobuf fields (title and description) before RunMigrations, and prunes the upgradedIBCState keys. The transfer module address stays blocked through retiredModuleAccounts, and the 0x1009 tombstone is kept, so both earlier review points are addressed. No new blocking or non-blocking issues found.

Findings: 0 blocking | 0 non-blocking | 0 posted inline

Blockers

  • None at the file/PR level.

Non-blocking

  • None at the file/PR level.

@seidroid seidroid Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This PR removes the retired IBC compatibility layer (the query intercept, the decode-only gov codecs, the transfer module permissions and the mounted capability/ibc/transfer stores). At v6.8 it deletes those stores, rewrites the stored /ibc.* proposals as TextProposals before RunMigrations, and prunes the upgradedIBCState/ keys from the upgrade store. Nothing blocks: the handler ordering, the store-loader deletion list, the version-map cleanup and the protowire title/description extraction are all correct, and the tests cover them; a Go toolchain was not available in the sandbox, so the tests were not run. Of the independent readings I dropped codex's single finding, that deleteByPrefix stores iterator keys without copying them: the memiavl iterator clones keys unless zero-copy is set, zero-copy keys point at immutable tree nodes, and the repo's own dbadapter.Store.DeleteAll uses the same pattern.

Non-blocking

  • New chains no longer create the transfer module account at genesis, so genesis account numbers shift by one (hence the evmrpc tests moving from account 8 to 7). Existing chains are unaffected, but any external fixture or tooling that hardcodes post-genesis account numbers will need the same update.
1 nit, not posted on the code
  • app/upgrades.go:208 — A malformed Content.Value on any /ibc.* proposal panics inside the v6.8 handler and halts the chain at the upgrade height. That is acceptable for the four known mainnet records, but logging the error and keeping an empty title or description would be a softer failure mode for a one-shot migration.

seidroid review · decision approve · session 08c0c611c08e47e0bea6995341c4c3dd · turn resp_claude_e686e214b4d92e52a603fd078aca94fc · item d4d703e7e98753d7a958146c93858330

Findings: 0 blocking | 1 non-blocking | 0 posted inline

@masih
masih enabled auto-merge October 1, 2026 09:17
@masih
masih added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit 299613c Oct 1, 2026
63 checks passed
@masih
masih deleted the masih/1790336853-remove-ibc-leftovers branch October 1, 2026 09:33
revofusion pushed a commit to revofusion/sei-chain that referenced this pull request Oct 2, 2026
…ei-protocol#4340)

With the IBC modules gone and sei-protocol#4337 deleting their stores at v6.8,
`x/upgrade` still carried the machinery that existed only to serve IBC
light-client upgrades: the
`upgradedIBCState/<height>/upgradedClient|upgradedConsState` keys and
their `SetUpgradedClient`/`GetUpgradedConsensusState`/`ClearIBCState`
keeper helpers, the deprecated `Plan.upgraded_client_state` field and
its `ValidateBasic` rejection, the `Query/UpgradedConsensusState` gRPC
and REST route, and the `upgradedConsensusState` method on the upgrade
precompile at 0x1015. None of it has a consumer on Sei, and keeping it
means keeping a path that writes IBC state back into the upgrade store.

This removes all of it. `ScheduleUpgrade`, `ClearUpgradePlan` and
`ApplyUpgrade` no longer touch IBC keys; `Plan` reserves field 5 rather
than carrying a dead `Any`; the upgrade query service loses the
deprecated rpc and its request/response messages, with `query.pb.go`,
`query.pb.gw.go`, `upgrade.pb.go` and the swagger regenerated for just
these two proto files. On the EVM side the method is dropped from the
current precompile, its ABI and `Upgrade.sol`, and from the
not-yet-wired `legacy/v68` archive so it matches the v6.8 code it will
freeze. The `legacy/v67` snapshot keeps the selector and returns empty
bytes, which is what it always returned: neither pacific-1
(`/store/upgrade/subspace` at height 234051819) nor atlantic-2 (same
query at height 274315652) has any `upgradedIBCState` key, and none of
the four passed mainnet IBC proposals was an `UpgradeProposal`, so the
state was never written. To keep v6.7-era replays gas-identical, the
legacy method still charges the gas of the store read it used to perform
(`ReadCostFlat` plus `ReadCostPerByte` over the
`upgradedIBCState/<h>/upgradedConsState` key), and
`TestPrecompile_UpgradedConsensusStateRemoved` pins that charge. The
replay is gas-identical rather than byte-identical in every observable:
the read no longer reaches the store, so a `debug_trace*` prestate dump
of a historical tx that hit this selector would lack one absent-key
`upgrade` store read. That is not consensus-relevant and no such tx is
known.

A tx carrying `Plan.upgraded_client_state` is still rejected, now by the
unknown-field check at decode time instead of `ValidateBasic`; neither
path touches state. Amino JSON sign bytes are unchanged because the
pointer field was `omitempty`. State impact is limited to the v6.8
upgrade already in sei-protocol#4337, whose `pruneUpgradedIBCState` step stays as a
defensive no-op on mainnet. The v6.8 `rewriteRetiredIBCProposals` scan
from sei-protocol#4337 is also bounded here: it stops at proposal ID 1000 before
decoding anything above it, so zero-deposit proposals submitted in the
deposit window before the upgrade cannot stretch the upgrade block. IBC
proposal types stopped being submittable at v6.7, when the highest
proposal ID on any Sei network was 286, and every IBC proposal on
pacific-1 and atlantic-2 has an ID at or below 163. Reviewers should
look at the v67 legacy path and at `ClearUpgradePlan`, which is now a
plain plan delete. Validated with the `x/upgrade` and
`precompiles/upgrade` suites, the tagged v6.8 upgrade tests, the offline
v6.7→v6.8 migration and `make lint`.
revofusion pushed a commit to revofusion/sei-chain that referenced this pull request Oct 2, 2026
…tocol#4420)

After sei-protocol#4337 and sei-protocol#4340 removed the IBC modules, stores and upgrade state,
a few places in the tree still describe behaviour in terms of IBC that
no longer exists on Sei: the tokenfactory `validateCreateDenom` check
calls itself a temporary workaround for an IBC bug, the `sc-keep-recent`
comment in the docker `app.toml` files and the v2 config migration guide
justifies the default with IBC relayers, the vendored
`sei-cosmos/x/README.md` points at ibc-go, the `x/upgrade` client spec
lists `ibc`, `transfer` and `vesting` module versions, and two
store-hash tests mount a store named `ibc`.

This PR only rewords and relabels. The tokenfactory check is kept as-is
because refusing a subdenom that collides with a denom that already has
supply is still correct; only the comment and error string change, and
nothing asserts on the old text. The two hash tests mount `evm` instead
of `ibc`; they derive their expectations from the stores they create
rather than from golden hashes, so the rename does not alter what they
verify. No runtime, state or consensus behaviour changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants