Skip to content

evmigration + upgrades: validator-migration scaling, correctness fixes, and state-driven v1.20.1 EVM bring-up#184

Merged
akobrin1 merged 30 commits into
masterfrom
fix-migrate-validator-scoped-iteration
Jul 6, 2026
Merged

evmigration + upgrades: validator-migration scaling, correctness fixes, and state-driven v1.20.1 EVM bring-up#184
akobrin1 merged 30 commits into
masterfrom
fix-migrate-validator-scoped-iteration

Conversation

@akobrin1

@akobrin1 akobrin1 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

This branch started as a validator-migration performance fix and has grown into the v1.20.1 hotfix for the EVM migration rollout. It bundles four workstreams:

  1. Validator-migration performance — make the hot path scale with the migrating validator's own footprint, not total chain state (the original scope).
  2. evmigration correctness fixes — unbonded-validator eligibility, action re-keying, delegation-stake units, redelegation replay determinism.
  3. State-driven v1.20.1 upgrade routing — a direct 1.12.0 → 1.20.1 one-hop performs the full EVM bring-up on any network; a chain that already ran v1.20.0 gets a no-op migration-only hotfix.
  4. Tooling / devnetchain-helper.sh --network defaults, devnet v1.20.1 wiring, uploader gRPC port, plus PR-review fixes and a dependabot merge.

1. Validator-migration performance

MigrateValidatorMigrateValidatorDelegations / MigrateValidatorDistribution re-keys a validator from its legacy to its new address (delegations, unbonding, redelegations, distribution state). The original code walked full-chain indexes and re-read the same records multiple times — costs that blow up for a large validator on a busy chain.

  • Scoped store iteration — replaces full-chain IterateValidatorHistoricalRewards / IterateValidatorSlashEvents / IterateRedelegations (O(total chain state)) with target-validator key-prefix reads via wired distribution/staking store handles. Falls back to the Iterate* path when the store service is unwired (mock unit tests), so behavior is identical there. TestMigrateValidatorScopedIteration_SimulatesGlobalStateImprovement models 25 unrelated validators × 20 records and asserts a ~215× reduction in KV keys touched (1507 → 7).
  • Eliminate the double-fetch of staking records — the MaxValidatorDelegations pre-check already reads delegations/unbondings/redelegations; V4 no longer re-reads them (they are threaded in).
  • O(1) historical-rewards reference count — all re-keyed delegations share one period, so the final refcount is deterministically 1 + len(delegations), written once instead of N+1 full-chain scans.
  • Deterministic redelegation replayredelegationsForValidator sorts the deduped store keys before returning, matching the IterateRedelegations fallback byte-for-byte, so InsertRedelegationQueue replay order can't diverge app hashes across nodes. Regression test: TestMigrateValidatorDelegations_RedelegationReplayIsDeterministic.

Live-measured impact and scaling analysis: test(evmigration): add validator-migration scaling test + benchmark + the benchmark results doc.

2. evmigration correctness fixes

  • Allow non-jailed BOND_STATUS_UNBONDED validators to migrate — only jailed or still-BOND_STATUS_UNBONDING validators are blocked (an unbonding validator still holds a live unbonding-validator-queue entry that re-keying would orphan). A validator that fell out of the active set on stake weight is now directly migratable. Estimate/rejection messages and the validator-migration guide updated to match.
  • Scope MigrateActions via the action secondary indexes instead of a full scan.
  • Store delegation stake as tokens, not shares during re-key.
  • Skip claim records in the evmigration devnet verify step (leftover legacy claim rows are expected).

3. State-driven v1.20.1 upgrade routing

  • Mainnet skips v1.20.0 and runs the EVM bring-up via v1.20.1; routing keys off the genesis-derived chain id (ctx.ChainID()), not the --chain-id flag default.
  • v1.20.1 is state-driven, not mainnet-only (app/upgrades/v1_20_1): the handler runs the full v1.20.0 EVM bring-up when the EVM module is absent from fromVM (never brought up) and is migration-only otherwise. This makes a direct 1.12.0 → 1.20.1 one-hop work on any network (e.g. a devnet rehearsal of the mainnet one-hop).
  • Add-only store loader (AddOnlyStoreLoader) mounts only the declared EVM store keys missing from committed state and never deletes or renames a store — the safe half of AdaptiveStoreLoader, so a store-registration regression can't wipe a live store on mainnet. Routed for v1.20.1 regardless of the adaptive-store-manager env flag.
  • Design: docs/design/v1_20_1-state-driven-evm-bringup-design.md.

4. Tooling / devnet / housekeeping

  • chain-helper.sh: --network devnet|testnet|mainnet endpoint defaults; LUMERA_* env values are treated as explicit and are not clobbered by --network; bats coverage.
  • devnet: devnet-upgrade-1200devnet-upgrade-1201 (+ devnet-evm-upgrade flow); binaries.json pins v1.20.0 and adds a v1.20.1 entry; uploader default gRPC port moved.
  • PR-review fixes (816c1d83): MigrationEstimate fails loud on a redelegation-count error instead of silently under-counting (which could flip WouldSucceed to true); env-vs---network precedence; loop-variable shadowing of the keeper receiver.
  • Dependency: merged master, picking up the golang.org/x/net dependabot bumps (chore(deps): bump golang.org/x/net from 0.51.0 to 0.55.0 in /tests/systemtests #185, chore(deps): bump golang.org/x/net from 0.52.0 to 0.55.0 #186).

Correctness & safety

  • Output-equivalent refcount: old path = reset-to-1 then +1×N = 1+N; new path writes 1+N directly.
  • Scoped == filtered: prefix reads return exactly the rows the client-side-filtered Iterate* returned; wired path used in production, Iterate* fallback covered by mock tests.
  • Add-only store safety: proven never to emit Deleted/Renamed, so it can only add stores.
  • Upgrade atomicity unchanged: a failed handler aborts before state commit, so store presence and fromVM presence stay consistent.

Testing

  • go test ./app/upgrades/... (incl. the mainnet full-bring-up integration test with -tags=test) — all pass.
  • go test ./x/evmigration/keeper/... — pass.
  • make lint — 0 issues.
  • go build ./... — clean.

akobrin1 and others added 3 commits July 2, 2026 13:04
…gration

Two hot-path optimizations for MigrateValidatorDelegations, layered on the
scoped-iteration work already on this branch:

- Thread the delegations/unbondings/redelegations already read by the
  MaxValidatorDelegations pre-check into MigrateValidatorDelegations rather
  than re-reading them. This removes a second O(N) scan of the same staking
  records (plus a second validator-scoped redelegation index scan) on the
  migration hot path, which dominated block time for validators with many
  delegations. Passing nil redelegations still triggers the internal scan so
  tests can exercise it directly.

- Replace the reset-to-1 + increment-per-delegation refcount pattern with a
  single setHistoricalRewardsReferenceCount write of base(1)+len(delegations).
  All re-keyed delegations share one historical-rewards period, so the count
  is deterministic. New validatorHistoricalReward does an O(1) keyed store.Get
  of a single (validator, period) row; adjustHistoricalRewardsReferenceCount
  now uses it too. Eliminates the N+1 full-chain IterateValidatorHistoricalRewards
  scans the old path incurred per migrated validator.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0836de5805

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread x/evmigration/keeper/migrate_validator_scoped.go Outdated
akobrin1 and others added 3 commits July 3, 2026 08:28
The wired redelegationsForValidator built its result by ranging a Go map, so
the order was process-dependent. MigrateValidatorDelegations replays that
slice via InsertRedelegationQueue, which appends to shared queue timeslices —
redelegations sharing a completion time could therefore commit in different
byte order on different nodes and diverge the app hash (chain halt).

Sort the deduped store keys before emitting. This is deterministic and
reproduces the store-key order the IterateRedelegations fallback already
yields, so wired and unwired paths agree.

Addresses the P1 raised in the Codex review of #184.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Locks in the fix for the map-iteration nondeterminism in
redelegationsForValidator: the scoped scan now emits redelegations in
store-key order, so MigrateValidatorDelegations replays them
deterministically across nodes. The test writes 12 redelegations, forces
the internal scoped scan (nil reds), and asserts the replay order matches
the canonical store-key order. A reverted fix (raw map range) fails this
essentially every run (12! possible orderings).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Address code-review findings on PR #184:
- Add the 12 validator-scoped-iteration tests to unit-evmigration.md and
  bump the EVMigration keeper count 124+ -> 136+ in tests.md, per the
  CLAUDE.md rule that new EVM tests be tracked in the test inventory.
- Correct the stakingStoreHandle comments in keeper.go: it is no longer
  used exclusively by DeleteValidatorRecordNoHooks. redelegationsForValidator
  now reads it for validator-scoped redelegation index scans (read/write).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@akobrin1 akobrin1 requested a review from a-ok123 July 3, 2026 13:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes the evmigration validator-migration hot path so its cost scales with the migrating validator’s own state (delegations, redelegations, distribution rows) rather than full-chain iteration, and updates related tooling/docs plus registers a migration-only v1.20.1 hotfix upgrade.

Changes:

  • Add validator-scoped KV iteration helpers for staking redelegations and distribution historical rewards/slash events, and use them in migration + migration-estimation query paths.
  • Reuse pre-fetched staking records during MigrateValidator (avoid redundant O(N) reads) and replace N+1 historical-rewards refcount updates with a single deterministic write.
  • Update chain-helper.sh to support --network endpoint defaults, switch devnet uploader default gRPC port to 15051, and register the v1.20.1 upgrade handler (no store changes).

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
x/evmigration/keeper/query.go Uses validator-scoped redelegation lookup in MigrationEstimate.
x/evmigration/keeper/query_test.go Adds coverage asserting scoped redelegation counting in estimate query.
x/evmigration/keeper/msg_server_migrate_validator.go Switches redelegation counting to scoped lookup and threads preloaded slices into V4.
x/evmigration/keeper/msg_server_migrate_validator_test.go Updates validator-migration tests for scoped redelegations + refcount single-write behavior.
x/evmigration/keeper/msg_server_claim_legacy_test.go Wires isolated staking store service in tests and adjusts V4 failure-path coverage.
x/evmigration/keeper/migrate_validator.go Changes MigrateValidatorDelegations signature to accept preloaded staking records; uses single refcount set.
x/evmigration/keeper/migrate_validator_scoped.go New scoped store iteration helpers for redelegations, historical rewards, and slash events.
x/evmigration/keeper/migrate_test.go Adds extensive unit coverage for scoped iteration, redelegation determinism, and refcount optimization.
x/evmigration/keeper/migrate_distribution.go Replaces Iterate-based historical-rewards lookup with keyed O(1) lookup helper.
x/evmigration/keeper/keeper.go Adds wiring for distribution KVStoreService handle and expands staking handle usage to scoped reads.
tests/scripts/chain-helper.bats Adds tests for network defaults / overrides behavior in chain-helper tooling.
scripts/chain-helper.sh Introduces --network flag and network endpoint defaults; raises default cap to 2500.
docs/evm-integration/user-guides/tune-guide.md Updates max_validator_delegations guidance to 2,500.
docs/evm-integration/user-guides/migration.md Adds guidance about using Keplr + MetaMask post-migration; minor edits.
docs/evm-integration/user-guides/main.md Adds a mainnet-readiness bullet about Keplr/MetaMask dual representation post-migration.
docs/evm-integration/testing/tests/unit-evmigration.md Documents new/expanded unit tests for the optimizations.
docs/evm-integration/testing/tests.md Updates aggregate unit test counts for evmigration keeper.
docs/evm-integration/evmigration/legacy-migration.md Updates max_validator_delegations default value to 2500.
docs/devnet/main.md Updates exposed ports list for devnet image (50051 → 15051).
docs/devnet/lumera-uploader.md Updates uploader default gRPC port to 15051 and related examples.
docs/devnet/configuration.md Updates devnet configuration docs for uploader gRPC port change.
devnet/scripts/lumera-uploader-setup.sh Changes uploader default gRPC port to 15051 and config handling.
devnet/generators/docker-compose_test.go Adds test ensuring default uploader gRPC port mapping is 15051.
devnet/generators/config.go Updates default uploader gRPC port constant to 15051.
devnet/dockerfile Updates EXPOSE ports (50051 → 15051).
devnet/config/validators.json Updates uploader gRPC port to 15051.
devnet/config/config.json Updates uploader gRPC port to 15051.
devnet/config/config-no-hermes.json Updates network-maker/uploader gRPC port to 15051.
app/upgrades/v1_20_1/upgrade.go Adds v1.20.1 migration-only upgrade handler.
app/upgrades/upgrades.go Registers v1.20.1 in upgrade names and setup routing.
app/upgrades/upgrades_test.go Adds test asserting v1.20.1 is migration-only (no store upgrades).
app/app.go Wires distribution KVStoreService into evmigration keeper post-build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread x/evmigration/keeper/query.go Outdated
Comment thread scripts/chain-helper.sh
Comment thread x/evmigration/keeper/migrate_validator_scoped.go
akobrin1 and others added 11 commits July 3, 2026 12:19
…no shadowing

Resolves three Copilot review comments on PR #184:

- query.go: MigrationEstimate now propagates a redelegationsForValidator
  error instead of swallowing it. A corrupt src/dst index would otherwise
  undercount redelegations, shrink totalRecords, and could flip WouldSucceed
  to true for a validator whose real footprint exceeds MaxValidatorDelegations.

- chain-helper.sh: LUMERA_* env values (documented as overrides) now count as
  explicitly set, so passing --network alongside them fills only the endpoints
  the caller left unset rather than clobbering the env values. Adds a bats test.

- migrate_validator_scoped.go: rename redelegation loop variables that shadowed
  the Keeper receiver `k`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MigrateActions — and MigrateValidatorActions, which delegates to it —
scanned the entire action store on every account/validator migration,
burning gas proportional to the global action count rather than the
address's own footprint. On testnet this drove ClaimLegacyAccount txs
to ~1.5B gas each; under a mainnet block gas cap they would be unminable.

Resolve the affected actions through the existing creator and supernode
secondary indexes instead, unioning the two result sets and deduping by
action ID so an action is re-keyed exactly once even when the legacy
address is both its creator and a supernode.

Adds ActionKeeper.GetActionsByCreator / GetActionsBySuperNode backed by
the index prefixes, mirroring the scoped-iteration approach PR #184
already applied to the staking and distribution steps.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DelegatorStartingInfo.Stake must hold tokens (TokensFromSharesTruncated),
matching the SDK's initializeDelegation. Both migration re-key paths wrote
raw shares. For any ever-slashed validator (exchange rate < 1, which passes
the only-currently-jailed pre-check), shares overstate the real stake, so the
next WithdrawDelegatorReward/undelegate/redelegate from any delegator panics
("calculated final stake greater than current stake") — permanently bricking
those operations for every affected delegator.

Fetch the target validator and convert shares -> tokens in both
MigrateValidatorDelegations (once, outside the loop — all delegations share the
re-keyed validator) and migrateActiveDelegations (per delegation, since each
targets a different third-party validator).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A validator that fell out of the active set purely on stake weight
(Unbonded, not jailed) was permanently deadlocked: MsgMigrateValidator
rejected both Unbonding and Unbonded, while MsgClaimLegacyAccount rejects
any validator operator. Such an operator could recover neither legacy
keys, funds, nor rewards, and had no economic path back across the
active-set threshold.

Narrow the guard to reject only Unbonding, whose live entry in the SDK
unbonding-validator queue (keyed by completion time -> operator address)
would be orphaned by Step V8's DeleteValidatorRecordNoHooks and halt the
chain at maturity, since the module's StakingKeeper interface has no
validator-queue methods. Unbonded is safe and is the recovery path: that
queue entry was already dequeued (the transition that makes it Unbonded),
so nothing is orphaned. MigrationEstimate now reports would_succeed=true
for Unbonded non-jailed. Jailed stays blocked (checked first; recovery is
unjail).

Also in this change:
- Remove MigrateClaim: claim records are no longer re-keyed during
  migration. The claim DB is frozen (claiming ended 2025-01-01) and kept
  for reference only; re-keying DestAddress was cosmetic (funds already
  moved) and scanning the ~18K-record store per migration was unbounded
  gas with no benefit. Drops the ClaimKeeper interface, keeper field, and
  depinject wiring.
- Docs: record Bug #27 (delegation stake stored as tokens, not shares)
  and the 2026-07-03 testnet gas calibration; update the migration guides
  and the evmigration unit/integration test-index docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a realistic testnet-scale scenario for MsgMigrateValidator (~6000
delegation/unbonding/redelegation records in the observed val1 mix,
seeded via the real StakingKeeper):

- TestMigrateValidatorAtScale: pipeline correctness gate (~1.8s) asserting
  full re-keying at scale; guards the PR #184 hot-path optimizations
  against scale-only regressions. No timing assertion, so it is
  deterministic and does not flake in CI.
- BenchmarkMigrateValidatorScaling: on-demand curve (1000/2000/4000/6000)
  measuring how cost scales; excluded from the pipeline by construction
  (go test runs no Benchmark* without -bench). Confirms linear
  ~38us/record scaling.

Seeding advances block time per unbonding/redelegation record so their
completion times land in distinct staking-queue buckets, matching a real
chain. Without this, all records share one completion-time bucket and the
migration's InsertUBDQueue / InsertRedelegationQueue re-serialize the whole
bucket per entry (O(N^2)) — a seeding artifact that would mask the true
linear per-record cost.

Widens four shared sign/msg test helpers from *testing.T to testing.TB so
both the Test and the Benchmark reuse them. Documents both in the EVM test
index.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Release notes for the migration-only hotfix hardening x/evmigration for
large validators and live-network conditions: validator/account migration
performance (scoped index reads, single-write refcount, secondary-index
action re-keying), correctness & safety fixes (tokens-not-shares stake,
Unbonded-validator recovery, claim-record removal, deterministic
redelegation replay), and the v1.20.1 upgrade handler. No store changes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lts + analysis

Adds the measured BenchmarkMigrateValidatorScaling results (1000/2000/4000/6000
records) and analysis to two places:

- Test index (integration-evmigration.md): a Representative results table plus a
  linear-scaling read (~38us/record, slope ~1.0) with the gas-meterless-harness
  caveat and a cross-link to the gas design doc.
- Gas design doc (2026-06-22-validator-migration-gas-design.md): a dated section
  noting the benchmark independently confirms the linear per-record scaling that
  the base + per_record*N formula assumes — the live devnet/testnet numbers were
  single-point and could not distinguish linear from super-linear. Includes the
  ns/op-vs-gas caveat and the completion-time-bucket O(N^2) worst case.

PR #184 description updated with the same table + analysis.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mainnet now skips the v1.20.0 upgrade entirely and performs the EVM store
additions + Lumera EVM param finalization through v1.20.1 instead, reusing
v1.20.0's StoreUpgrades and handler verbatim so everything v1.20.0 does is
guaranteed to run. Testnet and devnet (which already ran v1.20.0) keep it
there and treat v1.20.1 as a migration-only hotfix.

Mirrors the existing v1.8.0/v1.8.4 mainnet-skip precedent (setup-time
params.ChainID gating). Adds a behavioral test that boots the app on a
mainnet context and asserts v1.20.1 applies the Lumera EVM params and the
migration deadline.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@Bilaltanveer38 Bilaltanveer38 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a minor comment, some integration test comments are stale. Example: tests/integration/evmigration/migration_test.go still says the old validator row is “orphaned / left dangling”, but current V8 deletes it via DeleteValidatorRecordNoHooks. Not a behavior issue, but it should be corrected to avoid misleading future reviewers.

@mateeullahmalik mateeullahmalik requested review from Bilaltanveer38 and removed request for Bilaltanveer38 July 6, 2026 09:05
j-rafique
j-rafique previously approved these changes Jul 6, 2026
akobrin1 and others added 2 commits July 6, 2026 12:31
- Makefile.devnet: rename devnet-upgrade-1200 -> devnet-upgrade-1201 and
  point it (and the scripted devnet-evm-upgrade flow) at v1.20.1; drop the
  stale devnet-new-1111 target.
- binaries.json: pin v1.20.0 to its final tag (was -rc5) and add a v1.20.1
  entry (v1.20.1-rc1, bin-v1.20.1, supernode v2.6.0-rc1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
akobrin1 and others added 2 commits July 6, 2026 12:58
Design for making the v1.20.1 upgrade carry the EVM bring-up based on chain
state (fromVM + committed stores) rather than the IsMainnet chain-id branch,
so a direct 1.12.0 -> 1.20.1 one-hop works on any network. Add-only store
loader (no delete branch) + fromVM-gated handler.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Route the v1.20.1 EVM bring-up by chain STATE instead of the IsMainnet chain-id
branch, so a direct 1.12.0 -> 1.20.1 upgrade works on any network (e.g. a devnet
rehearsal of the mainnet one-hop), while remaining a no-op migration-only hotfix
on chains that already ran v1.20.0.

- New app/upgrades/v1_20_1 package: fromVM-gated handler. When the EVM module is
  absent from fromVM (EVM never brought up) it delegates to the full v1.20.0
  bring-up; otherwise it runs migrations only. evmAlreadyInitialized predicate is
  unit-tested.
- AddOnlyStoreLoader / computeAddOnlyStoreUpgrades: mount only the declared EVM
  store keys missing from committed state; never delete or rename. This is the
  safe half of AdaptiveStoreLoader (no Deleted branch), so a store-registration
  regression can never wipe a live store on mainnet.
- SetupUpgrades: v1.20.1 declares the EVM store set + the state-driven handler on
  every network (IsMainnet branch removed). StoreLoaderForUpgrade routes v1.20.1
  to the add-only loader regardless of the adaptive-store-manager env flag.
- Tests: add-only computation, add-only routing (adaptive and non-adaptive),
  handler predicate, and SetupUpgrades routing across mainnet/testnet/devnet.
  TestV1201MigrationOnlyOnNonMainnet (asserted StoreUpgrade==nil) replaced by
  TestV1201CarriesEVMBringupOnAllNetworks; the mainnet full-bring-up integration
  test still passes through the new handler.

Design: docs/design/v1_20_1-state-driven-evm-bringup-design.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@akobrin1 akobrin1 changed the title evmigration: optimize validator migration for large delegator sets evmigration + upgrades: validator-migration scaling, correctness fixes, and state-driven v1.20.1 EVM bring-up Jul 6, 2026
akobrin1 and others added 4 commits July 6, 2026 13:27
- AddOnlyStoreLoader fails closed if it cannot read committed store names,
  instead of falling back to a blind UpgradeStoreLoader that could re-add
  already-present EVM stores and halt an already-upgraded chain during load.
- v1.20.1 handler bases its decision on ALL four EVM bring-up modules, not just
  evm: none present -> full bring-up, all present -> migration-only hotfix, and
  partial state -> hard error (an impossible state that must not silently skip
  EVM param finalization).
- Add a real rootmulti store-loader test: commit a pre-EVM store set, run
  AddOnlyStoreLoader, and assert the EVM stores get mounted while existing data
  survives (plus a no-op-when-present case) — exercising the loader through a
  genuine committed multistore rather than only the pure diff.
- Handler tests updated for the all-present hotfix path and the partial-state
  fail-closed path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The devnet-evm-upgrade recipe still pinned EVM_VERSION=v1.20.0; bump it to
v1.20.1 to match the renamed devnet-upgrade-1201 target and the v1.20.1
release wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dependabot merge (#185, #186) re-tidied the root and tests/systemtests
modules but not the nested devnet module. go mod tidy in devnet re-resolves the
shared golang.org/x/* deps (crypto 0.49->0.51, net 0.52->0.55, sys, term, text)
to the same versions now in root, carrying the x/net security bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two comments in migration_test.go still described the old validator record as
"orphaned / left dangling" with the rationale that RemoveValidator can't run on
a bonded validator. V8 now deletes the old record via DeleteValidatorRecordNoHooks
(a raw KV delete that avoids those hooks), so the record is gone, not orphaned.
Comment-only; matches the existing V8 phrasing already used elsewhere in the file.
Raised in PR review (Bilaltanveer38).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@akobrin1 akobrin1 merged commit 4ce27cf into master Jul 6, 2026
24 checks passed
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.

5 participants