Skip to content

fix: pass initialized GovKeeper to gov precompile instead of zero-value#115

Merged
AdriaCarrera merged 1 commit into
mainfrom
fix/gov-keeper-init-order
May 13, 2026
Merged

fix: pass initialized GovKeeper to gov precompile instead of zero-value#115
AdriaCarrera merged 1 commit into
mainfrom
fix/gov-keeper-init-order

Conversation

@kpitapeersyst

@kpitapeersyst kpitapeersyst commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

fix: pass initialized GovKeeper to gov precompile instead of zero-value

Motivation 💡

DefaultStaticPrecompiles was called during EvmKeeper construction with app.GovKeeper passed by value. At that point app.GovKeeper had not yet been assigned, so the gov precompile received a copy of the zero-value govkeeper.Keeper (nil store service, nil codec, nil router, etc.). Because WithGovPrecompile takes the address of its local copy to pass to NewMsgServerImpl and NewQueryServer, the precompile permanently held a pointer to that nil-field keeper even after app.GovKeeper was properly initialized later in NewApp.

Changes 🛠

  • Move app.GovKeeper initialization before the EvmKeeper construction in app/app.go, so DefaultStaticPrecompiles receives a fully initialized keeper.

Considerations 🤔

  • All dependencies of govkeeper.NewKeeper (AccountKeeper, BankKeeper, StakingKeeper, DistrKeeper, ParamsKeeper) are initialized well before the new position without circular dependency risk.

Summary by CodeRabbit

  • Refactor
    • Reorganized internal module initialization sequence to improve code structure and ensure proper dependency ordering.

Note: This release contains internal code restructuring with no user-facing changes or new functionality.

@coderabbitai

coderabbitai Bot commented Apr 24, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The gov module initialization logic in app/app.go is relocated earlier in the New function constructor. This reordering ensures app.GovKeeper is initialized before subsequent Ethermint and IBC keeper/module code that depends on it, consolidating the initialization into a single point.

Changes

Cohort / File(s) Summary
Gov Module Initialization Relocation
app/app.go
Moved gov keeper instantiation, router construction, and hooks setup to execute before Ethermint/IBC initialization logic that references app.GovKeeper. Consolidated duplicate initialization block by removing the later instance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 The gov code hops forward in line,
Dependencies now align just fine,
Moved up the chain with care and grace,
Order restored to its proper place! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: reordering GovKeeper initialization to ensure it's fully initialized before being passed to the gov precompile.
Description check ✅ Passed The PR description follows the required template with all main sections completed: Motivation clearly explains the bug, Changes describe the fix, and Considerations address dependency impacts.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gov-keeper-init-order

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
app/app.go (1)

505-516: Consider passing &app.GovKeeper (or changing the field to a pointer) for future-proofing.

app.GovKeeper is declared as a value type (govkeeper.Keeper, L228) and is passed by value on L513. The upstream DefaultStaticPrecompiles function accepts the gov keeper as a value parameter, which internally passes it to WithGovPrecompile—that method takes the address of the parameter, creating a pointer to a temporary copy rather than to app.GovKeeper itself. This PR makes that snapshot correct, but any future mutation of app.GovKeeper after this point (e.g., additional SetHooks, re-wiring of collections) would silently not be visible to the precompile, reintroducing a similar class of bug.

Contrast with &app.Erc20Keeper and &app.TransferKeeper on L510-511, which are also value-type fields but passed as pointers—a pattern that keeps the reference valid across later re-assignments to the struct field. Consider one of:

  1. Pass &app.GovKeeper here, mirroring the Erc20/Transfer pattern.
  2. Change the App.GovKeeper field type to *govkeeper.Keeper for consistency (note: this also affects L648 gov.NewAppModule(appCodec, &app.GovKeeper, ...)).

Non-blocking for this PR, but worth a follow-up to make the wiring robust by construction rather than by ordering discipline.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/app.go` around lines 505 - 516, The GovKeeper is being passed by value
into DefaultStaticPrecompiles causing WithGovPrecompile to take a pointer to a
temporary copy; to future-proof, pass the address of the app's keeper instead
(use &app.GovKeeper like &app.Erc20Keeper and &app.TransferKeeper) or change the
App.GovKeeper field to a pointer type (*govkeeper.Keeper) and update usages
(including gov.NewAppModule where &app.GovKeeper is passed) so the precompile
always holds a pointer to the actual App.GovKeeper rather than a snapshot.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/app.go`:
- Around line 505-516: The GovKeeper is being passed by value into
DefaultStaticPrecompiles causing WithGovPrecompile to take a pointer to a
temporary copy; to future-proof, pass the address of the app's keeper instead
(use &app.GovKeeper like &app.Erc20Keeper and &app.TransferKeeper) or change the
App.GovKeeper field to a pointer type (*govkeeper.Keeper) and update usages
(including gov.NewAppModule where &app.GovKeeper is passed) so the precompile
always holds a pointer to the actual App.GovKeeper rather than a snapshot.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 30b9b9bc-b7a1-4fba-a671-71434b4069c0

📥 Commits

Reviewing files that changed from the base of the PR and between 43c1c36 and 6511019.

📒 Files selected for processing (1)
  • app/app.go

@AdriaCarrera AdriaCarrera merged commit d679806 into main May 13, 2026
6 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.

2 participants