Skip to content

chore(upgrade/v1.12.0): persist post-1.11.1 defaults and anchor Everlight clock#131

Open
mateeullahmalik wants to merge 1 commit intomasterfrom
chore/v1.12.0-upgrade-handler-completeness
Open

chore(upgrade/v1.12.0): persist post-1.11.1 defaults and anchor Everlight clock#131
mateeullahmalik wants to merge 1 commit intomasterfrom
chore/v1.12.0-upgrade-handler-completeness

Conversation

@mateeullahmalik
Copy link
Copy Markdown
Contributor

What & Why

The v1.12.0 upgrade handler previously ran module migrations only. Several PRs merged after v1.11.1-hotfix introduced new params and per-chain anchors that were not persisted at activation:

PR Module What landed Persisted by old handler?
#103 (LEP-5) x/action SvcChallengeCount, SvcMinChunksForChallenge ❌ blob keeps zero values
#113 (Everlight + LEP-4) x/supernode RewardDistribution{...}, full LEP-4 metrics block, new state keys (LastDistributionHeight, TotalDistributed, SNDistState), module-account perms now Minter+Burner+Staking ❌ blob zeros; clock not anchored; perms stale
#117 (LEP-6) x/audit StorageTruth* params block; ConsensusVersion 1→2 with registered migration ✅ migration covers KeepLastEpochEntries; ❌ enforcement mode not explicitly burned

Symptoms without this PR:

  • lumerad q action params and lumerad q supernode params return zeros on the new fields until next governance write.
  • Everlight first payout fires on the block immediately after the upgrade height because lastDistHeight=0 and currentHeight - 0 ≥ PaymentPeriodBlocks for any chain past 100,800 blocks — almost certainly not the intended activation policy.
  • Supernode ModuleAccount may persist with pre-Everlight perms until first interaction.
  • LEP-6 enforcement mode would rely on WithDefaults promotion, which intentionally does NOT promote UNSPECIFIED to SHADOW.

Changes

app/upgrades/v1_12_0/upgrade.go — completed handler

  1. consensusparams.EnsurePresent (defensive, matches v1.10.1/v1.11.x pattern).
  2. RunMigrations (audit v1→v2 fires here; bumps KeepLastEpochEntries floor).
  3. ActionKeeper.SetParams(ctx, ActionKeeper.GetParams(ctx)) — burns LEP-5 defaults to disk via the new WithDefaults path.
  4. SupernodeKeeper.SetParams(ctx, GetParams(ctx).WithDefaults()) — burns Everlight + LEP-4 defaults.
  5. SupernodeKeeper.SetLastDistributionHeight(ctx, ctx.BlockHeight()) — anchors Everlight clock at upgrade height. First payout fires one PaymentPeriodBlocks after upgrade, not on the next block.
  6. SupernodeKeeper.EnsureModuleAccount(ctx) — refreshes ModuleAccount with Minter+Burner+Staking perms.
  7. Burns audit.StorageTruthEnforcementMode = SHADOW explicitly (matches v1.11.0's auditScEnabled = true precedent).

Activation-policy constants (with regression tests pinning them):

const everlightEnabled = true
const storageTruthEnforcementMode = audittypes.StorageTruthEnforcementMode_STORAGE_TRUTH_ENFORCEMENT_MODE_SHADOW

x/action/v1/types/params.go and keeper/params.go

  • Adds Params.WithDefaults() (sibling-asymmetry fix — supernode and audit already had this since v1.11.x).
  • keeper.GetParams applies WithDefaults() on read; keeper.SetParams on write.
  • Direct callers reading Params.SvcChallengeCount no longer see 0 post-upgrade. (Previously masked by the ad-hoc fallback in keeper.GetSVCParams.)

x/supernode/v1/types/expected_keepers.go (+ regenerated mock)

  • Adds EnsureModuleAccount(ctx sdk.Context) to the SupernodeKeeper interface so the upgrade handler can call it through appParams.AppUpgradeParams.SupernodeKeeper.
  • go generate re-ran cleanly on expected_keepers_mock.go.

What is intentionally NOT done

  • No ConsensusVersion bump for action or supernode. Both modules' changes are purely additive params with safe zero-default semantics; bumping would force a near-empty per-module migration with the same effect as the in-handler SetParams. Lumera precedent (this PR's behaviour) follows v1.11.1's audit min_disk_free_percent floor pattern.
  • No additional InitGenesis call for any module. Audit v1→v2 migration already covers everything; supernode/action InitGenesis already ran on v1.11.x.
  • No new StoreUpgrades.Added/Deleted: Everlight uses the existing supernode store; LEP-6 uses the existing audit store.

Risks

Risk Mitigation
SetParams on a module already at correct values is a wasted write Idempotent; tiny gas; happens once per upgrade
Anchoring lastDistHeight = upgradeHeight delays first payout This is the intended activation behaviour per discussion
EnsureModuleAccount no-ops if account already correct Safe by design (matches InitGenesis usage in PR #113)
WithDefaults on action params changes runtime semantics for callers reading Params directly Defaults match what keeper.GetSVCParams already returned via fallback; verified all SvcChallengeCount / SvcMinChunksForChallenge consumers

Rollback

Revert this commit and lumerad rollback. No store schema change, no migration replay required.

Tests

  • app/upgrades/v1_12_0/upgrade_test.go — pins activation constants (everlightEnabled, enforcement mode) plus existing semver / store-safety / handler-non-nil tests.
  • x/action/v1/types/params_with_defaults_test.go — new: WithDefaults fills zero SVC fields and preserves non-zero values.
  • go build ./...
  • go vet ./...
  • All unit tests in app/upgrades/..., x/action/..., x/supernode/..., x/audit/...
  • All tests/integration/{action,audit,bank,everlight,gov,staking,supernode,wasm} and tests/system/{action,audit,supernode,wasm}

Devnet rehearsal

Recommend a lumera-upgrade-rehearsal run v1.11.1 → v1.12.0 and v1.10.1 → v1.12.0 before mainnet — the handler is keeper-heavy and the existing app/upgrades/upgrades_test.go::TestSetupUpgradesAndHandlers smoke test cannot exercise it (skipped, same as v1.11.0/v1.11.1).

…ght clock

The v1.12.0 upgrade handler previously only ran module migrations. After
v1.11.1-hotfix several PRs landed that introduced new params and per-chain
anchors which were not persisted at activation:

- LEP-5 (#103, action): SvcChallengeCount, SvcMinChunksForChallenge.
- Everlight plus LEP-4 (#113, supernode): RewardDistribution,
  MetricsUpdateIntervalBlocks, MetricsGracePeriodBlocks,
  MetricsFreshnessMaxBlocks, MinSupernodeVersion, MinCpu/Mem/StorageGB,
  MaxCpu/Mem/StorageUsagePercent, RequiredOpenPorts. New state keys
  LastDistributionHeight / TotalDistributed / SNDistState. Module account
  permissions changed to Minter+Burner+Staking.
- LEP-6 (#117, audit): full StorageTruth params block plus ConsensusVersion
  bump 1 to 2 with registered v1 to v2 migration (covered by RunMigrations).

This commit:

1. Adds Params.WithDefaults() in x/action/v1/types and applies it inside
   keeper.GetParams and keeper.SetParams (sibling-asymmetry fix; supernode
   and audit already had this).

2. Rewrites app/upgrades/v1_12_0/upgrade.go to:
   - Run consensusparams.EnsurePresent (defensive).
   - Run module migrations (audit v1 to v2 fires here).
   - Persist action params via SetParams(GetParams) so LEP-5 defaults land
     in the on-disk blob (no ConsensusVersion bump; soft-compat path).
   - Persist supernode params with WithDefaults likewise (Everlight plus LEP-4).
   - Anchor SetLastDistributionHeight(ctx.BlockHeight()) so the first
     Everlight payout fires one PaymentPeriodBlocks AFTER upgrade height
     instead of on the very next block.
   - Call SupernodeKeeper.EnsureModuleAccount(ctx) so the supernode
     ModuleAccount carries the updated Minter+Burner+Staking permissions.
   - Burn StorageTruthEnforcementMode = SHADOW on audit params (LEP-6
     activation default; explicit so it does not depend on WithDefaults
     promoting UNSPECIFIED).

3. Adds EnsureModuleAccount to the SupernodeKeeper expected-keeper
   interface and regenerates the mock.

4. Adds activation-policy constants everlightEnabled (true) and
   storageTruthEnforcementMode (SHADOW) with regression tests pinning them.

No module ConsensusVersion is bumped: action and supernode changes are
purely additive params with safe defaults reachable via WithDefaults.
Audit v1 to v2 migration is unchanged and runs via RunMigrations.

go build ./..., go vet ./..., and unit, integration, and system tests in
tests/{integration,system}/* all pass.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Completes the v1.12.0 upgrade handler so that post-v1.11.1-hotfix additive defaults and activation-time anchors are persisted immediately at upgrade height (not deferred until the next governance write), and updates the action params read/write path to normalize LEP-5 SVC defaults.

Changes:

  • Extend the v1.12.0 upgrade handler to persist Action/Supernode/Audit defaults, anchor Everlight’s distribution clock, and refresh the Supernode module account.
  • Add Params.WithDefaults() to x/action and apply it on keeper param reads/writes, with unit tests.
  • Extend the SupernodeKeeper expected interface (and regenerated mocks) to expose EnsureModuleAccount for upgrade wiring.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
app/upgrades/v1_12_0/upgrade.go Persists default params at upgrade time; anchors Everlight last distribution height; ensures module account; sets audit enforcement mode.
app/upgrades/v1_12_0/upgrade_test.go Pins activation-policy constants via unit tests.
x/action/v1/types/params.go Adds Params.WithDefaults() for LEP-5 additive SVC fields.
x/action/v1/keeper/params.go Applies WithDefaults() on params read and write.
x/action/v1/types/params_with_defaults_test.go Tests WithDefaults() behavior for zero vs non-zero values.
x/supernode/v1/types/expected_keepers.go Adds EnsureModuleAccount to SupernodeKeeper interface.
x/supernode/v1/mocks/expected_keepers_mock.go Regenerated gomock outputs reflecting interface changes.

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

Comment on lines +105 to +121
// WithDefaults returns a copy of the params with any zero-value fields populated
// from module defaults. Older genesis blobs and on-chain params written before
// new fields existed (e.g. LEP-5 SVC params) read back as zero; reading via
// WithDefaults keeps behaviour consistent without requiring a ConsensusVersion
// bump for purely additive params with safe defaults.
//
// Note: WithDefaults does NOT call Validate. Callers that want strict
// 0-as-unset semantics (genesis init, MsgUpdateParams) should apply
// WithDefaults() before Validate().
func (p Params) WithDefaults() Params {
if p.SvcChallengeCount == 0 {
p.SvcChallengeCount = DefaultSVCChallengeCount
}
if p.SvcMinChunksForChallenge == 0 {
p.SvcMinChunksForChallenge = DefaultSVCMinChunksForChallenge
}
return p
Comment on lines +76 to +77
// All four keepers are required by this handler. Fail loudly on any
// wiring regression rather than nil-deref mid-upgrade.
@a-ok123
Copy link
Copy Markdown
Contributor

a-ok123 commented May 2, 2026

@roomote code review

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.

3 participants