Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(app.go): Move keepers init, modules init away from app.go for simplicity #2402

Closed
wants to merge 2 commits into from

Conversation

udit-gulati
Copy link
Contributor

@udit-gulati udit-gulati commented Jan 27, 2024

Description

Refactors app/app.go to move following things into their own separate files:

  1. app/modules.go: modules init methods
  2. app/keepers/: keepers and keys init

Similar refactor done in other Cosmos-sdk chains:

  1. app.go cleanup cosmos/gaia#1580
  2. app.go refactor: Move keepers init, modules init and modularise upgrade handlers CosmosContracts/juno#366

Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • added appropriate labels to the PR
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • added a changelog entry to CHANGELOG.md
  • included comments for documenting Go code
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary
  • confirmed all CI checks have passed

Reviewers Checklist

All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.

I have...

  • confirmed the correct type prefix in the PR title
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic
  • reviewed API design and naming
  • reviewed documentation is accurate
  • reviewed tests and test coverage
  • manually tested (if applicable)

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive reorganization of the application structure, enhancing its functionality and modularity.
    • Added new keepers package to manage various aspects of the application, such as banking, staking, and governance.
    • Improved the method for retrieving staking store keys, optimizing data retrieval processes.
    • Expanded the application's module system, including the addition of new modules and initialization logic, to support extended functionalities.
  • Refactor

    • Significant refactor of the UmeeApp struct and its initialization function to accommodate new features and improve performance.
    • Updated the application's key management system for better efficiency and security.

@udit-gulati udit-gulati requested a review from a team as a code owner January 27, 2024 18:57
Copy link
Contributor

coderabbitai bot commented Jan 27, 2024

Walkthrough

The recent updates to the application introduce a comprehensive overhaul, focusing on enhancing functionality and reorganizing the system architecture. Key areas of change include the restructuring of the UmeeApp struct, the introduction of a new keepers package for improved data management, adjustments in module initialization and ordering, and refined methods for accessing and managing store keys. These modifications suggest a strategic enhancement aimed at boosting efficiency, scalability, and the overall capabilities of the application.

Changes

Files Change Summary
app/app.go Major restructuring, including imported packages, changes to UmeeApp struct, and New function.
app/export.go Updated method for retrieving the staking store key in prepForZeroHeightGenesis.
app/keepers/... Introduced keepers package with structs and initialization functions; added key management in keys.go.
app/modules.go Expanded module imports, maccPerms, ModuleBasics; added module setup and initialization functions.

🐇✨
In the realm of code, where logic does play,
A rabbit hopped in, with changes to say.
"With keepers and keys, modules anew,
Let's celebrate the update, with a carrot or two!"
🥕🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 4e72509 and 6d6951f.
Files selected for processing (5)
  • app/app.go (11 hunks)
  • app/export.go (1 hunks)
  • app/keepers/keepers.go (1 hunks)
  • app/keepers/keys.go (1 hunks)
  • app/modules.go (1 hunks)
Additional comments: 14
app/keepers/keys.go (3)
  • 44-61: The method GenerateKeys correctly initializes the keys, tkeys, and memKeys maps with the necessary store keys for the application's modules. This setup is crucial for the modular architecture and ensures that each module has its own dedicated storage space.
  • 63-73: The methods GetKVStoreKey, GetTransientStoreKey, and GetMemoryStoreKey provide a straightforward way to access the store keys maps. These methods enhance the code's modularity by allowing other parts of the application to retrieve store keys without directly accessing the maps.
  • 75-94: The methods GetKey, GetTKey, and GetMemKey are marked for testing purposes only, which is a good practice to isolate test utilities from production code. However, it's essential to ensure that these methods are not used in the application's business logic, as they bypass the encapsulation of the AppKeepers struct's internal state.
app/export.go (1)
  • 153-153: The change from ctx.KVStore(app.keys[stakingtypes.StoreKey]) to ctx.GetKey(stakingtypes.StoreKey) in the prepForZeroHeightGenesis method is a significant improvement. It leverages the newly introduced GetKey method from the AppKeepers struct, promoting better encapsulation and modularity. This change aligns with the overall goal of the PR to simplify and modularize the codebase.
app/app.go (3)
  • 18-18: The addition of the keepers package import and the appparams package import in app.go is a direct result of the refactoring effort to modularize the initialization of keepers and parameters. This change is consistent with the PR's objective to declutter app.go and improve the codebase's structure.
  • 156-169: The initialization of AppKeepers within the New function of UmeeApp demonstrates a clear separation of concerns, moving keeper initialization logic out of app.go. This approach enhances modularity and maintainability, aligning with best practices for large-scale application development.
  • 290-290: The method setAnteHandler in app.go has been updated to include the wasmConfig and wasmStoreKey parameters. This change likely reflects the integration of the wasm module into the application, necessitating adjustments to the ante handler setup to accommodate wasm-specific configurations. It's important to ensure that these changes are thoroughly tested, especially since the wasm module can significantly affect transaction processing.
app/modules.go (5)
  • 78-99: The maccPerms map has been expanded to include permissions for new modules such as leveragetypes.ModuleName, wasmtypes.ModuleName, incentive.ModuleName, and others. This setup is crucial for defining the access control and permissions for module accounts, aligning with the Cosmos SDK's design principles. It's important to ensure that the permissions assigned to each module account are carefully reviewed to prevent unauthorized access to funds or state manipulation.
  • 101-137: The ModuleBasics variable has been significantly expanded to include basic modules for the application, such as wasm, leverage, oracle, and others. This expansion is part of the refactor to modularize the application's initialization logic. It's crucial to ensure that all modules included here are correctly initialized and that their DefaultGenesis functions provide sensible defaults for the application's genesis state.
  • 141-185: The appModules function now includes a comprehensive list of application modules, reflecting the refactor's goal to modularize the application setup. This function is critical for setting up the application's module manager with all necessary modules. It's important to review the order of modules in this list, as it can affect the application's initialization and operation, especially regarding inter-module dependencies.
  • 188-227: The orderBeginBlockers function specifies the order in which modules' BeginBlocker methods are called at the start of each block. The order is crucial for ensuring that certain operations, such as fee distribution or slashing, occur in a specific sequence. This setup aligns with best practices for blockchain application development, where the execution order can significantly impact the application's state and security.
  • 230-249: The orderEndBlockers function specifies the order in which modules' EndBlocker methods are called at the end of each block. Similar to orderBeginBlockers, the order here is critical for the correct application logic execution. It's important to ensure that this order respects the dependencies and requirements of each module, especially for modules that must perform cleanup or finalization tasks at the block's end.
app/keepers/keepers.go (2)
  • 448-473: The initParamsKeeper function is a key part of the keeper initialization process, setting up the ParamsKeeper and its subspaces for various modules. This function is correctly setting up subspaces for each module, which is crucial for parameter management within those modules.

One minor suggestion is to ensure that all modules that require parameter management are included here. If any new modules are added to the application in the future, they should also have their subspaces initialized in this function. Additionally, consider adding comments to explain the purpose of parameter subspaces for those unfamiliar with the Cosmos SDK's parameter management system.

  • 476-497: Utility functions like GetSubspace, GetStakingKeeper, GetIBCKeeper, and GetScopedIBCKeeper are provided for testing purposes. These functions are straightforward and serve their intended purpose well. However, ensure that their usage is restricted to testing scenarios, as indicated by the comments, to maintain the encapsulation and integrity of the application's architecture in production environments.

Comment on lines +89 to +130
type AppKeepers struct {
// keys to access the substores
keys map[string]*storetypes.KVStoreKey
tkeys map[string]*storetypes.TransientStoreKey
memKeys map[string]*storetypes.MemoryStoreKey

// keepers
AccountKeeper authkeeper.AccountKeeper
BankKeeper bankkeeper.BaseKeeper
CapabilityKeeper *capabilitykeeper.Keeper
ConsensusParamsKeeper consensusparamskeeper.Keeper
StakingKeeper *stakingkeeper.Keeper
SlashingKeeper slashingkeeper.Keeper
MintKeeper mintkeeper.Keeper
DistrKeeper distrkeeper.Keeper
GovKeeper *govkeeper.Keeper
CrisisKeeper *crisiskeeper.Keeper
UpgradeKeeper *upgradekeeper.Keeper
ParamsKeeper paramskeeper.Keeper
AuthzKeeper authzkeeper.Keeper
EvidenceKeeper evidencekeeper.Keeper
FeeGrantKeeper feegrantkeeper.Keeper
GroupKeeper groupkeeper.Keeper
NFTKeeper nftkeeper.Keeper
WasmKeeper wasmkeeper.Keeper

IBCTransferKeeper ibctransferkeeper.Keeper
IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
PacketForwardKeeper *packetforwardkeeper.Keeper
ICAHostKeeper icahostkeeper.Keeper
LeverageKeeper leveragekeeper.Keeper
IncentiveKeeper incentivekeeper.Keeper
OracleKeeper oraclekeeper.Keeper
UIbcQuotaKeeperB uibcquota.KeeperBuilder
UGovKeeperB ugovkeeper.Builder
MetokenKeeperB metokenkeeper.Builder

// make scoped keepers public for testing purposes
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
ScopedTransferKeeper capabilitykeeper.ScopedKeeper
ScopedWasmKeeper capabilitykeeper.ScopedKeeper
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The AppKeepers struct is well-organized, grouping keys and keepers logically. This organization enhances readability and maintainability. However, consider documenting each keeper and key within the struct to explain their roles and interactions within the application, especially for new developers or external contributors unfamiliar with the Cosmos SDK or the specific application architecture.

Comment on lines +132 to +446
* ICS20 (Transfer) Middleware Stacks
* SendPacket, originates from the application to an IBC channel:
transferKeeper.SendPacket -> uibcquota.SendPacket -> channel.SendPacket
* RecvPacket, message that originates from an IBC channel and goes down to app, the flow is the other way
channel.RecvPacket -> uibcquota.OnRecvPacket -> forward.OnRecvPacket -> transfer.OnRecvPacket

* Note that the forward middleware is only integrated on the "receive" direction.
It can be safely skipped when sending.

* transfer stack contains (from top to bottom):
- Umee IBC Transfer
- IBC Rate Limit Middleware
- Packet Forward Middleware
**********/

quotaICS4 := uics20.NewICS4(appKeepers.IBCKeeper.ChannelKeeper, appKeepers.UIbcQuotaKeeperB)

// Create Transfer Keeper and pass IBCFeeKeeper as expected Channel and PortKeeper
// since fee middleware will wrap the IBCKeeper for underlying application.
appKeepers.IBCTransferKeeper = ibctransferkeeper.NewKeeper(
appCodec, appKeepers.keys[ibctransfertypes.StoreKey], appKeepers.GetSubspace(ibctransfertypes.ModuleName),
quotaICS4, // ISC4 Wrapper: fee IBC middleware
appKeepers.IBCKeeper.ChannelKeeper, &appKeepers.IBCKeeper.PortKeeper,
appKeepers.AccountKeeper, appKeepers.BankKeeper, appKeepers.ScopedTransferKeeper,
)

// Packet Forward Middleware
// Initialize packet forward middleware router
appKeepers.PacketForwardKeeper = packetforwardkeeper.NewKeeper(
appCodec,
appKeepers.keys[packetforwardtypes.StoreKey],
appKeepers.IBCTransferKeeper,
appKeepers.IBCKeeper.ChannelKeeper,
appKeepers.DistrKeeper,
appKeepers.BankKeeper,
quotaICS4, // ISC4 Wrapper: fee IBC middleware
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// Register the proposal types
// Deprecated: Avoid adding new handlers, instead use the new proposal flow
// by granting the governance module the right to execute the message.
// See: https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/gov/spec/01_concepts.md#proposal-messages
govRouter := govv1beta1.NewRouter()
govRouter.
AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(appKeepers.ParamsKeeper)).
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(appKeepers.UpgradeKeeper)).
AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(appKeepers.IBCKeeper.ClientKeeper))

govConfig := govtypes.DefaultConfig()
govConfig.MaxMetadataLen = 800
appKeepers.GovKeeper = govkeeper.NewKeeper(
appCodec, appKeepers.keys[govtypes.StoreKey], appKeepers.AccountKeeper, appKeepers.BankKeeper,
appKeepers.StakingKeeper, bApp.MsgServiceRouter(), govConfig,
govModuleAddr,
)

appKeepers.GovKeeper.SetLegacyRouter(govRouter)

var err error
wasmDir := filepath.Join(homePath, "wasm")
wasmCfg, err := wasm.ReadWasmConfig(appOpts)
if err != nil {
panic(fmt.Sprintf("error while reading wasm config: %s", err))
}

// Register umee custom plugin to wasm
wasmOpts = append(
uwasm.RegisterCustomPlugins(
appKeepers.LeverageKeeper, appKeepers.OracleKeeper, appKeepers.IncentiveKeeper,
appKeepers.MetokenKeeperB,
),
wasmOpts...,
)
// Register stargate queries
wasmOpts = append(wasmOpts, uwasm.RegisterStargateQueries(*bApp.GRPCQueryRouter(), appCodec)...)
appKeepers.WasmKeeper = wasmkeeper.NewKeeper(
appCodec,
appKeepers.keys[wasmtypes.StoreKey],
appKeepers.AccountKeeper,
appKeepers.BankKeeper,
appKeepers.StakingKeeper,
distrkeeper.NewQuerier(appKeepers.DistrKeeper),
appKeepers.IBCKeeper.ChannelKeeper,
appKeepers.IBCKeeper.ChannelKeeper,
&appKeepers.IBCKeeper.PortKeeper,
appKeepers.ScopedWasmKeeper, // capabilities
&appKeepers.IBCTransferKeeper, // ICS20TransferPortSource
bApp.MsgServiceRouter(),
nil,
wasmDir,
wasmCfg,
wasmCapabilities,
govModuleAddr,
wasmOpts...,
)

return appKeepers
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The NewAppKeepers function is comprehensive, covering the initialization of a wide range of keepers. Each keeper initialization is done methodically, ensuring that dependencies are correctly passed and configured. This function is central to the application's architecture, as it sets up the core components that manage state and interactions within the blockchain application.

However, there are a few areas for improvement:

  1. Error Handling: The function panics if it encounters an error, e.g., when reading the wasm config (lines 410-411). Consider handling errors more gracefully to enhance the robustness of the application. For critical errors that justify terminating the application, ensure that the error messages are clear and provide enough context to diagnose the issue.
  2. Documentation: Given the complexity and importance of this function, adding detailed comments explaining the purpose and effect of initializing each keeper would be beneficial. This documentation can aid in understanding the application's architecture and the role of each component within it.

Copy link

codecov bot commented Jan 27, 2024

Codecov Report

Attention: 173 lines in your changes are missing coverage. Please review.

Comparison is base (7f05ad4) 75.38% compared to head (6d6951f) 68.45%.
Report is 356 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2402      +/-   ##
==========================================
- Coverage   75.38%   68.45%   -6.94%     
==========================================
  Files         100      180      +80     
  Lines        8025    13362    +5337     
==========================================
+ Hits         6050     9147    +3097     
- Misses       1589     3606    +2017     
- Partials      386      609     +223     
Files Coverage Δ
ante/ante.go 66.66% <100.00%> (+18.45%) ⬆️
ante/fee.go 80.00% <100.00%> (+1.64%) ⬆️
ante/spam_prevention.go 75.92% <ø> (ø)
app/inflation/inflation.go 100.00% <100.00%> (ø)
app/upgradev3/migrations.go 84.21% <ø> (+5.94%) ⬆️
sdkclient/tx/sign.go 0.00% <ø> (ø)
util/coin/coin.go 11.11% <ø> (ø)
util/coin/dec.go 60.00% <ø> (ø)
util/coin/fixtures.go 20.00% <ø> (ø)
util/coin/utoken.go 100.00% <ø> (ø)
... and 45 more

... and 116 files with indirect coverage changes

@robert-zaremba
Copy link
Member

In the past I was thinking to do a similar setup. Osmosis has it in their repo.
However, after thinking a bit more I decided to stick with a "canonical" one (same as in the reference cosmos-sdk and IBC). This way it's easier to compare and make sure we don't miss anything.

In the future we are going to use deepinject, so most of this code won't be needed.

@gsk967 do you have thoughts?

@robert-zaremba
Copy link
Member

Closing now, but we can reconsider later once we will be closer with the SDK v0.50 migration (it's already in early draft)

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