Skip to content

feat: evm 0.5.0 upgrade#256

Open
AryaLanjewar3005 wants to merge 7 commits into
mainfrom
evm-upgrade-0.5.0
Open

feat: evm 0.5.0 upgrade#256
AryaLanjewar3005 wants to merge 7 commits into
mainfrom
evm-upgrade-0.5.0

Conversation

@AryaLanjewar3005
Copy link
Copy Markdown
Collaborator

Summary

EVM v0.5.0 Upgrade — Change Log

Overview

This document records every change made during the upgrade of pushchain/evm (fork of cosmos/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

upgrade-evm-0.5.0/
├── evm/          pushchain/evm fork  (branch: feat/derived-tx-evm-0.5.0)
├── push-chain/   consumer chain      (branch: evm-upgrade-0.5.0)
├── dkls23-rs/    TSS library (local go-wrapper dependency)
└── garbling/     garbling library

push-chain/go.mod replace directives:

github.com/cosmos/evm => ../evm
go-wrapper => ../dkls23-rs/wrapper/go-wrappers

Both repos were branched from their respective v0.4.0 branches before any changes were made, preserving a clean divergence point.


2. Fork Features That Must Be Preserved

The pushchain/evm fork carries the following non-upstream features. Every merge conflict was resolved in favour of keeping these intact:

Feature Description Key Files
DerivedTx Cosmos messages (non-EVM txs) exposed as derived Ethereum transactions over JSON-RPC and 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.go
baseFeeBurn Burns the base fee component of MsgEthereumTx instead 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.go
Custom tracing Exposes DerivedTx-specific fields in debug_traceTransaction responses. x/vm/keeper/grpc_query.go
VM Params v2 migration Migrates EVM module state from v1 to v2 params format; ConsensusVersion=2. x/vm/migrations/v2/, x/vm/keeper/migrator.go, x/vm/module.go
IBC transfer v5→v6 Custom IBC transfer module wrapping the upstream v5-to-v6 migration. x/ibc/transfer/module.go
JSON-RPC chainID Wires the EVM chain ID through JSON-RPC startup. RPC startup files
CallEVMWithData cache-context Uses a cache context for CallEVMWithData so state changes from failed EVM calls are discarded cleanly. x/vm/keeper/call_evm.go
ErrNonceLow Custom mempool error type for low-nonce rejection. mempool/errors.go
checktx subpackage NewCheckTxHandler that uses mempool.ErrNonceLow. mempool/checktx/check_tx.go

How Preservation Was Verified

  1. After merging the v0.5.1 tag into feat/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.
  2. go build ./... was run in the evm fork to confirm no compilation errors.
  3. go test -tags=test ./x/vm/... ./x/feemarket/... was run to confirm the fork's own unit tests pass (the -tags=test flag is required because EVMConfigurator.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.go

Change: msgs := b.EthMsgsFromCometBlock(...)msgs, _ := b.EthMsgsFromCometBlock(...)

Why: In v0.5, EthMsgsFromCometBlock was changed to return two values: ([]*MsgEthereumTx, []*TxResultAdditionalFields). The second return value carries the DerivedTx metadata; it is intentionally discarded here with _ because GetBlockReceipts only needs the messages. The DerivedTx path that uses additional fields is handled in comet_to_eth.go.

3.2 rpc/backend/tx_info.go

Change: Removed a stray ), nil token 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.go

Change: Four callers of EthMsgsFromCometBlock updated 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.go

Change:

// Removed (cosmos-sdk v0.53.5 only):
cosmosLedger.SetDERConversion(false)
cosmosLedger.AppName  // field access

// Replaced with:
cosmosLedger.SetSkipDERConversion()  // equivalent for v0.50.x
"Cosmos"                              // hardcoded, was cosmosLedger.AppName

Why: The upstream cosmos/evm fork was updated for cosmos-sdk v0.53.5, which added SetDERConversion and exposed AppName as a public field. Push-chain is pinned to cosmos-sdk v0.50.10, which has the older Ledger API (SetSkipDERConversion() instead of SetDERConversion(false), and no public AppName field). The evm fork's client/keys/add.go had 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/types Removal

Change: Replaced:

cosmosevmtypes "github.com/cosmos/evm/types"

with:

antetypes "github.com/cosmos/evm/ante/types"

Updated usages:

  • cosmosevmtypes.HasDynamicFeeExtensionOptionantetypes.HasDynamicFeeExtensionOption
  • cosmosevmtypes.GenesisStatemap[string]json.RawMessage (inlined)

Why: Upstream v0.5 deleted the cosmos/evm/types package entirely. HasDynamicFeeExtensionOption was moved to ante/types. GenesisState (which was map[string]json.RawMessage) no longer needs a named type alias; the raw map type is sufficient and matches what the SDK's AppModuleBasic.DefaultGenesis returns.

4.2 app/app.goevmkeeper.NewKeeper Signature

Change: Added EVMChainID parameter and changed ConsensusParamsKeeper to a pointer:

app.EVMKeeper = evmkeeper.NewKeeper(
    appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], keys,
    authtypes.NewModuleAddress(govtypes.ModuleName),
    authKeeperEVMWrapper{app.AccountKeeper},
    app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
    &app.ConsensusParamsKeeper,  // pointer (was value)
    &app.Erc20Keeper,
    EVMChainID,                  // new parameter
    tracer,
)

Why: In v0.5, NewKeeper now internally calls SetChainConfig(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 via EVMConfigurator.WithChainConfig. ConsensusParamsKeeper became a pointer parameter to match the keeper's internal interface expectation after the SDK update.

4.3 app/app.goibctransferkeeper.NewKeeper Signature

Change: Removed app.GetSubspace(ibctransfertypes.ModuleName) argument.

Why: IBC-go v10 (brought in by cosmos/evm v0.5) removed the Subspace dependency 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.govm.NewAppModule Signature

Change: Added app.BankKeeper parameter:

vm.NewAppModule(app.EVMKeeper, app.AccountKeeper, app.BankKeeper)

Why: The EVM module's AppModule.InitGenesis in v0.5 calls InitEvmCoinInfo, which reads denom metadata from the bank keeper. AppModule therefore now requires a BankKeeper at construction so it can pass it through to InitGenesis.

4.5 app/app.goSetOrderPreBlockers: Added evmtypes.ModuleName

Change:

app.ModuleManager.SetOrderPreBlockers(
    upgradetypes.ModuleName,
    authtypes.ModuleName,
    evmtypes.ModuleName,  // added
)

Why: In v0.5, AppModule for the EVM module gained a PreBlock hook. This hook is called on the first block of every process lifecycle (using sync.Once) and invokes SetGlobalConfigVariables, which registers the EVM coin denom and EIP activators as process-wide globals read from chain state. If the module is not listed in SetOrderPreBlockers, the cosmos-sdk module manager panics at startup with "missing module" because all modules implementing HasPreBlocker must be explicitly ordered.

4.6 app/app.goDefaultGenesis: Set EvmDenom = BaseDenom

Change:

evmGenState := evmtypes.DefaultGenesisState()
evmGenState.Params.ActiveStaticPrecompiles = evmtypes.AvailableStaticPrecompiles
evmGenState.Params.EvmDenom = BaseDenom  // added
genesis[evmtypes.ModuleName] = a.appCodec.MustMarshalJSON(evmGenState)

Why: The upstream default EvmDenom is "aatom" (the cosmos/evm test denomination). Push-chain uses "upc". During InitGenesis, InitEvmCoinInfo looks up the EvmDenom from 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. Setting EvmDenom = BaseDenom in DefaultGenesis ensures the correct denom flows through.

4.7 app/app.goGetMempool() Method

Change: Added:

func (app *ChainApp) GetMempool() sdkmempool.ExtMempool {
    return nil
}

Why: The evmserver.Application interface gained a GetMempool() sdkmempool.ExtMempool method 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 returning nil is correct and tells the server to use the base mempool.

4.8 app/config.go — Removed SetChainConfig and Configure() from EVMAppOptions

Change: Removed:

if err := evmtypes.SetChainConfig(evmtypes.DefaultChainConfig(EVMChainID)); err != nil {
    return err
}
err := evmtypes.NewEVMConfigurator().WithEVMCoinInfo(coinInfo).Configure()
if err != nil { return err }

EVMAppOptions now only calls setBaseDenom(coinInfo) (which registers the denomination with the cosmos-sdk sdk.RegisterDenom).

Why — Two separate issues:

SetChainConfig removed: evmkeeper.NewKeeper (called in NewChainApp) already calls SetChainConfig(DefaultChainConfig(evmChainID)) internally. SetChainConfig is 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 in EVMAppOptions was redundant and broke.

Configure() removed: The EVM AppModule.PreBlock method calls SetGlobalConfigVariables (using sync.Once) on the first block of every node process. SetGlobalConfigVariables itself calls NewEVMConfigurator().Configure(), which calls setEVMCoinInfo. setEVMCoinInfo also enforces a singleton — calling it twice panics with "EVM coin info already set". Because PreBlock runs before any transaction processing on every node restart, and InitGenesis also calls SetGlobalConfigVariables on chain genesis, there is no block of the chain's lifecycle where Configure() needs to be called from app-level startup code. Removing it from EVMAppOptions eliminates the double-set.

What EVMAppOptions still does: It registers the denomination with the cosmos-sdk denomination registry via sdk.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 — Removed TxFeeChecker Field

Change: Removed the TxFeeChecker ante.TxFeeChecker field from HandlerOptions struct and its corresponding check from Validate().

Why: In v0.5, NewDynamicFeeChecker changed signature — it now takes *feemarkettypes.Params (pre-fetched params) instead of a keeper. Constructing the checker therefore requires a sdk.Context to fetch params. HandlerOptions is 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 inside NewCosmosAnteHandler(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.gonewMonoEVMAnteHandler Accepts ctx

Change:

// Before:
func newMonoEVMAnteHandler(options HandlerOptions) sdk.AnteHandler

// After:
func newMonoEVMAnteHandler(ctx sdk.Context, options HandlerOptions) sdk.AnteHandler {
    evmParams := options.EvmKeeper.GetParams(ctx)
    feemarketParams := options.FeeMarketKeeper.GetParams(ctx)
    return sdk.ChainAnteDecorators(
        evmante.NewEVMMonoDecorator(..., &evmParams, &feemarketParams),
    )
}

Why: NewEVMMonoDecorator in v0.5 takes *evmtypes.Params and *feemarkettypes.Params instead 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 in NewAnteHandler(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.goNewCosmosAnteHandler Accepts ctx

Change:

// Before:
func NewCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler

// After:
func NewCosmosAnteHandler(ctx sdk.Context, options HandlerOptions) sdk.AnteHandler {
    feemarketParams := options.FeeMarketKeeper.GetParams(ctx)
    txFeeChecker := evmante.NewDynamicFeeChecker(&feemarketParams)
    return sdk.ChainAnteDecorators(
        ...
        NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, txFeeChecker),
        ...
        evmante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper, &feemarketParams),
    )
}

Why: Same motivation as 4.10. NewDynamicFeeChecker now takes *feemarkettypes.Params. NewGasWantedDecorator also requires *feemarkettypes.Params as 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 Constructors

Changes:

  • All precompile constructors now return *Precompile directly (no error return), except bech32.NewPrecompile which still returns an error.
  • Staking, distribution, gov, and slashing precompiles now receive injected MsgServer + QueryServer objects instead of deriving them internally.
  • ICS20 precompile no longer receives evmKeeper (removed from its constructor in v0.5).
  • erc20Keeper and transferKeeper are now passed as pointers (*erc20Keeper.Keeper, *transferkeeper.Keeper).
  • Function signature for NewAvailableStaticPrecompiles changed accordingly: evmKeeper parameter 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 *Precompile without 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 — Embedded abi.ABI for v0.5

Change:

// Before (v0.4 pattern):
type Precompile struct {
    cmn.Precompile  // ABI was inside cmn.Precompile
}
// Constructor set p.Precompile.ABI = ...
// Method call: p.MethodById(methodID)

// After (v0.5 pattern):
var ABI abi.ABI

func init() {
    var err error
    ABI, err = cmn.LoadABI(f, "abi.json")
    if err != nil { panic(err) }
}

type Precompile struct {
    cmn.Precompile
    abi.ABI  // embedded directly in the concrete precompile struct
}
// Method call: p.ABI.MethodById(methodID)

Why: In v0.5, the ABI field was removed from cmn.Precompile (the shared base struct). Each concrete precompile now embeds abi.ABI directly. This was done upstream to avoid a shared-state footgun (previously all precompiles that used cmn.Precompile shared the same ABI pointer type, which could cause confusion when different precompiles have different ABIs). The init() pattern loads the ABI once at package init time, making it a package-level constant for the precompile's lifetime. MethodById calls were updated from p.MethodById(...) to p.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:

const UpgradeName = "evm-v0-5-0"

func CreateUpgradeHandler(...) upgradetypes.UpgradeHandler {
    return func(ctx context.Context, ...) (module.VersionMap, error) {
        if err := keepers.EVMKeeper.InitEvmCoinInfo(sdkCtx); err != nil {
            return nil, fmt.Errorf("InitEvmCoinInfo: %w", err)
        }
        return mm.RunMigrations(ctx, configurator, fromVM)
    }
}

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. InitEvmCoinInfo reads 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 (the GetEvmCoinInfo would return the fallback defaultEvmCoinInfo from the keeper, which may differ from the actual chain denom). RunMigrations is called after to pick up any consensus version bumps in the EVM module.

4.15 app/test_helpers.go — Bank Denom Metadata for upc

Change: In GenesisStateWithValSet, the bank genesis now includes denom metadata for upc:

evmDenomMetadata := banktypes.Metadata{
    Description: "Native 18-decimal denom for push chain",
    Base:        BaseDenom,   // "upc"
    DenomUnits: []*banktypes.DenomUnit{
        {Denom: BaseDenom, Exponent: 0},
        {Denom: DisplayDenom, Exponent: 18},
    },
    Name:    "Push Chain",
    Symbol:  "PC",
    Display: DisplayDenom,
}
bankGenesis := banktypes.NewGenesisState(..., []banktypes.Metadata{evmDenomMetadata}, ...)

Why: InitEvmCoinInfo (called from InitGenesis) 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, InitGenesis panics 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 by GenesisStateWithValSet with an empty metadata list, so the metadata has to be added explicitly. This is the test-equivalent of what the evmd reference does via network.GenerateBankGenesisMetadata(evmChainID).

4.16 app/test_helpers.goResetTestConfig Cleanup

Change: Added t.Cleanup(func() { evmtypes.NewEVMConfigurator().ResetTestConfig() }) in both setup() and NewChainAppWithCustomOptions().

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 calls InitChain (which triggers InitGenesisSetGlobalConfigVariablesConfigure()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 as t.Cleanup ensures 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 call ResetTestConfig between test setup calls.


5. Summary of v0.4.0 → v0.5.0 Breaking Changes Applied

Breaking Change Where Applied
cosmos/evm/types package deleted evm fork (conflict resolution), push-chain/app/app.go (import swap)
EthMsgsFromCometBlock returns 2 values evm/rpc/backend/blocks.go, evm/tests/integration/rpc/backend/test_blocks.go
ApplyMessageWithConfig new overrides param evm fork (conflict resolution)
GetTxByEthHash/GetTxByTxIndex return 3 values evm/rpc/backend/tx_info.go (conflict resolution)
NewTransactionFromMsg new blockTime param, *ChainConfig evm fork (conflict resolution)
rpc/backend/blocks.go split into comet.go, comet_to_eth.go, headers.go Applied during merge; DerivedTx helpers kept in comet_to_eth.go
EventTypeTxLog removed upstream Re-added in evm/x/vm/types/events.go (fork-specific need)
AllowUnprotectedTxs removed from Params Removed from v2 migration and params (conflict resolution)
Precompile ABI moved out of cmn.Precompile evm fork + push-chain/precompiles/usigverifier/
MethodByIdp.ABI.MethodById push-chain/precompiles/usigverifier/
evmkeeper.NewKeeper new evmChainID param push-chain/app/app.go
ConsensusParamsKeeper as pointer in NewKeeper push-chain/app/app.go
ibctransferkeeper.NewKeeper Subspace removed push-chain/app/app.go
vm.NewAppModule new BankKeeper param push-chain/app/app.go
EVMMonoDecorator takes *Params push-chain/app/ante/ante_evm.go
GasWantedDecorator takes *feemarkettypes.Params push-chain/app/ante/ante_cosmos.go
NewDynamicFeeChecker takes *feemarkettypes.Params push-chain/app/ante/ante_cosmos.go
Precompile constructors return *Precompile (no error) push-chain/app/precompiles.go
Staking/gov/slashing/distribution take MsgServer+QueryServer push-chain/app/precompiles.go
ICS20 precompile drops evmKeeper push-chain/app/precompiles.go
EVMConfigurator.WithChainConfig removed push-chain/app/config.go (removed; keeper handles it)
evmtypes.EighteenDecimals.Uint32() conversion needed push-chain/app/config.go
evmserver.Application requires GetMempool() push-chain/app/app.go
Chain/denom config now persisted in EVM module state push-chain/app/upgrades/evm-v0-5-0/upgrade.go (new upgrade handler)
cosmos-sdk Ledger API v0.50 vs v0.53 incompatibility evm/client/keys/add.go

6. Test Results

evm fork

go test -tags=test ./x/vm/... ./x/feemarket/...
Package Result
x/vm/client/cli PASS
x/vm/keeper PASS
x/vm/statedb PASS
x/vm/store/snapshotkv PASS
x/vm/store/snapshotmulti PASS
x/vm/types PASS
x/vm/wrappers PASS
x/feemarket/types PASS

push-chain

go test -tags=test -mod=mod ./app/... ./x/uexecutor/... ./x/uregistry/... ./precompiles/...
Package Result
app PASS
app/ante PASS
app/decorators PASS
app/upgrades/purge-expired-outbounds PASS
app/upgrades/tss-fund-migration-fixes PASS
x/uexecutor/keeper PASS
x/uexecutor/types PASS
x/uregistry/keeper PASS
x/uregistry/migrations/v3 PASS
x/uregistry/types PASS

Note: Both repos must be tested with -tags=test. Without this flag, EVMConfigurator.ResetTestConfig() panics (it is only implemented in config_testing.go which is gated behind the test build tag). This is an intentional design in the evm fork to prevent accidental config resets in production builds.


7. Build Commands

# evm fork — verify build and tests
cd /Users/arya/Programming/task/upgrade-evm-0.5.0/evm
go build ./...
go test -tags=test ./x/vm/... ./x/feemarket/...

# push-chain — verify build and tests (dkls23-rs must be present)
cd /Users/arya/Programming/task/upgrade-evm-0.5.0/push-chain
go build -mod=mod ./app/... ./x/uexecutor/... ./x/uregistry/... ./precompiles/... ./cmd/...
go test -tags=test -mod=mod ./app/... ./x/uexecutor/... ./x/uregistry/... ./precompiles/...

8. Upgrade Handler Execution Path

On a live chain upgrading from evm-v0-4-0 to evm-v0-5-0:

  1. Governance passes upgrade proposal with name "evm-v0-5-0".
  2. At the upgrade height, CreateUpgradeHandler runs:
    a. keepers.EVMKeeper.InitEvmCoinInfo(ctx) — reads params.EvmDenom from 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.
  3. Node restarts; on the first block, PreBlock runs SetGlobalConfigVariables which reads coin info from the KV store (now populated) and sets process-wide globals.

If InitEvmCoinInfo fails (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/setEVMCoinInfo idempotent 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 for SetChainConfig, and PreBlock/InitGenesis for Configure().

Q: Why not keep TxFeeChecker in HandlerOptions and construct it at ante handler setup time with a stored context?

Storing a sdk.Context in 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. Since NewAnteHandler is 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 DisplayDenom placeholder "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

  • 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