Skip to content

fix(x/feegrant): migrate fee allowance queue entries stored with an empty value - #26944

Open
dpdanpittman wants to merge 3 commits into
cosmos:mainfrom
dpdanpittman:fix/feegrant-empty-queue-values
Open

dpdanpittman wants to merge 3 commits into
cosmos:mainfrom
dpdanpittman:fix/feegrant-empty-queue-values

Conversation

@dpdanpittman

Copy link
Copy Markdown
Contributor

Description

x/feegrant reads its fee allowance expiry queue (FeeAllowanceQueue, prefix 0x01) with collections.BoolValue, which cannot decode an empty value. Two writers store queue entries with an empty value:

  • the standalone cosmossdk.io/x/feegrant module (v0.1.x, v0.2.0), which chains ran before v0.55;
  • the in-tree v1 → v2 store migration (migrations/v2/store.go sets []byte{}).

The consensus version stayed at 2 and there is no migration, so a chain that upgrades to v0.55 with grants created before it keeps those entries. When the first one expires, RemoveExpiredAllowances fails in the EndBlocker with collections: encoding error: wanted size to be at least 1 on every validator, and the chain halts.

This halted XION's testnet (xion-testnet-2) at height 19286361 on 2026-10-29. XION fixed it in its own upgrade handler (burnt-labs/xion v33.0.1); this PR moves that fix into the module so every chain gets it from RunMigrations.

Changes

  • New v2 → v3 store migration (x/feegrant/migrations/v3): rewrites every queue entry with an empty value to the BoolValue encoding of true. Entries that already have a value, and the allowance prefix, are left unchanged, so it is idempotent. Keys are collected before any write.
  • Wiring: Migrator.Migrate2to3, registered from version 2; ConsensusVersion goes from 2 to 3.
  • v1 → v2 migration: now writes an encoded true instead of an empty value.
  • Docs: the queue comments in key.go, migrations/v2/keys.go and the module README described the empty value; they now say BoolValue (true). CHANGELOG (State Machine Breaking) and an UPGRADING.md section, following fix(enterprise/poa): truncate fee shares so allocations never exceed the balance #26875.

Tests

  • keeper/migrations_test.go: seeds a grant plus an empty-valued queue entry, advances block time past expiry, and shows RemoveExpiredAllowances fails with ErrEncoding before the migration and removes both the grant and the queue entry after it.
  • module/module_test.go: runs the real RunMigrations from feegrant version 2 through the module's registered migrations, so the registration and the version bump are covered too.
  • migrations/v3/store_test.go: empty values rewritten, non-empty and other-prefix entries untouched, idempotent on a second run, empty store.
  • migrations/v2/store_test.go: entries written by the v1 → v2 migration now decode, and expire cleanly.

Each test fails with the corresponding part of the fix reverted. go test ./x/feegrant/..., the simapp migration tests and golangci-lint (v2.15.0, repo config) pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RGzi5xYvf1h3LR2v7cHMcQ

…mpty value

The keeper reads the fee allowance expiry queue with collections.BoolValue,
which cannot decode an empty value. The standalone cosmossdk.io/x/feegrant
module and the in-tree v1 -> v2 store migration both wrote queue entries
with an empty value, so on chains that upgraded to v0.55 with such entries
RemoveExpiredAllowances fails in the EndBlocker once the first one expires,
halting the chain.

Add a v2 -> v3 store migration that rewrites every empty-valued queue entry
to the BoolValue encoding of true, bump ConsensusVersion to 3, and make the
v1 -> v2 migration write the encoded value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RGzi5xYvf1h3LR2v7cHMcQ
@dhfang

dhfang commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

@greptile review

@greptile-apps

greptile-apps Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Repairs legacy fee allowance queue entries so expired grants can be removed without an encoding error.

  • Feegrant repairs old expiry-queue entries before they are pruned.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[RunMigrations] --> B{Stored feegrant version}
  B -->|1| C[1 → 2: create queue entries with encoded true]
  B -->|2| D[2 → 3: find empty queue values]
  C --> D
  D --> E[Close iterator]
  E --> F[Rewrite collected entries with encoded true]
  F --> G[Record version 3]
Loading

Reviews (1) · Last reviewed commit: "docs(x/feegrant): link the changelog and..." · Reviewed by Greptile

@dpdanpittman

Copy link
Copy Markdown
Contributor Author

@dhfang thanks for kicking off the Greptile pass. It came back clean, and I've updated the branch against main. Could you or another maintainer take a look when you have a minute? Happy to adjust anything.

This branch has not been deployed

No deployments
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.

2 participants