Skip to content

Commit f838ddf

Browse files
committed
scaffolded x/evmigration module, added wiring, fixed proto definitions, evmigration store key added to upgrade, Cosmos EVM upgrade to 0.6.0
1 parent 66b455c commit f838ddf

File tree

118 files changed

+24722
-355
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

118 files changed

+24722
-355
lines changed

.markdownlint.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"MD013": false,
3+
"MD060": false
4+
}

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Generated files land in `x/*/types/` as `*.pb.go`, `*_pb.gw.go`, `*.pulsar.go`.
9595

9696
Custom ante handler in `ante/delayed_claim_fee_decorator.go` - a fee decorator specific to claim transactions. Dual-route EVM ante handler in `app/evm/ante.go` routes Ethereum extension txs to the EVM path and all others to the Cosmos path.
9797

98-
### EVM Stack (Cosmos EVM v0.5.1)
98+
### EVM Stack (Cosmos EVM v0.6.0)
9999

100100
Four EVM modules wired in `app/evm.go`:
101101

Makefile.devnet

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.PHONY: devnet-build devnet-tests-build devnet-up devnet-reset devnet-up-detach devnet-down devnet-stop devnet-clean devnet-deploy-tar devnet-upgrade devnet-new devnet-start
22
.PHONY: devnet-build-default _check-devnet-default-cfg _devnet-select-default-genesis devnet-upgrade-binaries devnet-upgrade-binaries-default devnet-update-scripts
3+
.PHONY: devnet-evmigration-sync-bin devnet-evmigration-prepare devnet-evmigration-migrate devnet-evmigration-migrate-validator devnet-evmigration-cleanup
34

45
##### Devnet Makefile ########################################
56
#
@@ -40,16 +41,19 @@ DEFAULT_VALIDATORS_JSON := config/validators.json
4041
# Default genesis and claims files for devnet docker
4142
DEFAULT_GENESIS_FILE := devnet/default-config/devnet-genesis.json
4243
DEFAULT_GENESIS_EVM_FILE := devnet/default-config/devnet-genesis-evm.json
43-
DEFAULT_CLAIMS_FILE := claims.csv # relative to devnet
44+
DEFAULT_CLAIMS_FILE := devnet/default-config/claims.csv
4445
ORIG_GENESIS_FILE := devnet/default-config/devnet-genesis-orig.json
4546
EVM_CUTOVER_VERSION ?= v1.12.0
4647

4748
devnet-tests-build:
4849
@mkdir -p "${DEVNET_BIN_DIR_ABS}"
4950
@echo "Building devnet test binaries..."
50-
@cd devnet && \
51-
$(GO) test -c -o "${DEVNET_BIN_DIR_ABS}/tests_validator" ./tests/validator && \
52-
$(GO) test -c -o "${DEVNET_BIN_DIR_ABS}/tests_hermes" ./tests/hermes
51+
@echo " -> building tests_validator (${DEVNET_BIN_DIR_ABS}/tests_validator)"
52+
@cd devnet && $(GO) test -c -o "${DEVNET_BIN_DIR_ABS}/tests_validator" ./tests/validator
53+
@echo " -> building tests_hermes (${DEVNET_BIN_DIR_ABS}/tests_hermes)"
54+
@cd devnet && $(GO) test -c -o "${DEVNET_BIN_DIR_ABS}/tests_hermes" ./tests/hermes
55+
@echo " -> building tests_evmigration (${DEVNET_BIN_DIR_ABS}/tests_evmigration)"
56+
@cd devnet && $(GO) build -o "${DEVNET_BIN_DIR_ABS}/tests_evmigration" ./tests/evmigration
5357
@echo "Devnet test binaries built successfully"
5458

5559
devnet-build:
@@ -114,7 +118,7 @@ devnet-build-default: _check-devnet-default-cfg
114118
EXTERNAL_GENESIS_FILE="$$(realpath "$$GENESIS_FILE")" \
115119
EXTERNAL_CLAIMS_FILE="$$(realpath $(DEFAULT_CLAIMS_FILE))"
116120

117-
.PHONY: devnet-build-172 _check-devnet-172-cfg devnet-build-191 _check-devnet-191-cfg
121+
.PHONY: devnet-build-172 _check-devnet-172-cfg devnet-build-191 _check-devnet-191-cfg devnet-build-1110 _check-devnet-1110-cfg
118122
devnet-build-172:
119123
@$(MAKE) devnet-build \
120124
DEVNET_BUILD_LUMERA=0 \
@@ -137,6 +141,17 @@ _check-devnet-191-cfg:
137141
@[ -f "$$(realpath $(DEFAULT_GENESIS_FILE))" ] || (echo "Missing DEFAULT_GENESIS_FILE: $$(realpath $(DEFAULT_GENESIS_FILE))"; exit 1)
138142
@[ -f "$$(realpath $(DEFAULT_CLAIMS_FILE))" ] || (echo "Missing DEFAULT_CLAIMS_FILE: $$(realpath $(DEFAULT_CLAIMS_FILE))"; exit 1)
139143

144+
devnet-build-1110:
145+
@$(MAKE) devnet-build \
146+
DEVNET_BUILD_LUMERA=0 \
147+
DEVNET_BIN_DIR=devnet/bin-v1.11.0 \
148+
EXTERNAL_GENESIS_FILE="$$(realpath $(DEFAULT_GENESIS_FILE))" \
149+
EXTERNAL_CLAIMS_FILE="$$(realpath $(DEFAULT_CLAIMS_FILE))"
150+
151+
_check-devnet-1110-cfg:
152+
@[ -f "$$(realpath $(DEFAULT_GENESIS_FILE))" ] || (echo "Missing DEFAULT_GENESIS_FILE: $$(realpath $(DEFAULT_GENESIS_FILE))"; exit 1)
153+
@[ -f "$$(realpath $(DEFAULT_CLAIMS_FILE))" ] || (echo "Missing DEFAULT_CLAIMS_FILE: $$(realpath $(DEFAULT_CLAIMS_FILE))"; exit 1)
154+
140155
_check-devnet-default-cfg:
141156
@[ -f "$$(realpath $(DEFAULT_GENESIS_FILE))" ] || (echo "Missing DEFAULT_GENESIS_FILE: $$(realpath $(DEFAULT_GENESIS_FILE))"; exit 1)
142157
@[ -f "$$(realpath $(DEFAULT_GENESIS_EVM_FILE))" ] || (echo "Missing DEFAULT_GENESIS_EVM_FILE: $$(realpath $(DEFAULT_GENESIS_EVM_FILE))"; exit 1)
@@ -340,7 +355,8 @@ devnet-update-scripts:
340355
echo "No containers were updated. Ensure the devnet is running."; \
341356
fi
342357

343-
.PHONY: devnet-new-172 devnet-new-191 devnet-upgrade-180 devnet-upgrade-191 devnet-upgrade-1100 devnet-upgrade-1101
358+
.PHONY: devnet-new-172 devnet-new-191 devnet-new-1110 devnet-upgrade-180 devnet-upgrade-191
359+
.PHONY: devnet-upgrade-1100 devnet-upgrade-1101 devnet-upgrade-1110 devnet-upgrade-1120
344360

345361
devnet-upgrade-180:
346362
@cd devnet/scripts && ./upgrade.sh v1.8.0 auto-height ../bin-v1.8.0
@@ -352,7 +368,13 @@ devnet-upgrade-1100:
352368
@cd devnet/scripts && ./upgrade.sh v1.10.0 auto-height ../bin-v1.10.0
353369

354370
devnet-upgrade-1101:
355-
@cd devnet/scripts && ./upgrade.sh v1.10.1 auto-height ../bin
371+
@cd devnet/scripts && ./upgrade.sh v1.10.1 auto-height ../bin-v1.10.1
372+
373+
devnet-upgrade-1110:
374+
@cd devnet/scripts && ./upgrade.sh v1.11.0 auto-height ../bin-v1.11.0
375+
376+
devnet-upgrade-1120:
377+
@cd devnet/scripts && ./upgrade.sh v1.12.0 auto-height ../bin
356378

357379
devnet-new-172:
358380
$(MAKE) devnet-down
@@ -368,6 +390,13 @@ devnet-new-191:
368390
sleep 10
369391
$(MAKE) devnet-up
370392

393+
devnet-new-1110:
394+
$(MAKE) devnet-down
395+
$(MAKE) devnet-clean
396+
$(MAKE) devnet-build-1110
397+
sleep 10
398+
$(MAKE) devnet-up
399+
371400
devnet-deploy-tar:
372401
# Ensure required files exist from previous build
373402
@if [ ! -f "devnet/docker-compose.yml" ] || [ ! -f "devnet/bin/lumerad" ] || [ ! -f "devnet/bin/libwasmvm.x86_64.so" ]; then \
@@ -401,3 +430,91 @@ devnet-deploy-tar:
401430
rm devnet/external_genesis.json; \
402431
fi
403432
@echo "Created devnet-deploy.tar.gz with the required files."
433+
434+
##### EVM Migration test targets #############################
435+
#
436+
# Run the evmigration test tool inside each devnet validator container
437+
# via docker compose exec.
438+
#
439+
# Inside containers:
440+
# binary = /shared/release/tests_evmigration
441+
# lumerad = /shared/release/lumerad (symlinked to PATH or used via -bin)
442+
# home = /root/.lumera
443+
# RPC = tcp://localhost:26657 (each container exposes its own node)
444+
# accounts = /shared/evmigration-accounts-<validator_service>.json
445+
# (unique per validator to avoid cross-validator key/account reuse)
446+
# names = evm_test_<validator_tag>_<idx> / evm_testex_<validator_tag>_<idx>
447+
# (validator tag is auto-derived by tests_evmigration from local validator/funder key name)
448+
449+
EVMIGRATION_CHAIN_ID ?= lumera-devnet-1
450+
EVMIGRATION_NUM_ACCOUNTS ?= 5
451+
EVMIGRATION_NUM_EXTRA ?= 5
452+
EVMIGRATION_ACCOUNTS_PREFIX ?= /shared/evmigration-accounts
453+
454+
# Container-internal paths (the /shared volume is mounted from $(DEVNET_DIR)/shared).
455+
_EVMIGRATION_BIN_CONTAINER := /shared/release/tests_evmigration
456+
_EVMIGRATION_LUMERAD_CONTAINER := /shared/release/lumerad
457+
_EVMIGRATION_ACCOUNTS_CONTAINER_PREFIX := $(EVMIGRATION_ACCOUNTS_PREFIX)
458+
_EVMIGRATION_BIN_HOST := $(DEVNET_BIN_DIR_ABS)/tests_evmigration
459+
_EVMIGRATION_BIN_SHARED_HOST := $(SHARED_RELEASE_DIR)/tests_evmigration
460+
461+
# Discover running validator services from the compose file.
462+
_EVMIGRATION_SERVICES = $(shell docker compose -f $(COMPOSE_FILE) ps --services 2>/dev/null | grep '^supernova_validator_' | sort)
463+
464+
# Common flags passed to the binary inside the container.
465+
_evmigration_common_container = \
466+
-bin="$(_EVMIGRATION_LUMERAD_CONTAINER)" \
467+
-chain-id="$(EVMIGRATION_CHAIN_ID)" \
468+
-home="/root/.lumera" \
469+
-rpc="tcp://localhost:26657"
470+
471+
define _run_evmigration_in_containers
472+
@if [ ! -f "$(COMPOSE_FILE)" ]; then \
473+
echo "docker-compose.yml not found; run 'make devnet-build' first"; \
474+
exit 1; \
475+
fi; \
476+
services="$(_EVMIGRATION_SERVICES)"; \
477+
if [ -z "$$services" ]; then \
478+
echo "No running supernova_validator_* services found; is the devnet up?"; \
479+
exit 1; \
480+
fi; \
481+
for svc in $$services; do \
482+
accounts_path="$(_EVMIGRATION_ACCOUNTS_CONTAINER_PREFIX)-$${svc}.json"; \
483+
echo "=== $(1) on $${svc} ==="; \
484+
echo " accounts file: $${accounts_path}"; \
485+
docker compose -f $(COMPOSE_FILE) exec -T "$${svc}" \
486+
"$(_EVMIGRATION_BIN_CONTAINER)" \
487+
$(_evmigration_common_container) \
488+
-accounts="$${accounts_path}" \
489+
-mode="$(1)" \
490+
$(2) || exit 1; \
491+
done
492+
endef
493+
494+
devnet-evmigration-sync-bin:
495+
@src="$(_EVMIGRATION_BIN_HOST)"; \
496+
dst="$(_EVMIGRATION_BIN_SHARED_HOST)"; \
497+
if [ ! -f "$$src" ]; then \
498+
echo "Missing $$src; run 'make devnet-tests-build' first"; \
499+
exit 1; \
500+
fi; \
501+
mkdir -p "$$(dirname "$$dst")"; \
502+
if [ -f "$$dst" ] && cmp -s "$$src" "$$dst"; then \
503+
echo "tests_evmigration binary is up to date in shared/release"; \
504+
else \
505+
cp -f "$$src" "$$dst"; \
506+
chmod +x "$$dst"; \
507+
echo "synced tests_evmigration to $$dst"; \
508+
fi
509+
510+
devnet-evmigration-prepare: devnet-evmigration-sync-bin
511+
$(call _run_evmigration_in_containers,prepare,-num-accounts=$(EVMIGRATION_NUM_ACCOUNTS) -num-extra=$(EVMIGRATION_NUM_EXTRA))
512+
513+
devnet-evmigration-migrate: devnet-evmigration-sync-bin
514+
$(call _run_evmigration_in_containers,migrate)
515+
516+
devnet-evmigration-migrate-validator: devnet-evmigration-sync-bin
517+
$(call _run_evmigration_in_containers,migrate-validator)
518+
519+
devnet-evmigration-cleanup: devnet-evmigration-sync-bin
520+
$(call _run_evmigration_in_containers,cleanup)

ante/evmigration_fee_decorator.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package ante
2+
3+
import (
4+
sdk "github.com/cosmos/cosmos-sdk/types"
5+
6+
evmigrationtypes "github.com/LumeraProtocol/lumera/x/evmigration/types"
7+
)
8+
9+
// EVMigrationFeeDecorator must be placed BEFORE MinGasPriceDecorator
10+
// in the AnteHandler chain. If every message inside the tx is a migration
11+
// message (MsgClaimLegacyAccount or MsgMigrateValidator) we clear
12+
// min-gas-prices, allowing zero-fee txs. This solves the chicken-and-egg
13+
// problem where the new address has zero balance before migration.
14+
type EVMigrationFeeDecorator struct{}
15+
16+
var _ sdk.AnteDecorator = EVMigrationFeeDecorator{}
17+
18+
func (d EVMigrationFeeDecorator) AnteHandle(
19+
ctx sdk.Context,
20+
tx sdk.Tx,
21+
simulate bool,
22+
next sdk.AnteHandler,
23+
) (sdk.Context, error) {
24+
for _, msg := range tx.GetMsgs() {
25+
switch msg.(type) {
26+
case *evmigrationtypes.MsgClaimLegacyAccount,
27+
*evmigrationtypes.MsgMigrateValidator:
28+
continue
29+
default:
30+
// Non-migration message in tx — run normal fee checks.
31+
return next(ctx, tx, simulate)
32+
}
33+
}
34+
35+
// All messages are migration messages — waive the fee.
36+
ctx = ctx.WithMinGasPrices(nil)
37+
38+
return next(ctx, tx, simulate)
39+
}

app/app.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ import (
7575
"github.com/CosmWasm/wasmd/x/wasm"
7676
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
7777
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
78-
evmibctransferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper"
7978
ibcpacketforwardkeeper "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v10/packetforward/keeper"
8079
icacontrollerkeeper "github.com/cosmos/ibc-go/v10/modules/apps/27-interchain-accounts/controller/keeper"
8180
icahostkeeper "github.com/cosmos/ibc-go/v10/modules/apps/27-interchain-accounts/host/keeper"
@@ -102,6 +101,7 @@ import (
102101
actionmodulekeeper "github.com/LumeraProtocol/lumera/x/action/v1/keeper"
103102
auditmodulekeeper "github.com/LumeraProtocol/lumera/x/audit/v1/keeper"
104103
claimmodulekeeper "github.com/LumeraProtocol/lumera/x/claim/keeper"
104+
evmigrationmodulekeeper "github.com/LumeraProtocol/lumera/x/evmigration/keeper"
105105
lumeraidmodulekeeper "github.com/LumeraProtocol/lumera/x/lumeraid/keeper"
106106
sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"
107107
erc20keeper "github.com/cosmos/evm/x/erc20/keeper"
@@ -143,11 +143,15 @@ type App struct {
143143
pendingTxListeners []evmante.PendingTxListener
144144
evmMempool *evmmempool.ExperimentalEVMMempool
145145
// evmTxBroadcaster is used to asynchronously broadcast promoted EVM transactions from the mempool to the network without blocking CheckTx execution.
146-
evmTxBroadcaster *evmTxBroadcastDispatcher
146+
evmTxBroadcaster *evmTxBroadcastDispatcher
147147
// if true, the app will log additional information about mempool transaction broadcasts, which can be noisy but is useful for debugging mempool behavior.
148148
evmBroadcastDebug bool
149149
evmBroadcastLogger log.Logger
150150

151+
// jsonrpcRateLimitProxy is the optional rate-limiting reverse proxy for JSON-RPC.
152+
jsonrpcRateLimitProxy *http.Server
153+
jsonrpcRateLimitCleanupStop chan struct{}
154+
151155
// keepers
152156
// only keepers required by the app are exposed
153157
// the list of all modules is available in the app_config
@@ -172,7 +176,6 @@ type App struct {
172176
ICAControllerKeeper icacontrollerkeeper.Keeper
173177
ICAHostKeeper icahostkeeper.Keeper
174178
TransferKeeper ibctransferkeeper.Keeper
175-
EVMTransferKeeper evmibctransferkeeper.Keeper
176179

177180
// IBC middleware keepers
178181
PacketForwardKeeper *ibcpacketforwardkeeper.Keeper
@@ -191,6 +194,8 @@ type App struct {
191194
PreciseBankKeeper precisebankkeeper.Keeper
192195
EVMKeeper *evmkeeper.Keeper
193196
Erc20Keeper erc20keeper.Keeper
197+
EvmigrationKeeper evmigrationmodulekeeper.Keeper
198+
erc20PolicyWrapper *erc20PolicyKeeperWrapper
194199
// this line is used by starport scaffolding # stargate/app/keeperDeclaration
195200

196201
// simulation manager
@@ -297,6 +302,8 @@ func New(
297302
&app.SupernodeKeeper,
298303
&app.AuditKeeper,
299304
&app.ActionKeeper,
305+
&app.EvmigrationKeeper,
306+
300307
// this line is used by starport scaffolding # stargate/app/keeperDefinition
301308
); err != nil {
302309
panic(err)
@@ -320,14 +327,25 @@ func New(
320327

321328
// register EVM modules first — the ante handler (set during IBC/wasm registration)
322329
// depends on EVM keepers (FeeMarketKeeper, EVMKeeper).
323-
if err := app.registerEVMModules(); err != nil {
330+
if err := app.registerEVMModules(appOpts); err != nil {
324331
panic(err)
325332
}
326333

334+
// Create the ERC20 registration policy wrapper (governance-controlled IBC voucher
335+
// ERC20 auto-registration). Must be created before registerIBCModules, which wires
336+
// the wrapper into the IBC transfer middleware stacks.
337+
app.registerERC20Policy()
338+
327339
// register legacy modules (IBC, wasm)
328340
if err := app.registerIBCModules(appOpts, wasmOpts...); err != nil {
329341
panic(err)
330342
}
343+
// Inject IBC store keys into the EVM keeper's KV store map so the snapshot
344+
// multi-store used by StateDB includes "ibc" and "transfer" stores.
345+
// registerEVMModules captured kvStoreKeys() before IBC stores were registered;
346+
// adding them here fixes Bug #6 (ICS20 precompile panic).
347+
app.syncEVMStoreKeys()
348+
331349
// Enable Cosmos EVM static precompiles once IBC keepers are available.
332350
app.configureEVMStaticPrecompiles()
333351

@@ -349,6 +367,9 @@ func New(
349367
panic(err)
350368
}
351369

370+
// Start optional JSON-RPC rate-limiting reverse proxy.
371+
app.startJSONRPCRateLimitProxy(appOpts, logger)
372+
352373
// **** SETUP UPGRADES (upgrade handlers and store loaders) ****
353374
// This needs to be done after keepers are initialized but before loading state.
354375
app.setupUpgrades()
@@ -372,6 +393,10 @@ func New(
372393
panic(err)
373394
}
374395

396+
// Pre-populate the ERC20 registration policy with default allowlist
397+
// base denoms (uatom, uosmo, uusdc) on first genesis.
398+
app.initERC20PolicyDefaults(ctx)
399+
375400
return app.App.InitChainer(ctx, req)
376401
})
377402

@@ -405,7 +430,7 @@ func (app *App) setupUpgrades() {
405430
SupernodeKeeper: app.SupernodeKeeper,
406431
ParamsKeeper: &app.ParamsKeeper,
407432
ConsensusParamsKeeper: &app.ConsensusParamsKeeper,
408-
AuditKeeper: &app.AuditKeeper,
433+
AuditKeeper: &app.AuditKeeper,
409434
}
410435

411436
allUpgrades := upgrades.AllUpgrades(params)
@@ -570,7 +595,7 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig
570595
if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {
571596
panic(err)
572597
}
573-
apiSvr.Router.HandleFunc(appopenrpc.HTTPPath, appopenrpc.ServeHTTP).Methods(http.MethodGet, http.MethodHead)
598+
apiSvr.Router.HandleFunc(appopenrpc.HTTPPath, appopenrpc.ServeHTTP).Methods(http.MethodGet, http.MethodHead, http.MethodOptions)
574599

575600
// register app's OpenAPI routes.
576601
docs.RegisterOpenAPIService(Name, apiSvr.Router)

0 commit comments

Comments
 (0)