feat: pushchain/evm v0.2.0 to 0.3.2 upgrade changes#223
Open
AryaLanjewar3005 wants to merge 4 commits intomainfrom
Open
feat: pushchain/evm v0.2.0 to 0.3.2 upgrade changes#223AryaLanjewar3005 wants to merge 4 commits intomainfrom
AryaLanjewar3005 wants to merge 4 commits intomainfrom
Conversation
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
cosmos/evm v0.3.2 Upgrade — Full Impact Analysis on push-chain
Part 1: Dependency Change — go-ethereum v1.10 → v1.15
The single largest driver of compile-time breakage. The
go.modreplace directive was bumped:go-ethereum v1.15 is a major release with five years of breaking changes relative to v1.10. Every item in this section is a direct consequence of that jump.
1.1 Missing packages — first failure, most visible
The very first
go build ./...after bumping../evmproduced errors like:Same for
core/stateless,crypto/kzg4844,consensus/misc/eip1559,trie/utils. These packages were introduced in go-ethereum releases between v1.10 and v1.15. They did not exist in the v1.10 Cosmos fork at all.Push-chain impact: No push-chain source file directly imported these packages. The failure cascaded from
cosmos/evm's own precompiles and internals. The only fix was thego.modreplace bump. Nothing in push-chain source needed to change for this specific issue, but nothing could compile until the replace was updated.1.2
core.Message— from interface to value structThis is the most pervasive API change in the EVM path.
v1.10 (old):
v1.15 (new):
Push-chain files affected:
x/uexecutor/keeper/evm.go— everyCallEVMhelper that built a message:CallFactoryToGetUEAAddressForOrigin,CallFactoryGetOriginForUEA,GetUniversalCoreQuoterAddress,GetUniversalCoreWPCAddress,GetDefaultFeeTierForToken,GetSwapQuote,CallUEADomainSeparator,GetGasPriceByChain,GetL1GasFeeByChain,GetTssFundMigrationGasLimitByChain— approximately 10 call sitesx/uexecutor/keeper/deploy_uea.go— UEA deploy message constructionx/uexecutor/types/expected_keepers.go— interface signatures referencingcore.Messagex/uexecutor/mocks/mock_evmkeeper.go— mock method signaturestest/integration/uexecutor/evm_hooks_and_outbound_test.go— five call sites passednilas thecore.Messageargument toPostTxProcessing(ctx, sender, nil, receipt). In v1.10,nilwas valid because the message was an interface (nullable). In v1.15,core.Messageis a concrete value type —nilis not assignable, causing a compile errorcannot use nil as core.Message value. Fixed by replacing all fivenils withcore.Message{}(the zero value).1.3
statedb.Account.Balance—*big.Int→*uint256.Intv1.10:
Balance *big.Intv1.15:
Balance *uint256.Int— go-ethereum switched its internal balance representation to the EVM's native 256-bit integer type throughout the state layer.Push-chain files affected:
x/uregistry/keeper/genesis.go—deployImplementationContract,deployProxyAdminContract,deployProxyContractall setBalance: big.NewInt(0). Changed toBalance: new(uint256.Int).The change is subtle but causes a compile error because
*big.Intand*uint256.Intare distinct types with no implicit conversion.1.4
vm.Contract.Caller()— field removed, method addedv1.10:
contract.CallerAddresswas a publiccommon.Addressfield onvm.Contract.v1.15: The field was removed and replaced with a
Caller()method.Push-chain files affected:
utils/precompile/exec.go— reads the caller address when dispatching a precompile call. Changedcontract.CallerAddress→contract.Caller().1.5
BlockContext.Time—*big.Int→uint64v1.10:
vm.BlockContext{ Time: big.NewInt(ctx.BlockTime().Unix()), ... }v1.15:
vm.BlockContext{ Time: uint64(ctx.BlockTime().Unix()), ... }— go-ethereum simplified time representation to a plainuint64(UNIX seconds) across the entire EVM.Push-chain files affected: Any keeper code that constructed
vm.BlockContextdirectly. In push-chain, this flows throughx/vm/keeper/state_transition.goin../evm, which push-chain delegates to — but any customBlockContextconstruction in hooks or custom message handling had to be updated.1.6
vm.EVMLogger→tracing.Hooksv1.10: Tracers passed to the EVM implemented the
vm.EVMLoggerinterface.v1.15: The tracer system was redesigned. Tracers are now
*tracing.Hooksstructs from the newcore/tracingpackage.Push-chain files affected: Any code passing a tracer to
ApplyMessageor constructing an EVM with a custom logger. Push-chain primarily passesnilfor the tracer, so the impact was limited to updating the type annotations in interfaces.1.7
ethtypes.LogsBloom→ethtypes.CreateBloomv1.10:
ethtypes.LogsBloom(logs)returned a bloom filter directly.v1.15:
ethtypes.CreateBloom(ðtypes.Receipt{Logs: logs}).Bytes()— the function was refactored and the old form removed.Push-chain files affected:
x/uexecutor/keeper/evm_hooks.go— computes bloom filters for EVM transaction logs.Part 2: cosmos/evm Internal API Changes
Changes in
../evmitself (not go-ethereum) that broke push-chain's integration layer.2.1
ApplyMessageandApplyMessageWithConfiggained aninternal boolparameterv0.3.1:
v0.3.2:
The
internalflag tells the EVM executor whether the call is an internally-triggered call (from cosmos modules) vs a user-submitted EVM transaction. This distinction drives different gas accounting and receipt generation paths introduced in the same upgrade.Push-chain files affected:
x/uexecutor/keeper/evm.go— allCallEVMhelpers that ultimately callApplyMessagex/uexecutor/types/expected_keepers.go— theEVMKeeperinterface definitionx/uexecutor/mocks/mock_evmkeeper.go— mock method signatures2.2 EVM keeper constructor changed —
evmkeeper.NewKeeperNewKeeperin v0.3.2 gained additional parameters for the new derived-tx and gas accounting infrastructure.Push-chain files affected:
app/app.go— the keeper instantiation call had to be updated with the new parameter set.2.3
vm.NewAppModule— module constructor changedSame pattern:
NewAppModulegained parameters.Push-chain files affected:
app/app.go— module registration in the module manager.2.4
AccountKeeperinterface grew three unordered-transaction methodsv0.3.2 cosmos/evm's ante package introduced support for unordered transactions. The
AccountKeeperinterface ingithub.com/cosmos/evm/ante/interfacesnow requires:cosmos-sdk v0.50's
AccountKeeperdoes not implement these methods. Push-chain is on cosmos-sdk v0.50 and does not use unordered transactions.Push-chain files affected:
app/ante/ante_evm.go— introducedevmAccountKeeperWrapper:This adapter wraps push-chain's existing
AccountKeeperand provides safe no-op stubs. Without it the ante handler fails to compile because the type assertion fails.2.5 Precompile constructors added required parameters
v0.3.2 expanded the precompile constructors to support richer functionality:
bankprecompile.NewPrecompileBankKeeper(first arg)govprecompile.NewPrecompileappCodec codec.Codecslashingprecompile.NewPrecompileBankKeeperevidenceprecompile.NewPrecompileBankKeeperPush-chain files affected:
app/precompiles.go—NewAvailableStaticPrecompilesfunction signature and all four call sites. The function also had to addappCodec codec.Codecto its own parameter list.2.6
GetChainID()→GetEIP155ChainID().Uint64()v0.3.1:
k.GetChainID()returneduint64directly.v0.3.2:
k.GetEIP155ChainID()returns*big.Int(mirroring go-ethereum's representation of chain IDs). Callers must call.Uint64()to get a scalar value.Push-chain files affected: Any keeper code that called
GetChainID()to embed the chain ID into an EVM message. Changed tok.GetEIP155ChainID().Uint64().2.7
Bech32StringFromHexAddressreplacesEthHexToCosmosAddrv0.3.1:
EthHexToCosmosAddr(hexAddr string) sdk.AccAddressv0.3.2:
Bech32StringFromHexAddress(hexAddr string) string— renamed and changed return type fromsdk.AccAddresstostring.Push-chain files affected:
app/app.goand address conversion utilities.2.8
EVMChainIDtype: string → uint64v0.3.1:
DefaultChainConfig(chainID string)— chain ID as a string like"9000".v0.3.2:
DefaultChainConfig(evmChainID uint64)— chain ID as a typed integer. The internaltestChainID = 262144constant was also introduced as the fallback whenevmChainID == 0.Push-chain files affected:
app/config.go—EVMAppOptionsnow callsevmtypes.DefaultChainConfig(EVMChainID)whereEVMChainID = uint64(9000)is declared inapp/app.go.2.9
MakeConfignow takesevmChainID uint64The encoding config constructor gained
evmChainID uint64to properly configure EIP-712 typed data signing with the correct chain ID.Push-chain files affected:
app/app.go—cosmosevmencoding.MakeConfig(EVMChainID).2.10
EthMsgsFromTendermintBlockreturn arity changedv0.3.1:
msgs, err := b.EthMsgsFromTendermintBlock(resBlock, blockRes)— 2 return valuesv0.3.2:
msgs, _, err := b.EthMsgsFromTendermintBlock(resBlock, blockRes)— 3 return values (added metadata return)Push-chain files affected: Any code calling this RPC backend method.
2.11
GetTxByEthHashreturn arity changedv0.3.1:
res, err := b.GetTxByEthHash(hash)— 2 return valuesv0.3.2:
res, additional, err := b.GetTxByEthHash(hash)— 3 return values (added*rpctypes.TxResultAdditionalFieldsfor derived-tx metadata)Push-chain files affected: Any code calling this directly.
2.12
ShanghaiBlock/CancunBlock→ShanghaiTime/CancunTime+ newPragueTimev0.3.1: Hardfork activation was block-number based:
ShanghaiBlock,CancunBlock.v0.3.2: Activation is timestamp-based (matching mainnet Ethereum):
ShanghaiTime,CancunTime, and a newPragueTime. This is a foundational shift in how EVM hardfork progression works.Push-chain files affected: The
DefaultChainConfigin../evm/x/vm/types/chain_config.gohandles this internally. Push-chain source files are largely shielded unless they constructed custom chain configs directly.Part 3: Runtime Behavioral Regressions Introduced by v0.3.2
These are not compile errors. They are behavioral changes that only manifest at runtime, making them harder to detect.
3.1
CallEVMWithData— Gas Meter Overflow on RevertFile:
../evm/x/vm/keeper/call_evm.goUpstream commits:
72b035b("Consume gas when EVM is called internally"),d1a82a7("gas optimizations")What changed in v0.3.2
The
CallEVMWithDatafunction — which push-chain uses for all internal EVM calls viaCallEVM— was changed to charge gas against the cosmos gas meter:The intent was sound for the nominal case: EVM gas cost should be visible in the cosmos receipt. But the revert path calls
ResetGasMeterAndConsumeGas(ctx, ctx.GasMeter().Limit())to implement EVM-standard "a reverting tx burns all gas."How push-chain is affected
Push-chain calls
CallEVM(→CallEVMWithData) from multiple cosmos message handlers:ExecuteInboundGas,ExecuteInboundFundsAndPayload,ExecutePayloadinx/uexecutor/keeper/GetSwapQuote,GetGasPriceByChain,GetL1GasFeeByChain,GetTssFundMigrationGasLimitByChainThese handlers run under the standard cosmos ante handler which provides an infinite gas meter. An infinite gas meter's
.Limit()returnsmath.MaxUint64.When
GetSwapQuoteis called and the quoter contract reverts (expected behaviour when no AMM pool exists, e.g. in tests), the code calls:This sets the gas consumed counter to
MaxUint64. The very nextConsumeGascall in any downstream code path (e.g.,UpdateUniversalTxinexecute_inbound_gas.go) triggers:Test that caught it:
TestInboundGas/quorum_reached_moves_GAS_inbound_out_of_pending_stateWhy
DerivedEVMCallWithDatawas not affected: The sibling function already usedctx.CacheContext(), isolating execution from the parent gas meter.CallEVMWithDatawas not given the same treatment in the upstream refactor.Fix applied (with approval)
Wrapped
CallEVMWithDatabody inctx.CacheContext(), mirroringDerivedEVMCallWithData:On the success path, this preserves upstream intent: charge the parent meter the actual gas used. On the revert path, the cache is discarded and the parent meter is never touched — eliminating the overflow entirely.
3.2
GetTransactionReceipt— Returns Error Instead of Null for Pending TransactionsFile:
../evm/rpc/backend/tx_info.goUpstream commit:
eee08ea(0.3.2 version merge)What changed in v0.3.2
What the Ethereum standard requires
eth_getTransactionReceiptmust returnnull(not an error) when the transaction has not yet been mined. This is the signal clients use to distinguish "pending, keep polling" from "genuine server error." Returning a-32000error is interpreted by all Ethereum tooling (forge, cast, ethers.js, viem) as a permanent failure.How push-chain is affected
The
e2e-tests/setup.sh allcommand deploys push-chain's core contracts usingforge script ... --broadcast --slow. With v0.3.2:eth_getTransactionReceipt(hash)to wait for confirmationGetTxByEthHashreturns "ethereum tx not found" →GetTransactionReceiptreturnsnil, err{"error": {"code": -32000, "message": "GetTxByEthHash 0x...: ethereum tx not found"}}--resumeThe tx IS on-chain and findable — manually calling
eth_getTransactionReceiptafter the fact returns a valid receipt withstatus: 0x1. The failure is entirely due to the timing window between broadcast and CometBFT indexer availability (typically under 1 second), which was previously handled gracefully byreturn nil, nil.Fix applied (with approval)
The other
return nil, errlines introduced by the same merge commit (for block-not-found, block-result-not-found, and decode failures) were left intact — those are genuine server errors that should propagate.Part 4: Genesis and Node Configuration Changes
These changes do not affect push-chain's Go source. They affect how the local devnet is initialized and how the node's JSON-RPC server is configured.
4.1
chain_configremoved fromtypes.ParamsgenesisFile:
local-native/scripts/setup-genesis-auto.shWhat changed in v0.3.2
In v0.3.1, the EVM chain configuration (chain ID, hardfork block numbers, etc.) was part of
types.Paramsand persisted in genesis:{ "app_state": { "evm": { "params": { "evm_denom": "upc", "chain_config": { "chain_id": 9000, "homestead_block": "0" } } } } }In v0.3.2,
chain_configwas removed from theParamsproto definition entirely. Chain configuration is now registered once at process startup viaEVMConfiguratorinapp/config.goand is never stored in genesis or on-chain state. This matches the upstream direction of making chain config a build-time constant rather than a governance-managed parameter.How push-chain devnet was affected
setup-genesis-auto.shwas still injecting:update_genesis ".app_state[\"evm\"][\"params\"][\"chain_config\"][\"chain_id\"]=$EVM_CHAIN_ID"pchainduses strict proto-JSON unmarshaling when loading genesis. Unknown fields cause a panic, not a warning:The node process exited immediately on every start attempt. The devnet could never reach consensus because validator 1 (the genesis validator) died before producing a single block.
Fix
Removed that line from the setup script.
chain_configis now set entirely viaEVMAppOptions→EVMConfiguratorat startup, requiring no genesis entry.4.2
evm-chain-idinapp.tomlis now the authoritative EVM chain ID for the RPC backendFile:
local-native/scripts/setup-genesis-auto.shWhat changed in v0.3.2
Previously, the EVM chain ID used by the JSON-RPC backend for transaction validation was derived from the genesis params (via
chain_config.chain_id). In v0.3.2, withchain_configremoved from genesis, the RPC backend reads the EVM chain ID fromapp.toml:The default value
262144is the internal test chain ID (testChainIDinchain_config.go). This default exists so the evm module works out of the box in test environments. It has no relation to push-chain's production chain ID of9000.How push-chain devnet was affected
The devnet setup script ran
pchaind initwhich generatedapp.tomlwithevm-chain-id = 262144. The script never patched this field. The running node then had a split personality:eth_chainIdJSON-RPC returned0x2328(= 9000) — correct, read fromEVMConfiguratorSendRawTransactionvalidated againstb.chainID= 262144 — wrong, read fromapp.tomlWhen forge signed and submitted a transaction with chain ID 9000 (derived from
eth_chainId), the RPC backend'sSendRawTransactionrejected it:This happened before any tx ever reached the mempool. Every forge deployment command failed at submission, not at confirmation.
Fix
Added to
setup-genesis-auto.shimmediately afterpchaind init:EVM_CHAIN_ID="9000"is already defined inlocal-native/env.sh. The patch writes it intoapp.tomlso the RPC backend's chain ID matchesEVMConfigurator's chain ID.Summary Table
go buildfails immediatelygo.modreplace bumpcore.Messagevalue structnilinvalid in testsx/uexecutor/keeper/*.go, test fileBalance: *uint256.Intx/uregistry/keeper/genesis.gocontract.Caller()methodutils/precompile/exec.goBlockContext.Time: uint64tracing.Hooksreplacesvm.EVMLoggerethtypes.CreateBloomreplacesLogsBloomx/uexecutor/keeper/evm_hooks.goApplyMessage+internal boolx/uexecutor/keeper/*.go, interfaces, mocksNewKeeperparams changedapp/app.goNewAppModuleparams changedapp/app.goAccountKeeper3 new methodsapp/ante/ante_evm.go(new wrapper)app/precompiles.goGetEIP155ChainID().Uint64()Bech32StringFromHexAddressrenamedapp/app.goDefaultChainConfig(uint64)app/config.goMakeConfig(evmChainID uint64)app/app.goEthMsgsFromTendermintBlock3 returnsGetTxByEthHash3 returns../evmCallEVMWithDatagas meter overflow../evm/x/vm/keeper/call_evm.goGetTransactionReceipterror vs null../evm/rpc/backend/tx_info.gochain_configremoved fromParamslocal-native/scripts/setup-genesis-auto.shevm-chain-idinapp.tomlis authoritativelocal-native/scripts/setup-genesis-auto.shReferences
Changes
Testing
go test ./...Checklist