Skip to content

chore: cosmos-sdk upgrade 0.54 and evm upgrade 0.7.0 - #295

Open
AryaLanjewar3005 wants to merge 1 commit into
developfrom
feat/cosmos-sdk-0.54-evm-0.7.0
Open

chore: cosmos-sdk upgrade 0.54 and evm upgrade 0.7.0#295
AryaLanjewar3005 wants to merge 1 commit into
developfrom
feat/cosmos-sdk-0.54-evm-0.7.0

Conversation

@AryaLanjewar3005

@AryaLanjewar3005 AryaLanjewar3005 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

chore: upgrade cosmos-sdk v0.53.7 → v0.54.3, ibc-go v10 → v11.2.0, cosmos-evm v0.6.0 → v0.7.0

Target chain: donut testnet (push_42101-1).

Summary

cosmos-evm v0.7.0 requires cosmos-sdk v0.54, which in turn requires ibc-go v11 and
cometbft v0.39. There is no way to split this — it is one atomic, coordinated,
state-affecting upgrade.

Component before after
Go 1.23.8 (toolchain 1.24.3) 1.25.9
cosmos-sdk v0.53.7 v0.54.3
cometbft v0.38.21 v0.39.3
ibc-go v10.4.0 v11.2.0
cosmos-evm v0.6.0 (pushchain/evm rc2) v0.7.0 (../push-chain-evm)
wasmd / wasmvm v0.55.0 / v2 v0.70.3 / v3.0.7
store cosmossdk.io/store v1.1.2 cosmos-sdk/store/v2 v2.0.0
log cosmossdk.io/log v1.6.1 cosmossdk.io/log/v2 v2.1.0
iavl v1.3.4 v1.2.8

71 files changed on feat/cosmos-sdk-0.54-evm-0.7.0.

Companion PR: the push-chain-evm v0.7.0 upgrade (see PR-evm.md). This PR points
github.com/cosmos/evm at that fork via a local replace.


Critical decisions

Each of these was a fork in the road. Rationale recorded so reviewers can challenge
the reasoning, not just the diff.

D1. Target ibc-go v11.2.0, not the v11.0.0 that cosmos-evm pins

Decision. Pin ibc-go to v11.2.0 even though cosmos-evm v0.7.0 requires only
v11.0.0.

Why. packet-forward-middleware and rate-limiting have no ibc-apps v11
release
— the latest are v10.6.0 and v10.7.0, both pinning ibc-go v10 and
cosmos-sdk v0.53.4, and cosmos/ibc-apps main is still on v10 for both. It would
be easy to conclude from that alone that these modules are unavailable and must be
dropped.

That conclusion is wrong. Both middlewares were upstreamed into ibc-go core. On
v11 they are imported from ibc-go itself:

github.com/cosmos/ibc-go/v11/modules/apps/packet-forward-middleware
github.com/cosmos/ibc-go/v11/modules/apps/rate-limiting

The patch release matters:

ibc-go packet-forward rate-limiting
v11.0.0 (what cosmos-evm pins) absent absent
v11.1.0 present absent
v11.2.0 present present

Pinning v11.0.0 or v11.1.0 forces dropping rate-limiting. v11.2.0 keeps both.
Verified by resolving the module and compiling a probe against
pfm.NewIBCMiddleware, pfmkeeper.NewKeeper, rl.NewIBCMiddleware and
rlkeeper.NewKeeper.

Consequence. Zero IBC middleware functionality is lost. An earlier in-house
attempt (task/sdk-upgrade) targeted v11.1.0 and consequently deleted the
rate-limiting middleware and its store; that sacrifice is unnecessary.

D2. Drop tokenfactory and group — and nothing else

Decision. Unwire exactly two modules and delete their stores.

Why. Neither has a cosmos-sdk v0.54 compatible release, verified by compiling:

  • cosmossdk.io/x/group only ships v0.2.0-rc.1, which requires
    cosmossdk.io/core/registry, core/transaction, core/appmodule/v2,
    cosmos-sdk/simsx and client/v2/autocli/prompt — all from the abandoned SDK
    v2 line
    , none present in the 0.54 constellation (core v1.1.0,
    client/v2 v2.11.0).
  • tokenfactory (strangelove-ventures) is latest at v0.50.7-wasmvm2, targeting
    SDK v0.50. Its own app package imports github.com/cosmos/cosmos-sdk/x/group,
    a path that no longer exists in 0.54.

Why nothing else. It is tempting to conclude that x/crisis, x/circuit,
x/nft, x/evidence, x/feegrant and x/upgrade were also removed, because their
old import paths all break. They were relocated, not removed:

Was Now
cosmossdk.io/x/circuit cosmos-sdk/contrib/x/circuit
cosmos-sdk/x/crisis cosmos-sdk/contrib/x/crisis
cosmossdk.io/x/nft cosmos-sdk/contrib/x/nft
cosmossdk.io/x/evidence cosmos-sdk/x/evidence (main module)
cosmossdk.io/x/feegrant cosmos-sdk/x/feegrant (main module)
cosmossdk.io/x/upgrade cosmos-sdk/x/upgrade (main module)

All six are retained. The casualty list is two, not eight.

D3. Deleting those two stores is safe — verified against live chain state

Decision. Delete the tokenfactory and group stores in the upgrade handler
with no pre-upgrade asset migration.

Why. Store deletion is irreversible and can strand funds, so this was verified
against donut rather than assumed. Queried at height ~20,158,578:

Check Result
q bank total-supply one denom: upc. No factory/... denoms.
q bank denoms-metadata one entry: upc
q tokenfactory params module registered and responding; denoms-from-creator empty
q group group-info 1..5 group: not found for every id

Group ids are sequential from 1, so the absence of group 1 means no group was ever
created
— therefore no group policies, therefore no policy accounts holding funds.

This distinction matters because the two modules carry different risk:

  • tokenfactory balances live in x/bank, not in the tokenfactory store. Deleting
    its store would not delete balances; it would freeze denom administration (no more
    mint/burn/admin changes). Recoverable-ish.
  • group is the dangerous one. A group policy has its own account address and
    can hold funds, and the only way to spend from it is a proposal executed through
    the group module. Delete the module with a funded policy and those funds become
    permanently unreachable.

Both are empty, so neither risk materialises.

D4. Sequential default tx runner — not BlockSTM

Decision. vmrunner.SetRunner(app.BaseApp, txnrunner.NewDefaultRunner(txConfig.TxDecoder())).

Why. Registering a runner is mandatory in v0.7.0 regardless of execution
strategy. The reference evmd app uses NewSTMRunner (BlockSTM parallel execution),
but BlockSTM is an optional, state-breaking feature bundled with virtual fee
collection. Adopting it is a separate decision with its own risk profile and its own
coordinated upgrade; folding it into an already-large dependency upgrade would
conflate two independent sources of consensus risk.

Virtual fee collection is likewise not enabled (no
EnableVirtualFeeCollection, no banktypes.ObjectStoreKey).

BlockSTM can be adopted later, but note it requires another coordinated upgrade —
it is baked in at build time.

D5. Krakatoa mempool — not applicable

Decision. No mempool migration performed.

Why. The v0.7.0 guide's Krakatoa section is required only if the fork wired
ExperimentalEVMMempool. push-chain does not — app.go has only a commented-out
SetMempool(nonceMempool) and otherwise uses the default SDK mempool. Nothing to
migrate. mempool.type = "app" is not set in config.toml.

D6. Retain the compat/orm-api shim, re-pointed at api v1.0.0

Decision. Keep the nested shim module and bump its cosmossdk.io/api
requirement from v0.9.2 to v1.0.0.

Why. cosmossdk.io/api dropped the cosmos/orm/* packages at v0.9.0 and still
does not ship them at v1.0.0
, but cosmossdk.io/orm — and therefore push-chain's
own ORM-backed x/uregistry and x/uvalidator generated state files, which carry
_ "cosmossdk.io/orm" — still import them. The shim re-provides them via
replace cosmossdk.io/api/cosmos/orm => ./compat/orm-api.

Worth flagging for reviewers of the reference attempt: task/sdk-upgrade has no
compat/ dir and no ORM state files, because its base commit predates them. It is a
good template for pins but does not cover this.

D7. Purge the SDK-v2-line modules — the root cause of the resolution failure

Decision. Remove cosmossdk.io/x/group, x/bank, x/gov, the RC cosmossdk.io/store
and core/testing from go.mod entirely.

Why. These pull cometbft >= v1.0.0 transitively. With them present, MVS
resolved cometbft to v1.0.1 regardless of the require on v0.39.3, and the
build failed with a wall of does not contain package github.com/cometbft/cometbft/proto/tendermint/* errors that look like a cometbft
problem but are not.

They had been re-added automatically by go build -mod=mod while the source still
imported x/group. Once group was unwired and these purged, cometbft holds at
v0.39.3 with no replace needed
— for cometbft or the SDK.

This is the single highest-value debugging note in this PR: if cometbft ever drifts
to v1.x again, look for a v2-line module, not for a cometbft pin.

D8. Remove the GasWantedDecorator from the cosmos ante chain

Decision. Delete it, add nothing in its place.

Why. It was removed upstream along with the transient stores. Its job was to
accumulate block gas-wanted into a feemarket transient store; in v0.7.0
x/feemarket reads ctx.BlockGasWanted() directly from the SDK's own block gas
meter in EndBlock. Ante-side accumulation is redundant. No behaviour is lost
this is not a feature drop.

D9. Remove the capability module

Decision. Delete capabilitykeeper usage entirely.

Why. ibc-go v11 drops capabilities. In push-chain it was already vestigial: two
fields (ChainApp.ScopedWasmKeeper, Upgrade.CapabilityKeeper) with zero
consumers
anywhere in the repo. Its keeper also fails to compile against store/v2
(cosmossdk.io/store/types vs cosmos-sdk/store/v2/types mismatch).

D10. Rate-limiting placed at the top of the transfer stack

Decision. Rebuild the transfer stack on ibc-go v11's porttypes.NewIBCStackBuilder,
ordered bottom-to-top:

transfer → erc20 middleware → callbacks (wasm) → packet-forward → rate-limiting

Why. Build() wires the ICS4Wrappers so the transfer keeper's SendPacket flows
up through every middleware before reaching the channel keeper — this replaces the
manual app.TransferKeeper.WithICS4Wrapper(cbStack) call the v10 code needed.
Rate-limiting sits outermost so it observes every packet after forwarding decisions
are made, which is where quota enforcement belongs.

Reviewers should sanity-check this ordering against the v10 behaviour, since the
old code expressed the stack by nesting constructors and passing
app.RatelimitKeeper as the transfer keeper's ICS4Wrapper — a different shape, and
the ordering equivalence is a judgement call rather than a mechanical translation.

D11. iavl pinned to v1.2.8

Why. v1.3.4 references corestore.KVStoreWithBatch and corestore.Batch, which
do not exist in the cosmossdk.io/core v1.1.0 that SDK 0.54.3 uses. v1.2.8 is the
version the working reference builds against.


Other notable changes

Store layer. SetCommitMultiStoreTracer removed (gone with store/v2). The evm
and feemarket transient keys replaced by
storetypes.NewObjectStoreKeys(evmtypes.ObjectKey) + MountObjectStores. The EVM
keeper now takes the object key and a deterministically sorted
[]storetypes.StoreKey instead of the key map — sorting matters, the slice order is
consensus-visible.

Keeper signature changes. ibc (drops params subspace; upgrade keeper is now an
02-client/types.UpgradeKeeper), gov (reordered, plus
govkeeper.NewDefaultCalculateVoteResultsAndVotingPower(app.StakingKeeper)),
transfer (pointer return, address codec inline, no ICS4Wrapper arg), rate-limiting,
packet-forward (SetTransferKeeper gone — transfer keeper passed directly), ICA
host/controller (pointer returns), wasm (gains ChannelKeeperV2),
nodeservice.RegisterNodeService (gains an earliest-version getter).

AppCreator. The traceStore io.Writer parameter was dropped from
servertypes.AppCreator; newApp, appExport and the sdkAppCreator wrapper were
updated and now pass nil to NewChainApp.

HydrateGlobals. Added after LoadLatestVersion:

hydrateCtx := app.NewContextLegacy(true, tmproto.Header{
    Height: app.LastBlockHeight(), ChainID: app.ChainID(),
})
vmModule.HydrateGlobals(hydrateCtx)

This populates the global EVM coin info from the KV store before any JSON-RPC handler
can run. Unit tests do not catch its absence — the app builds and the entire
suite passes without it — but RPC requests served before the first PreBlock would
read an uninitialised evmCoinInfo. Caught by diffing against evmd, not by tests.

banktypes.ModuleName added to SetOrderEndBlockers. SDK 0.54 panics if any
registered module is missing from the ordering.

precompiles/usigverifier. Two changes: added the Name() method that geth 1.17
added to vm.PrecompiledContract; and replaced the removed cmn.LoadABI. Note
for anyone porting another precompile:
this abi.json is a Hardhat artifact
(hh-sol-artifact-1 — an object with an "abi" key), not a bare ABI array like the
upstream precompiles use. cmn.LoadABI unwrapped it; abi.JSON does not. Passing
the raw artifact panics at package init and takes down every app-constructing test in
the repo.

app/ante/fee.go. errorsmod.Wrapf(err, err.Error())Wrap; Go 1.24+ vet
rejects a non-constant format string.


Upgrade handler

app/upgrades/sdk-v0-54, registered in app/upgrades.go:

StoreUpgrades{ Deleted: []string{"tokenfactory", "group"} }

The handler also deletes both from the consensus version map before RunMigrations,
so it does not attempt to init-genesis or migrate modules that no longer exist.

UpgradeName = "sdk-v0.54" — must match the plan.name in the
MsgSoftwareUpgrade proposal.


Testing

go build ./...                                       # clean *
go test -tags=test ./x/... ./app/... ./utils/...     # 14 packages, all ok

All passing: x/uexecutor, x/uregistry (incl. migrations/v3), x/utss,
x/uvalidator (keeper + types each), app, app/ante, app/decorators,
app/upgrades/purge-expired-outbounds, utils.

* cmd/puniversald fails at the link step with ld: library 'godkls' not found
because ../dkls23-rs/target/release does not exist in this workspace. Pre-existing
environment gap, not a regression — go vet ./cmd/puniversald/... compiles clean.
Build the Rust dkls23 library and it links.

Dependency link — to be repointed before merge

go.mod currently carries a local path replace:

github.com/cosmos/evm => ../push-chain-evm

This is intentional for development and will be swapped for a published version.
Everything in this PR was built and tested against push-chain-evm at commit
a5cdd297 ("feat: cosmos evm upgrade 0.7.0", branch evm-upgrade-0.7.0), tree
clean.

When repointing, the published tag must contain that exact tree. If the fork is
re-tagged from a different commit, none of the test results in this PR transfer —
the local replace bypasses go.sum, so a content mismatch will not be caught by
checksum verification. Re-run go test -tags=test ./x/... ./app/... ./utils/...
after the swap.


Review checklist

  • D1 — is v11.2.0 acceptable, given cosmos-evm pins v11.0.0? (superset, but confirm)
  • D3 — re-run the empty-state queries at the actual upgrade height, not just today's
  • D4 — confirm deferring BlockSTM is the intended call
  • D10 — transfer-stack ordering matches v10 semantics, particularly where rate-limiting sits
  • Sorted allStoreKeys slice passed to the EVM keeper is deterministic across nodes
  • Upgrade-handler name matches the governance proposal
  • HydrateGlobals context (LastBlockHeight/ChainID) is correct for a fresh-genesis start as well as a restart
  • Rust dkls23 library built in CI so puniversald links

References

  • Fixes #
  • Related issue/PR:

Changes

Testing

  • go test ./...

Checklist

  • Ready for review
  • Docs updated (if applicable)
  • Env vars updated (if applicable)

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.

1 participant