feat: evm 0.5.0 upgrade#256
Open
AryaLanjewar3005 wants to merge 7 commits into
Open
Conversation
…ions for evm v0.4.0 signature change
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
EVM v0.5.0 Upgrade — Change Log
Overview
This document records every change made during the upgrade of
pushchain/evm(fork ofcosmos/evm) from v0.4.0 to v0.5.1, and the corresponding updates to the push-chain consumer chain. It also documents how every fork-specific feature was verified to survive the merge, the reasoning behind each decision made in push-chain, and the test fixes required.1. Repository Layout
push-chain/go.modreplace directives:Both repos were branched from their respective
v0.4.0branches before any changes were made, preserving a clean divergence point.2. Fork Features That Must Be Preserved
The
pushchain/evmfork carries the following non-upstream features. Every merge conflict was resolved in favour of keeping these intact:debug_traceTransaction. Allows block explorers to see Cosmos txs as ETH txs.rpc/types/events.go,rpc/backend/comet_to_eth.go,rpc/backend/tx_info.go,x/vm/keeper/call_evm.goMsgEthereumTxinstead of routing it to the fee collector module account. Required for push-chain's deflationary tokenomics.x/vm/keeper/state_transition.go,x/vm/keeper/gas.goDerivedTx-specific fields indebug_traceTransactionresponses.x/vm/keeper/grpc_query.goConsensusVersion=2.x/vm/migrations/v2/,x/vm/keeper/migrator.go,x/vm/module.gox/ibc/transfer/module.goCallEVMWithDataso state changes from failed EVM calls are discarded cleanly.x/vm/keeper/call_evm.gomempool/errors.goNewCheckTxHandlerthat usesmempool.ErrNonceLow.mempool/checktx/check_tx.goHow Preservation Was Verified
v0.5.1tag intofeat/derived-tx-evm-0.5.0, each conflict in the files listed above was reviewed against the upstream change. Upstream changes were applied (API signature updates, import path changes) while the fork-specific logic was kept in all cases.go build ./...was run in the evm fork to confirm no compilation errors.go test -tags=test ./x/vm/... ./x/feemarket/...was run to confirm the fork's own unit tests pass (the-tags=testflag is required becauseEVMConfigurator.ResetTestConfig()is only implemented under that build tag).3. Changes in the evm Fork (
/evm)These are the code-level changes made to the fork after merging upstream v0.5.1. The merge itself brought in all upstream API changes; these are the fixes to remaining compile errors and test failures.
3.1
rpc/backend/blocks.goChange:
msgs := b.EthMsgsFromCometBlock(...)→msgs, _ := b.EthMsgsFromCometBlock(...)Why: In v0.5,
EthMsgsFromCometBlockwas changed to return two values:([]*MsgEthereumTx, []*TxResultAdditionalFields). The second return value carries the DerivedTx metadata; it is intentionally discarded here with_becauseGetBlockReceiptsonly needs the messages. The DerivedTx path that uses additional fields is handled incomet_to_eth.go.3.2
rpc/backend/tx_info.goChange: Removed a stray
), niltoken at line 450.Why: During the merge, an orphaned closing-paren and nil from a previous append operation was left in the file as a dangling token outside any function body, causing a syntax error. It had no semantic meaning and was simply removed.
3.3
tests/integration/rpc/backend/test_blocks.goChange: Four callers of
EthMsgsFromCometBlockupdated from single-variable to two-variable form:msgs, _ := s.backend.EthMsgsFromCometBlock(...).Why: Same v0.5 signature change as 3.1. The integration test file had four call sites that needed updating.
3.4
client/keys/add.goChange:
Why: The upstream
cosmos/evmfork was updated for cosmos-sdk v0.53.5, which addedSetDERConversionand exposedAppNameas a public field. Push-chain is pinned to cosmos-sdk v0.50.10, which has the older Ledger API (SetSkipDERConversion()instead ofSetDERConversion(false), and no publicAppNamefield). The evm fork'sclient/keys/add.gohad to match the older API to compile against push-chain's pinned SDK.4. Changes in push-chain (
/push-chain)Each subsection explains the change, the v0.5 API that required it, and the decision behind the implementation approach chosen.
4.1
app/app.go— Import Cleanup:cosmos/evm/typesRemovalChange: Replaced:
with:
Updated usages:
cosmosevmtypes.HasDynamicFeeExtensionOption→antetypes.HasDynamicFeeExtensionOptioncosmosevmtypes.GenesisState→map[string]json.RawMessage(inlined)Why: Upstream v0.5 deleted the
cosmos/evm/typespackage entirely.HasDynamicFeeExtensionOptionwas moved toante/types.GenesisState(which wasmap[string]json.RawMessage) no longer needs a named type alias; the raw map type is sufficient and matches what the SDK'sAppModuleBasic.DefaultGenesisreturns.4.2
app/app.go—evmkeeper.NewKeeperSignatureChange: Added
EVMChainIDparameter and changedConsensusParamsKeeperto a pointer:Why: In v0.5,
NewKeepernow internally callsSetChainConfig(DefaultChainConfig(evmChainID))to register the EVM chain configuration as a global singleton. The chain ID must be passed explicitly so the keeper can do this. Previously the chain config was set externally viaEVMConfigurator.WithChainConfig.ConsensusParamsKeeperbecame a pointer parameter to match the keeper's internal interface expectation after the SDK update.4.3
app/app.go—ibctransferkeeper.NewKeeperSignatureChange: Removed
app.GetSubspace(ibctransfertypes.ModuleName)argument.Why: IBC-go v10 (brought in by cosmos/evm v0.5) removed the
Subspacedependency from the transfer keeper. The keeper no longer manages its own params via the legacy params subspace; params are now in the module's own KV store.4.4
app/app.go—vm.NewAppModuleSignatureChange: Added
app.BankKeeperparameter:Why: The EVM module's
AppModule.InitGenesisin v0.5 callsInitEvmCoinInfo, which reads denom metadata from the bank keeper.AppModuletherefore now requires aBankKeeperat construction so it can pass it through toInitGenesis.4.5
app/app.go—SetOrderPreBlockers: Addedevmtypes.ModuleNameChange:
Why: In v0.5,
AppModulefor the EVM module gained aPreBlockhook. This hook is called on the first block of every process lifecycle (usingsync.Once) and invokesSetGlobalConfigVariables, which registers the EVM coin denom and EIP activators as process-wide globals read from chain state. If the module is not listed inSetOrderPreBlockers, the cosmos-sdk module manager panics at startup with "missing module" because all modules implementingHasPreBlockermust be explicitly ordered.4.6
app/app.go—DefaultGenesis: SetEvmDenom = BaseDenomChange:
Why: The upstream default
EvmDenomis"aatom"(the cosmos/evm test denomination). Push-chain uses"upc". DuringInitGenesis,InitEvmCoinInfolooks up theEvmDenomfrom EVM module params and then retrieves its metadata from the bank module. If the genesis uses"aatom", no bank metadata for that denom exists in push-chain's genesis, and the chain panics at genesis init. SettingEvmDenom = BaseDenominDefaultGenesisensures the correct denom flows through.4.7
app/app.go—GetMempool()MethodChange: Added:
Why: The
evmserver.Applicationinterface gained aGetMempool() sdkmempool.ExtMempoolmethod in v0.5, used by the EVM server's mempool wiring. Push-chain does not use the EVM extended mempool (it uses the default SDK mempool), so returningnilis correct and tells the server to use the base mempool.4.8
app/config.go— RemovedSetChainConfigandConfigure()fromEVMAppOptionsChange: Removed:
EVMAppOptionsnow only callssetBaseDenom(coinInfo)(which registers the denomination with the cosmos-sdksdk.RegisterDenom).Why — Two separate issues:
SetChainConfigremoved:evmkeeper.NewKeeper(called inNewChainApp) already callsSetChainConfig(DefaultChainConfig(evmChainID))internally.SetChainConfigis a singleton guard — calling it twice with a non-default chain ID panics with "chainConfig already set". The keeper's internal call is the authoritative one; the duplicate inEVMAppOptionswas redundant and broke.Configure()removed: The EVMAppModule.PreBlockmethod callsSetGlobalConfigVariables(usingsync.Once) on the first block of every node process.SetGlobalConfigVariablesitself callsNewEVMConfigurator().Configure(), which callssetEVMCoinInfo.setEVMCoinInfoalso enforces a singleton — calling it twice panics with "EVM coin info already set". BecausePreBlockruns before any transaction processing on every node restart, andInitGenesisalso callsSetGlobalConfigVariableson chain genesis, there is no block of the chain's lifecycle whereConfigure()needs to be called from app-level startup code. Removing it fromEVMAppOptionseliminates the double-set.What
EVMAppOptionsstill does: It registers the denomination with the cosmos-sdk denomination registry viasdk.RegisterDenom. This is needed at startup (before the first block) so fee calculations and coin parsing work correctly. This call is idempotent (registering the same denom twice is a no-op), so it is safe to keep.4.9
app/ante/handler_options.go— RemovedTxFeeCheckerFieldChange: Removed the
TxFeeChecker ante.TxFeeCheckerfield fromHandlerOptionsstruct and its corresponding check fromValidate().Why: In v0.5,
NewDynamicFeeCheckerchanged signature — it now takes*feemarkettypes.Params(pre-fetched params) instead of a keeper. Constructing the checker therefore requires asdk.Contextto fetch params.HandlerOptionsis a struct set up at startup without a context, so it can no longer hold a pre-built checker. The checker is now constructed inline insideNewCosmosAnteHandler(ctx, options)at the point where the context is available. The field was removed entirely to avoid confusion; leaving it as a nil-able field with a mandatory validation check would have been misleading.4.10
app/ante/ante_evm.go—newMonoEVMAnteHandlerAcceptsctxChange:
Why:
NewEVMMonoDecoratorin v0.5 takes*evmtypes.Paramsand*feemarkettypes.Paramsinstead of extracting them from keepers at decoration time. This was an upstream performance optimisation: params are fetched once at handler construction rather than on every transaction. Fetching at construction time requires a context, which is provided at ante handler setup inNewAnteHandler(ctx, options). The params are passed as pointers to avoid copying; the pointed-to values are read-only after construction.4.11
app/ante/ante_cosmos.go—NewCosmosAnteHandlerAcceptsctxChange:
Why: Same motivation as 4.10.
NewDynamicFeeCheckernow takes*feemarkettypes.Params.NewGasWantedDecoratoralso requires*feemarkettypes.Paramsas a new parameter. Both need params fetched from state, which requires a context. Constructing them at handler setup (with a context) rather than at decoration time (per-tx) is the intentional design in v0.5.4.12
app/precompiles.go— Full Rewrite for v0.5 Precompile ConstructorsChanges:
*Precompiledirectly (no error return), exceptbech32.NewPrecompilewhich still returns an error.MsgServer+QueryServerobjects instead of deriving them internally.evmKeeper(removed from its constructor in v0.5).erc20KeeperandtransferKeeperare now passed as pointers (*erc20Keeper.Keeper,*transferkeeper.Keeper).NewAvailableStaticPrecompileschanged accordingly:evmKeeperparameter removed.Why: The v0.5 precompile API change was architectural: precompile constructors moved to dependency injection for message and query servers rather than constructing them from keeper references. This decouples the precompile from the keeper's concrete implementation of the server interfaces. Returning
*Precompilewithout an error was a cleanup — all precompiles that could previously error on construction were refactored so construction is infallible (errors at init time panic, which is appropriate for misconfiguration).4.13
precompiles/usigverifier/usigverifier.go— Embeddedabi.ABIfor v0.5Change:
Why: In v0.5, the
ABIfield was removed fromcmn.Precompile(the shared base struct). Each concrete precompile now embedsabi.ABIdirectly. This was done upstream to avoid a shared-state footgun (previously all precompiles that usedcmn.Precompileshared the same ABI pointer type, which could cause confusion when different precompiles have different ABIs). Theinit()pattern loads the ABI once at package init time, making it a package-level constant for the precompile's lifetime.MethodByIdcalls were updated fromp.MethodById(...)top.ABI.MethodById(...)to reflect the new embedding path.4.14
app/upgrades/evm-v0-5-0/upgrade.go(NEW FILE)Change: Created a new upgrade handler:
Registered in
app/upgrades.go.Why: In v0.5, chain denomination and decimal configuration is no longer purely derived from app-level options at startup. It is now persisted in the EVM module's KV store (on-chain state). Existing chains upgrading from v0.4 do not have this on-chain record yet.
InitEvmCoinInforeads the denom metadata from the bank module (which is already on-chain) and writes the coin info record into the EVM module's store. Without this call, after the upgrade the EVM module would fail to find its coin info on restarts (theGetEvmCoinInfowould return the fallbackdefaultEvmCoinInfofrom the keeper, which may differ from the actual chain denom).RunMigrationsis called after to pick up any consensus version bumps in the EVM module.4.15
app/test_helpers.go— Bank Denom Metadata forupcChange: In
GenesisStateWithValSet, the bank genesis now includes denom metadata forupc:Why:
InitEvmCoinInfo(called fromInitGenesis) reads bank module denom metadata to derive the EVM coin's display denomination and decimal precision. In v0.5, this metadata is mandatory — without it,InitGenesispanics with "denom metadata upc could not be found". In production, the bank module genesis is populated with denom metadata via the chain's genesis file. In tests, the bank genesis is rebuilt from scratch byGenesisStateWithValSetwith an empty metadata list, so the metadata has to be added explicitly. This is the test-equivalent of what the evmd reference does vianetwork.GenerateBankGenesisMetadata(evmChainID).4.16
app/test_helpers.go—ResetTestConfigCleanupChange: Added
t.Cleanup(func() { evmtypes.NewEVMConfigurator().ResetTestConfig() })in bothsetup()andNewChainAppWithCustomOptions().Why: The EVM configurator's
setTestingEVMCoinInfo(used in test builds) is a process-wide singleton: once set, it returns an error on any subsequent set attempt. Each test that callsInitChain(which triggersInitGenesis→SetGlobalConfigVariables→Configure()→setTestingEVMCoinInfo) sets this global. When the next test tries to do the same, it panics with "testing EVM coin info already set".ResetTestConfig()clears the test-mode EVM coin info, chain config, and EIP activators back to nil/empty so the next test can re-initialize them. Registering it ast.Cleanupensures it runs automatically after each test, even on failure, without needing to be called explicitly in every test case. This pattern mirrors the evm fork's own test helpers which callResetTestConfigbetween test setup calls.5. Summary of v0.4.0 → v0.5.0 Breaking Changes Applied
cosmos/evm/typespackage deletedevmfork (conflict resolution),push-chain/app/app.go(import swap)EthMsgsFromCometBlockreturns 2 valuesevm/rpc/backend/blocks.go,evm/tests/integration/rpc/backend/test_blocks.goApplyMessageWithConfignewoverridesparamevmfork (conflict resolution)GetTxByEthHash/GetTxByTxIndexreturn 3 valuesevm/rpc/backend/tx_info.go(conflict resolution)NewTransactionFromMsgnewblockTimeparam,*ChainConfigevmfork (conflict resolution)rpc/backend/blocks.gosplit intocomet.go,comet_to_eth.go,headers.gocomet_to_eth.goEventTypeTxLogremoved upstreamevm/x/vm/types/events.go(fork-specific need)AllowUnprotectedTxsremoved from ParamsABImoved out ofcmn.Precompileevmfork +push-chain/precompiles/usigverifier/MethodById→p.ABI.MethodByIdpush-chain/precompiles/usigverifier/evmkeeper.NewKeepernewevmChainIDparampush-chain/app/app.goConsensusParamsKeeperas pointer inNewKeeperpush-chain/app/app.goibctransferkeeper.NewKeeperSubspaceremovedpush-chain/app/app.govm.NewAppModulenewBankKeeperparampush-chain/app/app.goEVMMonoDecoratortakes*Paramspush-chain/app/ante/ante_evm.goGasWantedDecoratortakes*feemarkettypes.Paramspush-chain/app/ante/ante_cosmos.goNewDynamicFeeCheckertakes*feemarkettypes.Paramspush-chain/app/ante/ante_cosmos.go*Precompile(no error)push-chain/app/precompiles.gopush-chain/app/precompiles.goevmKeeperpush-chain/app/precompiles.goEVMConfigurator.WithChainConfigremovedpush-chain/app/config.go(removed; keeper handles it)evmtypes.EighteenDecimals.Uint32()conversion neededpush-chain/app/config.goevmserver.ApplicationrequiresGetMempool()push-chain/app/app.gopush-chain/app/upgrades/evm-v0-5-0/upgrade.go(new upgrade handler)cosmos-sdkLedger API v0.50 vs v0.53 incompatibilityevm/client/keys/add.go6. Test Results
evm fork
x/vm/client/clix/vm/keeperx/vm/statedbx/vm/store/snapshotkvx/vm/store/snapshotmultix/vm/typesx/vm/wrappersx/feemarket/typespush-chain
appapp/anteapp/decoratorsapp/upgrades/purge-expired-outboundsapp/upgrades/tss-fund-migration-fixesx/uexecutor/keeperx/uexecutor/typesx/uregistry/keeperx/uregistry/migrations/v3x/uregistry/typesNote: Both repos must be tested with
-tags=test. Without this flag,EVMConfigurator.ResetTestConfig()panics (it is only implemented inconfig_testing.gowhich is gated behind thetestbuild tag). This is an intentional design in the evm fork to prevent accidental config resets in production builds.7. Build Commands
8. Upgrade Handler Execution Path
On a live chain upgrading from
evm-v0-4-0toevm-v0-5-0:"evm-v0-5-0".CreateUpgradeHandlerruns:a.
keepers.EVMKeeper.InitEvmCoinInfo(ctx)— readsparams.EvmDenomfrom EVM module state, reads denom metadata from bank module, writes the coin info record into EVM module KV store.b.
mm.RunMigrations(ctx, configurator, fromVM)— runs any registered module migrations, including any consensus version bump for the EVM module.PreBlockrunsSetGlobalConfigVariableswhich reads coin info from the KV store (now populated) and sets process-wide globals.If
InitEvmCoinInfofails (e.g., bank has no metadata for the EVM denom), the upgrade halts with a descriptive error rather than leaving the chain in a partially-upgraded state.9. Decisions Not Taken and Why
Q: Why not make
SetChainConfig/setEVMCoinInfoidempotent in the evm fork?Making the singleton guards silently ignore duplicate calls with identical values would mask bugs where the same config is initialized from two paths. The chosen approach (remove the duplicate call site in
EVMAppOptions) is cleaner because it makes there be exactly one authoritative call site: the keeper forSetChainConfig, andPreBlock/InitGenesisforConfigure().Q: Why not keep
TxFeeCheckerinHandlerOptionsand construct it at ante handler setup time with a stored context?Storing a
sdk.Contextin a long-lived struct is an anti-pattern in the cosmos-sdk: contexts carry block state and are only valid for a single request's lifetime. The correct approach is to construct context-dependent objects at the start of each request path. SinceNewAnteHandleris called once at node startup (with a checkState context), and then ante decorators run per-transaction, the right place for this construction is at handler setup.Q: Why not update the
DisplayDenomplaceholder"MY_DENOM_DISPLAY"?That is a pre-existing placeholder in the push-chain codebase and outside the scope of the EVM upgrade. The upgrade changes are intentionally scoped to the EVM/feemarket integration. Updating denominations would require a broader discussion about the chain's tokenomics and naming.
References
Changes
Testing
go test ./...Checklist