ExperimentalEVMMempool (the type is gone in v0.7) and optional for forks on CometBFT’s stock mempool. The unconditional migration work is the dependency bump and the keeper-signature shuffle that comes with it.
Optional headline features (each enables a distinct path; see Step 5):
- Krakatoa mempool (#1030, #1053, #1112) — moves the EVM mempool out of CometBFT and into the application layer. The chain gets full control over
CheckTx/RecheckTx, sudo-rechecking on promote/demote, reapable-list filtering, and pool-level lifecycle hooks. Krakatoa is the only app-side EVM mempool in v0.7; the v0.6ExperimentalEVMMempooltype is gone. If your v0.6 fork wiredExperimentalEVMMempool, migrating to Krakatoa is required — see Step 5a. If your v0.6 fork ran on CometBFT’s stock mempool, Krakatoa is optional and you can stay on stock CometBFT. - BlockSTM parallel execution (#589, #1082, #1132) — parallel state-transition function under a software-transactional-memory scheduler, with per-tx object stores for bloom / log indexing / gas accounting and an incarnation cache for signature/auth verification. Includes virtual fee collection (
EndBlockfee settlement via per-tx bank object store, 18-decimal chains only) — virtual fees are bundled with BlockSTM, not a standalone feature. Chains that don’t wire the STM runner keep sequential execution.
- ICS-02 client-router precompile (#768) — Solidity contracts can now manage IBC light clients.
- Authority params (#1130) —
x/vm,x/erc20,x/feemarketMsgServerhandlers consultAuthorityParamsfrom the consensus module before falling back to per-module gov authority. - OpenTelemetry tracing (#871, #863) — spans across
x/vmand the JSON-RPC layer. - JSON-RPC filter lifecycle overhaul (#1008) — idle-timeout reclamation replacing the old global filter cap.
x/precisebank deprecation, the abi.json strict-ABI requirement (#758) — round out the upgrade.
The reference evmd also enables optimistic execution (baseapp.SetOptimisticExecution()). That’s an SDK-level feature, not new in v0.7, but if your fork hasn’t turned it on yet the upgrade is a convenient time — see Step 5c for the wiring.
For deeper background on the new features, see:
If you’re skipping a release, read the v0.5.x → v0.6.0 guide first — its StateDB / callFromPrecompile API break still applies.
Table of contents
The migration steps split into three groups. Required steps apply to every fork; the Krakatoa and BlockSTM groups are independent and either may be skipped. (Step 5c covers optimistic execution — an SDK feature unrelated to v0.7 — for forks that haven’t wired it.) Required (every fork)- Step 1: Bump dependencies
- Step 1.5: Migrate import paths
- Step 2: Update store keys in
app.go - Step 3: Update
EVMDstruct fields - Step 4: Update
NewExampleAppand keeper constructors inapp.go - Step 6: Drop
x/precisebank(18-decimal chains) - Step 7: Update custom code
- Step 8: Coordinate the upgrade
- Step 9: Verify
ExperimentalEVMMempool; otherwise optional)
BlockSTM parallel execution (optional, bundled with virtual fee collection)
Optimistic execution (SDK feature, not v0.7-specific — opt-in)
Step 1: Bump dependencies
Audit everyv0.7.0 transitively bumps the entire stack. The minimum versions you need:go.modin your tree. Forks with nested submodules (e.g., a separatetests/systemtests/go.mod) need the dependency bumps applied independently andgo mod tidyrun separately in each — root-only bumps leave the nested modules with stalecosmossdk.io/log,cosmossdk.io/storeresolutions that fail to compile.
| Dependency | v0.6.x | v0.7.0 | Upstream guide |
|---|---|---|---|
| Go toolchain | 1.23 | 1.25 | — |
cosmos-sdk | v0.53.x | v0.54.2 | SDK |
cometbft | v0.38.x | v0.39.3 | release notes |
ibc-go | v10 | v11 | v10→v11 |
go-ethereum | v1.15 | v1.17 via Cosmos fork | release notes |
go.mod:
core/vm), expect compile errors and follow the geth 1.16 → 1.17 changelog for shim updates.
Step 1.5: Migrate import paths
A large block ofcosmossdk.io/... packages moved into github.com/cosmos/cosmos-sdk/... in SDK v0.54, and store is now store/v2. Run these find-and-replaces across your fork:
| Old import | New import |
|---|---|
cosmossdk.io/store | github.com/cosmos/cosmos-sdk/store/v2 |
cosmossdk.io/store/types | github.com/cosmos/cosmos-sdk/store/v2/types |
cosmossdk.io/store/snapshots/types | github.com/cosmos/cosmos-sdk/store/v2/snapshots/types |
cosmossdk.io/store/prefix | github.com/cosmos/cosmos-sdk/store/v2/prefix |
cosmossdk.io/log | cosmossdk.io/log/v2 |
cosmossdk.io/x/upgrade{,/keeper,/types} | github.com/cosmos/cosmos-sdk/x/upgrade/... |
cosmossdk.io/x/evidence{,/keeper,/types} | github.com/cosmos/cosmos-sdk/x/evidence/... |
cosmossdk.io/x/feegrant{,/keeper,/module} | github.com/cosmos/cosmos-sdk/x/feegrant/... |
cosmossdk.io/x/tx/signing | github.com/cosmos/cosmos-sdk/x/tx/signing |
cosmossdk.io/systemtests | github.com/cosmos/cosmos-sdk/tools/systemtests |
github.com/cosmos/ibc-go/v10/... | github.com/cosmos/ibc-go/v11/... |
tests/systemtests/go.mod (recommended pattern), apply the rename there too and run go mod tidy in that submodule independently of the main module.
Internal Cosmos EVM relocations — the top-level github.com/cosmos/evm/config package was deleted and its symbols redistributed:
| v0.6 symbol | v0.7 location |
|---|---|
config.MustGetDefaultNodeHome | evmd/config.MustGetDefaultNodeHome |
config.InitAppConfig | evmd/config.InitAppConfig |
config.BlockedAddresses | evmd/config.BlockedAddresses |
config.GetMaccPerms | evmd/config.GetMaccPerms |
config.SetBip44CoinType | evmd/config.SetBip44CoinType |
config.GetChainIDFromHome | utils.GetChainIDFromHome |
config.EVMChainID (constant) | removed — use evmtypes.DefaultEVMChainID |
config.GetCosmosPoolMaxTx | server.GetCosmosPoolMaxTx |
config.GetLegacyPoolConfig etc. | folded into server.ResolveMempoolConfig (see Step 5a) |
MustGetDefaultNodeHome, InitAppConfig, BlockedAddresses, GetMaccPerms) moved from github.com/cosmos/evm/config to github.com/cosmos/evm/evmd/config. Mempool / chain-id helpers moved to github.com/cosmos/evm/server and github.com/cosmos/evm/utils. Update every import in evmd/cmd/evmd/cmd/root.go, evmd/cmd/evmd/main.go, and evmd/cmd/evmd/cmd/testnet.go accordingly.
Step 2: Update store keys in app.go
The transient stores evmtypes.TransientKey and feemarkettypes.TransientKey were both removed. The EVM keeper still needs a per-tx scratch store for tx bloom and gas accounting, so it now consumes evmtypes.ObjectKey (an object store) instead. This change is unconditional — it applies even on the sequential path.
Replace the transient-store declaration, mount the new object store, and build a nonTransientKeys slice for the EVM keeper:
nonTransientKeys is the 4th argument to evmkeeper.NewKeeper (Step 4) and the EVM keeper uses it for cross-module store access. Step 5 reuses the same slice if you wire the BlockSTM runner.
Step 5 (parallel path) extends(The matchingoKeyswithbanktypes.ObjectStoreKeyand wires it into the bank keeper. Skip if you’re not adopting virtual fee collection.
EVMD struct field rename is in Step 3.)
Step 3: Update EVMD struct fields
TransferKeeper is now stored as a pointer (ibc-go v11). EVMMempool’s field type was widened to the ExtMempool interface to permit Krakatoa or any future custom subpool. If you have getters/setters keyed on these field types (e.g. GetTransferKeeper, SetTransferKeeper), update their signatures too.
The Close() method on EVMD does a type assertion against the old mempool type — update it to the new one (or remove if you’re not wiring an EVM mempool):
Step 4: Update NewExampleApp and keeper constructors in app.go
NewExampleApp signature — drop traceStore
The traceStore io.Writer parameter is gone. Update the function signature and every call site of your app constructor — CLI commands (newApp, appExport, the appCreator callback in your root cmd), test-network fixtures (e.g., NewTestNetworkFixture), and any custom integration-test bootstrapping. nil-passing call sites need to drop the nil argument too.
feemarketkeeper.NewKeeper — drop transient key
ibckeeper.NewKeeper — drop capability keeper
ibc-go v11 removed the capability-keeper argument. Existing chains have nothing to migrate — the parameter was already nil — but the call must lose it:
govkeeper.NewKeeper — reordered args, new vote-results function
Cosmos SDK v0.54 reordered the constructor and added a final pluggable vote-tally function:
transferkeeper.NewKeeper — pointer return, inline address codec, drop ICS4Wrapper / duplicate ChannelKeeper
ibc-go v11 returns *transferkeeper.Keeper. The constructor also takes the EVM address codec inline (no more SetAddressCodec) and drops the duplicate ICS4Wrapper / ChannelKeeper params:
⚠️ The referenceevmdinstantiatesTransferKeeperbeforeEVMKeeperso static precompiles receive a non-nil reference. v0.6 constructs them in the opposite order (EVMKeeper, then Erc20Keeper consuming&app.TransferKeeper, then TransferKeeper). To swap, you’ll also need to moveErc20Keeperso it’s constructed afterTransferKeeper— andErc20Keeperitself now takes the pointer-typedapp.TransferKeeperdirectly, no&. Walk the three keeper constructions as a unit, not individually.
IBC callbacks middleware — wrap with setter calls
ibc-go v11 split the constructor and the wrapping. Replace the single-lineNewIBCMiddleware with the three-step setter form:
NewIBCMiddleware itself doesn’t accept either argument anymore. A middleware constructed without SetICS4Wrapper or SetUnderlyingApplication compiles but panics with a nil-pointer dereference on the first packet send / receive (the constructor does panic on a nil contract keeper or zero gas, but the wrapper / underlying-app fields are checked at use, not construction).
evmkeeper.NewKeeper — object store key, store-key slice, BankKeeper replaces PreciseBankKeeper
The third arg is the new EVM object-store key (Step 2). The fourth changed from map[string]*storetypes.KVStoreKey to []storetypes.StoreKey — the keeper uses it for cross-module store access. Pass the nonTransientKeys slice from Step 2; the same slice is also what the STM runner tracks if you opt into Step 5.
DefaultStaticPrecompiles — Bank, dereferenced TransferKeeper, ClientKeeper
TransferKeeper is already a pointer (Step 3); pass it directly. IBCKeeper.ClientKeeper is the new dependency — it backs the ICS-02 client-router precompile (#768):
erc20keeper.NewKeeper — Bank, dereferenced TransferKeeper
node.RegisterNodeService — earliest-version callback
Hydrate EVM globals on restart (#1126)
Required regardless of which path you choose. AfterLoadLatestVersion (inside if loadLatest), hydrate the EVM globals from KV so evmCoinInfo is populated before any RPC handler runs:
PreBlock panic on a nil evmCoinInfo.
vmModule here is the value returned by vm.NewAppModule(...). v0.6 calls vm.NewAppModule(...) inline inside app.ModuleManager = module.NewManager(...), so before the HydrateGlobals call you’ll need to refactor: bind the result to a local first, then pass that local into module.NewManager:
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types".
Wire the EVM tx runner (#1132)
Required regardless of path.vmrunner.SetRunner installs the baseapp tx runner wrapped with the EVM module’s PatchTxResponses post-execution log/tx index fix-up. Without it, log.Index and transactionIndex on receipts are wrong (the bug #1132 corrected). The wrapper works for both sequential and parallel inner runners — only the inner runner choice differs by path:
- Sequential (default) — pass
txnrunner.NewDefaultRunner(txDecoder). - Parallel — pass
txnrunner.NewSTMRunner(...)(see Step 5b).
NewExampleApp so it can be reused by the runner (and by bApp := baseapp.NewBaseApp(...) if you want to share it):
return app. The sequential form:
"github.com/cosmos/cosmos-sdk/baseapp/txnrunner", vmrunner "github.com/cosmos/evm/x/vm/runner".
Removed EVMD methods
These were deleted; remove any callers:
GetTKey,GetMemKey— transient/mem stores no longer exist as separate maps.GetAuthzKeeper— the helper was redundant; exposeapp.AuthzKeeperdirectly if you need it.GetPreciseBankKeeper— module is removed (Step 6).SetClientCtxand theclientCtxfield — unused.
Step 5: Enable Krakatoa and/or BlockSTM
Two independent v0.7 opt-ins:- Krakatoa (5a) is required for forks that already used the v0.6
ExperimentalEVMMempool(the type was removed); optional for forks on CometBFT’s stock mempool. - BlockSTM with virtual fee collection (5b) is always opt-in. Skip 5b to keep sequential execution.
baseapp.SetOptimisticExecution() separately — it’s an SDK-level feature, not new in v0.7, but the reference evmd/app.go enables it and forks that haven’t yet adopted it can use this upgrade as the moment to do so.
State-breaking features. Each ships as part of the binary; adopting or dropping any of them requires a coordinated MsgSoftwareUpgrade and a binary swap, the same as any other consensus change.
5a. Krakatoa application-layer mempool
Krakatoa is the only app-side EVM mempool in v0.7. TheExperimentalEVMMempool type from v0.6 is gone, so optionality depends on what your v0.6 fork already used:
- If you wired
ExperimentalEVMMempoolin v0.6: this step is required. The construction signature changed and the handler set was redesigned; you must migrate or your fork won’t compile. - If you ran on CometBFT’s stock mempool in v0.6 (no app-side EVM mempool): this step is optional. Adopt Krakatoa to gain app-level
CheckTx/RecheckTxcontrol, or skip it and stay on stock CometBFT.
ExperimentalEVMMempool, replace the construction with evmmempool.NewMempool and the new handler set. The full reference is evmd/mempool.go’s configureEVMMempool — read it before applying the diff below; the local variables it constructs (mpConfig, txEncoder, evmRechecker, cosmosRechecker, cosmosPoolMaxTx, checkTxTimeout) are what the new NewMempool signature consumes:
server.ResolveMempoolConfig, server.GetCosmosPoolMaxTx, and server.GetMempoolCheckTxTimeout are all in github.com/cosmos/evm/server; the evmconfig.GetLegacyPoolConfig / GetBlockGasLimit / GetMinTip helpers from v0.6 collapsed into ResolveMempoolConfig. app.TxDecode and the SetInsertTxHandler / SetReapTxsHandler setters are new in cosmos-sdk v0.54 baseapp.
Ordering:Then replace the construction and handler wiring:app.SetAnteHandler(...)must run beforeconfigureEVMMempool.ResolveMempoolConfigcallsapp.GetAnteHandler()and stashes the result onmpConfig.AnteHandler, which the recheckers then close over. If the ante handler hasn’t been set yet,GetAnteHandlerreturns nil and the chain panics on firstRecheckTx. There’s no compile-time signal — get the ordering right.evmRecheckerandcosmosRecheckermust be distinct instances, even though they wrap identical config. They feed different subpools (the EVM eth-tx pool vs. the Cosmos pool) and need independent state for promotion/demotion bookkeeping. Sharing one instance compiles fine but produces silent cross-pool state interference at promote/demote time.
The reference application uses aTo opt out entirely, drop theNewNoCheckProposalTxVerifierat proposal time when verifying the txs in a given proposal. This is a performance optimization since with the Krakatoa mempool, it is a requirement that every tx within the proposal has already been validated, thus this check is redundant. If you choose to adopt this pattern as well copy the referenceNewNoCheckProposalTxVerifierand pass this to yourPrepareProposalHandler.
configureEVMMempool(...) call from NewExampleApp, or set mempool.max-txs=-1 in app.toml (the SDK FlagMempoolMaxTxs — note this is the top-level [mempool] key, not evm.mempool.max-txs). configureEVMMempool reads it via server.GetCosmosPoolMaxTx, bails out on a negative value, and falls back to CometBFT’s stock mempool.
⚠️ Setmempool.type = "app"inconfig.toml. CometBFT v0.39 requires the app-side mempool type whenever the application supplies an EVM mempool. The default is"flood"; Krakatoa errors out at startup if it’s left as the default. This is a one-line patch to each validator’sconfig.toml(or your fork’s equivalent), applied at the same time as the binary swap. Forks that opt out of Krakatoa (the previous paragraph) don’t need this. Note that by settingmempool.type = "app"inconfig.toml, there are additional configuration parameters you may want to configure that will affect Krakatoa mempool operations. Please see the CometBFT application mempool documentation for more info.
5b. (Optional) BlockSTM parallel execution and virtual fee collection
BlockSTM enables parallel execution of the state-transition function and bundles virtual fee collection (per-tx bank-balance accounting reduced atEndBlock). Not required — chains that skip this section keep sequential execution. Independent of Krakatoa, and independent of optimistic execution (5c).
The two pieces below are wired together; you opt into the bundle, not into individual lines.
Swap the inner tx runner to BlockSTM
Step 4 already wiredvmrunner.SetRunner(bApp, ...) with the sequential txnrunner.NewDefaultRunner(txDecoder) as the inner runner. To opt into parallel execution, swap the inner runner for txnrunner.NewSTMRunner(...):
sdk.DefaultBondDenom — chains that customized their EVM denom will diverge.
Additional import: goruntime "runtime".
Virtual fee collection (18-decimal chains only)
Virtual fee collection is part of the BlockSTM bundle — it’s what lets fee settlement happen in parallel without contending the fee collector account on every tx. Two pieces are required. First, extend theoKeys declaration from Step 2 with banktypes.ObjectStoreKey and wire it into the bank keeper. Order matters: the oKeys declaration must include banktypes.ObjectStoreKey before the for _, k := range oKeys loop that builds nonTransientKeys, otherwise the bank object store won’t be in the slice the EVM keeper sees. Apply the change at the Step 2 declaration site, not later:
BankKeeper is constructed, wire the object-store key into it:
WithObjStoreKey(storetypes.StoreKey) BaseKeeper is part of the bankkeeper.Keeper interface in cosmos-sdk v0.54, so the call works whether your EVMD.BankKeeper field is the interface (bankkeeper.Keeper, the reference default) or the concrete bankkeeper.BaseKeeper. The method returns BaseKeeper, but BaseKeeper satisfies Keeper, so assigning the result back to an interface-typed field type-checks. No field-widening required.
Then, after WithStaticPrecompiles, enable virtual fees on the EVM keeper:
⚠️ Do not callEnableVirtualFeeCollection()if your gas token is not 18-decimal.x/vm/keeper.DeductFeesreads the EVM denom’s bank metadata and panics if the display-denom unit’s exponent is not 18 (x/vm/keeper/fees.go:156). See Step 6. A non-18-decimal chain that still wants BlockSTM has to skip this final piece — but the parallel path’s main throughput win comes from virtual fees, so the practical recommendation is to migrate to 18 decimals first.
5c. (Optional) Optimistic execution
Not new in v0.7 —baseapp.SetOptimisticExecution() has been an SDK feature since v0.50. Documented here because the reference evmd/app.go ships with it enabled, and forks that haven’t yet adopted it can fold the wiring into this upgrade. Independent of BlockSTM and Krakatoa.
The feature overlaps FinalizeBlock for height H with ProcessProposal for height H+1: while CometBFT is still finalizing the current block, the app speculatively executes the next proposed block. If the speculative result matches what FinalizeBlock is later asked to commit, the result is reused; if it diverges, the speculative state is discarded and execution falls back to the standard path.
The reference evmd/app.go enables it. Add the option to baseAppOptions before baseapp.NewBaseApp(...) is called — append after the baseAppOptions ...func(*baseapp.BaseApp) parameter is in scope but before the constructor consumes it:
- Determinism is preserved. Speculative execution uses a sandboxed cache; on a mismatch the state is dropped, not committed. The user-visible behavior is identical to non-optimistic execution — only the latency of
FinalizeBlockshifts. - Composes with BlockSTM (5b) and Krakatoa (5a). Optimistic execution runs the speculative block through whichever runner is wired (
vmrunner.SetRunner), so you get parallel-on-speculative + parallel-on-final when 5b is also enabled. - State-breaking. Like 5a and 5b, this is baked into the binary. Adopting or dropping it requires a coordinated
MsgSoftwareUpgrade, not a runtime toggle. See Step 8. - Resource cost. The speculative path uses an extra goroutine and an extra working state cache per height. On memory-tight nodes you may prefer to disable it; the SDK doc linked at the top of this guide covers the trade-offs.
Step 6: Drop x/precisebank
x/precisebank is deprecated (#1019). It only ever made sense for non-18-decimal gas tokens — it bridged them into the EVM’s 18-decimal world. The reference v0.6 evmd/app.go wired it unconditionally despite the inline comment “PreciseBank is not needed if SDK use 18 decimals for gas coin”, so most v0.6 forks have it threaded through evmkeeper, erc20keeper, and the precompiles regardless of their gas token’s decimals.
In v0.7 the module is gone from the main tree. EvmCoinInfo.Decimals is also marked deprecated (#1029).
Non-18-decimal chains are not fully supported going forward. v0.7.0 still ships precisebank underIf your fork wiredcontrib/x/precisebank, but future EVM releases will not test or maintain it. Either stay on v0.6.x until you can migrate to 18 decimals, or pincosmos/evm/contrib/x/precisebankand do not enable virtual fee collection (5b).
PreciseBankKeeper (whether or not your gas token is 18-decimal), unwire it:
precisebanktypes.StoreKey from the keys declaration and the module name from your SetOrderBeginBlockers / SetOrderEndBlockers / SetOrderInitGenesis lists.
Replace every app.PreciseBankKeeper reference (in evmkeeper.NewKeeper, erc20keeper.NewKeeper, DefaultStaticPrecompiles, and any custom modules) with app.BankKeeper. Verify decimal expectations at each call site — anywhere your code assumed the precisebank denom translation was happening, you now need to either operate on 18-decimal values directly or do the conversion yourself.
Tests that referenced precisebank also need cleanup. In the reference repo this meant deleting evmd/tests/integration/x_precisebank_test.go and removing PreciseBankMintEventCount / PreciseBankBurnEventCount and their consumers from evmd/tests/ibc/helper.go. Audit your fork’s test tree for any precisebank symbols and drop them — the code won’t compile against v0.7 with them present.
Step 7: Update custom code
Custom ante handlers / mempool plugins
The transient stores backing gas accounting and the feemarket are gone. Read gas-wanted from the SDK context instead —ctx.GasMeter().GasConsumed(). If your decorator wrote to the feemarket transient store, remove that logic — feemarkettypes.TransientKey and the keeper methods GetTransientGasWanted, SetTransientBlockGasWanted, AddTransientGasWanted are all gone. The same applies to the EVM keeper: GetBlockBloomTransient, SetBlockBloomTransient, GetTxIndexTransient, SetTxIndexTransient, and WithDefaultEvmCoinInfo were removed.
Custom BankKeeper / BankWrapper implementations
The interfaces in x/vm/types/interfaces.go changed. Any fork that supplies a non-default bank wrapper must update.
BankKeeper gained five methods to support virtual fee collection and parallel-safe balance accounting:
BankWrapper is a hard API break: MintAmountToAccount and BurnAmountFromAccount were removed and replaced by a single SetBalance(ctx, account, amt *big.Int) error. Callers and implementations must both change.
EmitBlockBloomEvent’s argument type changed from ethtypes.Bloom to []byte.
A new VMKeeper interface (GetEvmCoinInfo) was added; some helpers now take it instead of a concrete keeper.
Custom indexers / receipt consumers
- Read
log.Indexandlog.TxIndexonly after post-execution patching (#1132). Recomputing from raw event order will diverge from canonical receipts. - Drop any workaround that special-cased the
MaxUint64overflow ontransactionIndex— fixed in #1047. - Don’t assume tx counts in receipt arrays match raw block tx counts. StateDB-error txs are now skipped during receipt conversion (#1107).
Forks of precompile abi.json
PR #758 made the precompile ABI files strict — only valid Ethereum ABI fields are accepted. Forks that vendor or override abi.json for any precompile must remove non-ABI extension fields, or they will fail to parse at startup.
Removed helpers
Params.GetActiveStaticPrecompilesAddrs()is gone — derive[]common.Addressyourself if you used it.
Mocks of EVMKeeper
Regenerate against v0.7.0 — the constructor signature (Step 4) and static-precompile dependencies (Step 4) shifted.
Step 8: Coordinate the upgrade
This is a normal Cosmos consensus-breaking upgrade.- All validators must run the same v0.7 binary post-upgrade. Mixing v0.6 and v0.7 binaries will fork.
- Step 5 (Krakatoa, BlockSTM + virtual fees, optimistic execution) is state-breaking. Each is baked into the binary — adopting or dropping any of them later is another coordinated
MsgSoftwareUpgrade, not a runtime toggle. - There is no on-chain governance flag for these toggles. Switching paths later requires a new binary release and another
MsgSoftwareUpgrade.
UpgradeName constant and its doc comment to match the new release. The doc-comment drift between releases is a recurring foot-gun — the system test reads the constant verbatim, but readers and downstream handlers grep the comment for context:
RunMigrations with empty StoreUpgrades — no module schema changes. Submit a MsgSoftwareUpgrade with name: "v0.6.0-to-v0.7.0" at your target height and swap the binary at the halt height.
Step 9: Verify
Sanity check the upgrade path
MsgSoftwareUpgrade for v0.6.0-to-v0.7.0, swaps to the v0.7 binary at the halt height, and runs a contended-account workload (many txs hitting the same hot contract per block). On the parallel path this exercises the BlockSTM scheduler’s conflict detection across the upgrade boundary; on the sequential path it’s still a useful end-to-end smoke test.
The test reads a v0.6-era binary from tests/systemtests/binaries/v0.6/evmd. For your fork, that binary is your own chain build pinned to the v0.6 cosmos-evm dependency — not a generic cosmos/evm@v0.6.0 binary. The legacy build’s keepers, ante decorators, and module set must match what your validators are actually running pre-upgrade, otherwise the test exercises the wrong starting state.
Wire whatever make (or shell) target you use for this — the key constraints are:
- Output goes to
tests/systemtests/binaries/v0.6/evmd(or wherever yourchainupgrade/v6_v7.goreads from). - Your
test-systemMake target (or equivalent) depends on it and on the current binary, in that order. - If your previous release had a
build-v05target chained fromtest-system, retarget that dependency to the newbuild-v06(or whatever you name it).