Skip to content

refactor(server/v2): eager config loading#22267

Merged
julienrbrt merged 55 commits into
mainfrom
kocu/config-rf
Oct 29, 2024
Merged

refactor(server/v2): eager config loading#22267
julienrbrt merged 55 commits into
mainfrom
kocu/config-rf

Conversation

@kocubinski
Copy link
Copy Markdown
Contributor

@kocubinski kocubinski commented Oct 15, 2024

Description

Fixes: #22268

This PR refactors config parsing for server/v2. A long standing point of confusion since the adoption of depinject has been a pattern where dependency injection happens twice during application start up. After some analysis this seemed to only be necessary due to late binding of config, somewhat of an outgrowth of cobras command architecture.

Config parsing has been pulled up as early possible into NewRootCmd. To facilitate this initRootCmd is called twice; once to initialize the CLI skeleton so that flags may be parsed (then combined with viper app.toml parsing), and then a second time immediately after DI occurs. The first invocation requires no DI outputs, the second does. A fully realized configuration blob is available immediately after the first initRootCmd invocation, and is then supplied to DI and ServerComponent constructors.

Another new feature of this design is introspection on the subcommand (e.g. start, export genesis) in order to determine if a client command (i.e. no SimApp needed) or a server command has been invoked. These two cases use different composition roots for injection. As a consequence of this the function closures (which provided late bound config) for newApp appExport are no longer needed; the server can be passed directly to the command handler.

I believe this paves the way for a minimal root command helper so that even more boilerplate may be kept out of simapp/v2 and pushed down into server/v2, which would be a good follow up issue. The code seems much easier to follow now too since there is much less indirection and circular references which were previously resolved by late bound function closures.


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, you can find examples of the prefixes below:
  • confirmed ! in the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • reviewed "Files changed" and left comments if necessary
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • updated the relevant documentation or specification, including comments for documenting Go code
  • 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.

Please see Pull Request Reviewer section in the contributing guide for more information on how to review a pull request.

I have...

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

Summary by CodeRabbit

  • New Features

    • Introduced a structured approach for managing module configurations dynamically, enhancing modularity.
    • Added a new CommandFactory to streamline command creation and configuration handling.
  • Bug Fixes

    • Improved error handling during server initialization and configuration processes.
  • Refactor

    • Updated various command and server initialization methods for better clarity and maintainability.
    • Simplified the logging configuration process by changing the parameter type to server.ConfigMap.
  • Documentation

    • Enhanced comments and clarity in configuration-related functions.
  • Chores

    • Updated code ownership in the .github/CODEOWNERS file.

Comment thread simapp/v2/simdv2/cmd/root_di.go Fixed
Comment thread simapp/v2/simdv2/cmd/root_di.go Fixed
Comment thread simapp/v2/simdv2/cmd/root_di.go Fixed
Comment thread simapp/v2/simdv2/cmd/root_di.go Fixed
Comment thread server/v2/store/snapshot.go Fixed
Comment thread simapp/v2/simdv2/cmd/root_di.go Fixed
Comment thread simapp/v2/app_di.go Outdated
Comment thread simapp/v2/app_di.go Outdated
Comment thread simapp/v2/simdv2/cmd/root_di.go Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 23, 2024

📝 Walkthrough

Walkthrough

The changes introduced in this pull request encompass a comprehensive restructuring of the server and runtime modules to enhance configuration management and modularity. New types, functions, and methods are added to facilitate dynamic configuration of modules, allowing for improved initialization and error handling. The modifications also include the removal of certain methods and the introduction of new interfaces to streamline command handling and server setup, while ensuring that existing functionalities remain intact.

Changes

File Change Summary
runtime/config.go Added ModuleConfigMaps type, ModuleConfigMapsInput struct, and functions for managing module configurations.
runtime/module.go Integrated new config functions into the init function.
runtime/v2/builder.go Added storeConfig field to AppBuilder struct and updated Build method for error handling.
runtime/v2/config.go Introduced GlobalConfig type and functions for module configuration management.
runtime/v2/module.go Updated ProvideAppBuilder and init functions to include new config management functions.
server/v2/api/grpc/server.go Modified New and Init methods to accept new parameters for enhanced configuration handling.
server/v2/api/grpcgateway/server.go Removed Init method and updated New function for improved configuration management.
server/v2/api/rest/server.go Updated New and Init methods to include new parameters for configuration.
server/v2/api/rest/server_test.go Adjusted server instantiation in tests to reflect new initialization methods.
server/v2/api/telemetry/server.go Updated New function to include configuration and logger parameters.
server/v2/api/grpc/server.go Updated New function to accept new parameters for server initialization.
server/v2/api/store/server.go Updated New function to include configuration handling and removed Init method.
server/v2/store/snapshot.go Updated RestoreSnapshotCmd to simplify its interface and enhance error handling.
simapp/app_di.go Improved readability of AppConfig function.
simapp/v2/app_config.go Renamed appConfig variable to ModuleConfig for clarity.
simapp/v2/app_di.go Modified NewSimApp function to accept new parameters and improve error handling.
simapp/v2/simdv2/cmd/commands.go Introduced CommandDependencies struct for better command initialization.
simapp/v2/simdv2/cmd/root_di.go Replaced multiple command creation functions with a single NewRootCmd function.
simapp/v2/simdv2/cmd/testnet.go Enhanced server initialization for testnet environment.
simapp/v2/simdv2/cmd/testnet_test.go Updated test functions to reflect new command initialization methods.
x/genutil/client/cli/collect.go Updated CollectGenTxsCmd function signature for flexible validation handling.
x/genutil/v2/cli/commands.go Introduced ExportableApp interface for improved application state handling.
x/genutil/v2/cli/export.go Updated ExportCmd function to use ExportableApp interface.
x/upgrade/depinject.go Enhanced configuration handling in ProvideModule function.
x/validate/depinject.go Updated configuration management in validate package.
runtime/v2/app.go Renamed GetQueryHandlers method to QueryHandlers.
simapp/v2/simdv2/cmd/depinject.go Introduced ProvideClientContext function for dependency injection.
server/v2/logger.go Updated NewLogger function to use server.ConfigMap instead of *viper.Viper.
server/v2/util.go Removed error handling from context-setting functions.
x/genutil/v2/types.go Removed AppExporter type definition.
.github/CODEOWNERS Updated code ownership for /server/v2/ directory.
server/v2/command_factory.go Introduced CommandFactory struct for command creation and configuration.

Assessment against linked issues

Objective Addressed Explanation
Fix panic during snapshot restore (#22268)

Possibly related PRs

Suggested labels

C:server/v2, stf

Suggested reviewers

  • julienrbrt
  • hieuvubk
  • tac0turtle
  • facundomedica

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>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • 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 testing code 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 gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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 using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
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.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (8)
scripts/init-simapp-v2.sh (4)

Line range hint 4-7: Enhance error handling for binary validation.

The current binary validation could be more robust by checking if the found binary is executable.

Consider this enhanced validation:

-SIMD_BIN=${SIMD_BIN:=$(which simdv2 2>/dev/null)}
-
-if [ -z "$SIMD_BIN" ]; then echo "SIMD_BIN is not set. Make sure to run 'COSMOS_BUILD_OPTIONS=v2 make install' before"; exit 1; fi
-echo "using $SIMD_BIN"
+SIMD_BIN=${SIMD_BIN:=$(which simdv2 2>/dev/null)}
+
+if [ -z "$SIMD_BIN" ]; then
+    echo "Error: SIMD_BIN is not set. Make sure to run 'COSMOS_BUILD_OPTIONS=v2 make install' before"
+    exit 1
+elif [ ! -x "$SIMD_BIN" ]; then
+    echo "Error: $SIMD_BIN is not executable"
+    exit 1
+fi
+echo "Using binary: $SIMD_BIN"

Line range hint 8-13: Add error handling for configuration commands.

The configuration commands should verify their success to ensure proper initialization.

Consider wrapping the commands in a function with error checking:

+set -e  # Exit on error
+
+configure_client() {
+    local cmd=$1
+    local output
+    
+    if ! output=$($cmd); then
+        echo "Error executing: $cmd"
+        echo "Output: $output"
+        exit 1
+    fi
+}
+
 SIMD_HOME=$($SIMD_BIN config home)
 if [ -d "$SIMD_HOME" ]; then rm -rv $SIMD_HOME; fi
-$SIMD_BIN config set client chain-id simapp-v2-chain
-$SIMD_BIN config set client keyring-backend test
-$SIMD_BIN config set client keyring-default-keyname alice
-$SIMD_BIN config set app rest.enable true
+configure_client "$SIMD_BIN config set client chain-id simapp-v2-chain"
+configure_client "$SIMD_BIN config set client keyring-backend test"
+configure_client "$SIMD_BIN config set client keyring-default-keyname alice"
+configure_client "$SIMD_BIN config set app rest.enable true"

Line range hint 17-20: Improve genesis file modification safety.

The current jq modifications could be safer by validating the JSON structure and backing up the genesis file.

Consider this safer approach:

+# Backup genesis file
+cp "$SIMD_HOME/config/genesis.json" "$SIMD_HOME/config/genesis.json.backup"
+
+modify_genesis() {
+    local path=$1
+    local value=$2
+    local temp_file
+    
+    # Create temporary file in the same directory
+    temp_file=$(mktemp "$SIMD_HOME/config/.genesis.tmp.XXXXXX")
+    
+    if ! jq --arg value "$value" "$path = \$value" "$SIMD_HOME/config/genesis.json" > "$temp_file"; then
+        echo "Error: Failed to modify genesis file at path $path"
+        rm -f "$temp_file"
+        exit 1
+    fi
+    
+    mv "$temp_file" "$SIMD_HOME/config/genesis.json"
+}
+
-jq '.app_state.gov.params.voting_period = "600s"' $SIMD_HOME/config/genesis.json > temp.json && mv temp.json $SIMD_HOME/config/genesis.json
-jq '.app_state.gov.params.expedited_voting_period = "300s"' $SIMD_HOME/config/genesis.json > temp.json && mv temp.json $SIMD_HOME/config/genesis.json
-jq '.app_state.mint.minter.inflation = "0.300000000000000000"' $SIMD_HOME/config/genesis.json > temp.json && mv temp.json $SIMD_HOME/config/genesis.json
+modify_genesis '.app_state.gov.params.voting_period' "600s"
+modify_genesis '.app_state.gov.params.expedited_voting_period' "300s"
+modify_genesis '.app_state.mint.minter.inflation' "0.300000000000000000"

Add error handling for genesis account setup and transaction collection

The review suggestion is valid as both init scripts lack proper error handling for the genesis account setup and transaction collection commands. The scripts already have error handling for the SIMD_BIN check but miss it for critical genesis operations. The suggested refactoring would improve reliability by:

  • Wrapping account creation in a function with error checking
  • Adding error handling for genesis transaction generation
  • Adding error handling for transaction collection
  • Maintaining consistency with existing error handling patterns in the scripts

The proposed changes in the review comment are appropriate and would enhance the script's robustness.

🔗 Analysis chain

Line range hint 21-24: Add validation for genesis account setup.

The genesis account setup and transaction collection should include error checking.

Let's verify the account setup commands:

Consider adding error handling:

+setup_genesis_account() {
+    local account=$1
+    local amount=$2
+    
+    if ! $SIMD_BIN genesis add-genesis-account "$account" "$amount" --keyring-backend test; then
+        echo "Error: Failed to add genesis account for $account"
+        exit 1
+    fi
+}
+
-$SIMD_BIN genesis add-genesis-account alice 5000000000stake --keyring-backend test
-$SIMD_BIN genesis add-genesis-account bob 5000000000stake --keyring-backend test
-$SIMD_BIN genesis gentx alice 1000000stake --chain-id simapp-v2-chain
-$SIMD_BIN genesis collect-gentxs
+setup_genesis_account "alice" "5000000000stake"
+setup_genesis_account "bob" "5000000000stake"
+
+if ! $SIMD_BIN genesis gentx alice 1000000stake --chain-id simapp-v2-chain; then
+    echo "Error: Failed to generate genesis transaction"
+    exit 1
+fi
+
+if ! $SIMD_BIN genesis collect-gentxs; then
+    echo "Error: Failed to collect genesis transactions"
+    exit 1
+fi
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify that the genesis accounts are properly set up
if [ -f "$SIMD_HOME/config/genesis.json" ]; then
    # Check if the accounts exist in genesis
    jq -e '.app_state.auth.accounts[] | select(.address != null)' "$SIMD_HOME/config/genesis.json"
fi

Length of output: 33


Script:

#!/bin/bash
# Let's check the actual script content and any similar scripts for error handling patterns
rg -l "genesis add-genesis-account" --type sh
rg -l "genesis collect-gentxs" --type sh
rg -A 5 "if.*genesis" --type sh

Length of output: 772


Script:

#!/bin/bash
# Let's examine the content of both init scripts to see their implementation
cat scripts/init-simapp.sh scripts/init-simapp-v2.sh

Length of output: 2790

simapp/v2/simdv2/cmd/root_di.go (2)

35-42: Enhance error handling with context

The error handling could be more descriptive to help with debugging. Consider wrapping errors with additional context.

 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to create command factory: %w", err)
 }
 
 subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to parse command: %w", err)
 }

50-55: Remove unnecessary nesting of depinject.Configs

The nested depinject.Configs calls are redundant and can be simplified.

-depinjectConfig = depinject.Configs(
-   depinject.Configs(
-       depinject.Supply(logger, runtime.GlobalConfig(configMap)),
-       depinject.Provide(ProvideClientContext),
-   ),
-)
+depinjectConfig = depinject.Configs(
+   depinject.Supply(logger, runtime.GlobalConfig(configMap)),
+   depinject.Provide(ProvideClientContext),
+)
server/v2/command_builder.go (1)

27-32: Create the referenced issue for removing the viper field.

The TODO comment mentions that an issue needs to be created after merging #22267. Please create the issue and update the comment with the actual issue number to replace <CREATE ME>.

Would you like me to help create this issue to track the removal of the viper field?

simapp/v2/simdv2/cmd/commands.go (1)

35-42: Enhance type documentation with field descriptions.

While the type documentation provides a good overview, consider adding detailed documentation for each field to improve maintainability.

 // commandDependencies is a struct that contains all the dependencies needed to initialize the root command.
 // an alternative design could fetch these even later from the command context
+//
+// Fields:
+// - globalAppConfig: Configuration map for the entire application
+// - txConfig: Transaction configuration for encoding/decoding
+// - moduleManager: Manages the application's modules
+// - simApp: Instance of the simulation application
+// - consensusComponent: Handles consensus-related operations
 type commandDependencies[T transaction.Tx] struct {
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ca06258 and ff0fa66.

📒 Files selected for processing (10)
  • scripts/init-simapp-v2.sh (1 hunks)
  • server/v2/api/grpc/server.go (3 hunks)
  • server/v2/api/rest/server.go (2 hunks)
  • server/v2/api/rest/server_test.go (1 hunks)
  • server/v2/cometbft/server.go (3 hunks)
  • server/v2/command_builder.go (1 hunks)
  • simapp/v2/simdv2/cmd/commands.go (2 hunks)
  • simapp/v2/simdv2/cmd/root_di.go (1 hunks)
  • simapp/v2/simdv2/cmd/testnet.go (1 hunks)
  • x/genutil/v2/types.go (0 hunks)
💤 Files with no reviewable changes (1)
  • x/genutil/v2/types.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • server/v2/api/rest/server_test.go
  • simapp/v2/simdv2/cmd/testnet.go
🧰 Additional context used
📓 Path-based instructions (6)
server/v2/api/grpc/server.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/api/rest/server.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/cometbft/server.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/command_builder.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/commands.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/root_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🔇 Additional comments (19)
server/v2/api/rest/server.go (5)

9-9: LGTM: Import additions align with new functionality

The new imports support the eager config loading and dependency injection requirements.

Also applies to: 13-13


43-43: Type assertion can be avoided

The type assertion srv.Config().(*Config) is still present. As mentioned in previous reviews, this could be made type-safe by changing Config() to return *Config directly.


29-52: LGTM: Improved initialization with proper DI and error handling

The changes to New function properly implement:

  • Early configuration loading
  • Dependency injection through appManager
  • Explicit error handling for config unmarshaling

54-61: LGTM: Well-documented config initialization function

The new NewWithConfigOptions function provides a clean way to handle configuration separately from server initialization, supporting the eager config loading objective.


29-52: Verify impact on snapshot restore functionality

Since this refactor changes server initialization, please verify that it resolves the snapshot restore panic from issue #22268.

simapp/v2/simdv2/cmd/root_di.go (2)

88-97: Review the order of command enhancement operations

The current sequence of operations (factory enhancement → initialization → AutoCLI enhancement) might lead to conflicts or overrides in command configuration. Consider consolidating all enhancements before the final initialization.

#!/bin/bash
# Check for potential command conflicts or overrides
rg -A 3 "Command.*already|flag.*already" 

19-29: Consider improving initial command setup

The initial setup uses a nop logger and empty command dependencies, which might mask potential initialization issues. Consider passing a proper logger and validating the command dependencies even during the initial setup phase.

server/v2/api/grpc/server.go (5)

Line range hint 24-28: LGTM: Import changes are appropriate.

The new imports are correctly organized and necessary for the enhanced server functionality.


46-55: LGTM: Constructor signature improvements enhance dependency injection.

The new constructor signature explicitly requires all dependencies, making the initialization process more robust and maintainable.


83-89: LGTM: Well-documented configuration constructor.

The new constructor clearly documents its limited purpose and usage constraints.


200-200: LGTM: Start method implementation.

The implementation correctly handles server startup with appropriate error handling and logging.


67-70: Verify GRPC server configuration and reflection setup.

The GRPC server configuration looks correct, but let's verify the usage of these handlers across the codebase.

Also applies to: 74-74

✅ Verification successful

Let me gather more information about the GRPC handler implementation to ensure completeness of verification.


GRPC server configuration is correctly implemented and consistent

The verification shows:

  • The GRPC server configuration is consistent across different server implementations
  • The custom codec and unknown service handler are properly implemented
  • Query handlers are correctly registered and used throughout the codebase
  • GRPC reflection is properly set up for external client discovery
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify GRPC handler usage patterns
# Look for other GRPC server configurations to ensure consistency

# Search for other GRPC server configurations
rg -A 3 "grpc.NewServer\(" --type go

# Search for query handler registrations
rg "map\[string\]appmodulev2.Handler" --type go

Length of output: 3312


Script:

#!/bin/bash
# Check the implementation of newProtoCodec and UnknownServiceHandler
ast-grep --pattern 'func newProtoCodec($_) $_'

# Look for the actual implementation of UnknownServiceHandler
ast-grep --pattern 'func makeUnknownServiceHandler($_) $_'

# Check if there are any other similar handler patterns
rg -A 5 "UnknownServiceHandler" --type go

Length of output: 1374

simapp/v2/simdv2/cmd/commands.go (2)

66-82: LGTM: CLI skeleton initialization looks good.

The initial config parsing logic with nil checks is well-structured.


141-144: ⚠️ Potential issue

Add safe type assertion for genutil module.

The current type assertion could panic if the module is not of the expected type.

-    genTxValidator = moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule).GenTxValidator()
+    if module, ok := moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule); ok {
+        genTxValidator = module.GenTxValidator()
+    } else {
+        return nil, fmt.Errorf("module %s is not of type genutil.AppModule", genutiltypes.ModuleName)
+    }

Likely invalid or redundant comment.

server/v2/cometbft/server.go (5)

21-31: LGTM: Import changes are well-organized

The new imports are properly organized and necessary for the enhanced functionality.


67-67: LGTM: Improved error handling in New function

The addition of error return type enhances error handling and follows Go best practices.


80-86: LGTM: Robust error handling in configuration unmarshaling

The error handling for configuration unmarshaling is comprehensive and provides clear error messages.


149-157: LGTM: Well-implemented indexer initialization

The indexer setup includes proper error handling, logging, and configuration validation.


164-170: LGTM: Well-documented configuration function

The NewWithConfigOptions function is properly documented with its limitations and follows Go best practices.

Comment thread scripts/init-simapp-v2.sh Outdated
Comment thread simapp/v2/simdv2/cmd/root_di.go Outdated
Comment thread server/v2/command_builder.go
Comment thread server/v2/command_builder.go
Comment thread server/v2/command_builder.go
Comment thread simapp/v2/simdv2/cmd/commands.go
Comment on lines +109 to 112
indexEvents := make(map[string]struct{}, len(srv.config.AppTomlConfig.IndexEvents))
for _, e := range srv.config.AppTomlConfig.IndexEvents {
indexEvents[e] = struct{}{}
}
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.

⚠️ Potential issue

Add nil check for AppTomlConfig.IndexEvents

The initialization of indexEvents assumes AppTomlConfig.IndexEvents is not nil. Add a nil check to prevent potential panic.

-indexEvents := make(map[string]struct{}, len(srv.config.AppTomlConfig.IndexEvents))
-for _, e := range srv.config.AppTomlConfig.IndexEvents {
+events := srv.config.AppTomlConfig.IndexEvents
+if events == nil {
+    events = []string{}
+}
+indexEvents := make(map[string]struct{}, len(events))
+for _, e := range events {
    indexEvents[e] = struct{}{}
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
indexEvents := make(map[string]struct{}, len(srv.config.AppTomlConfig.IndexEvents))
for _, e := range srv.config.AppTomlConfig.IndexEvents {
indexEvents[e] = struct{}{}
}
events := srv.config.AppTomlConfig.IndexEvents
if events == nil {
events = []string{}
}
indexEvents := make(map[string]struct{}, len(events))
for _, e := range events {
indexEvents[e] = struct{}{}
}

Copy link
Copy Markdown
Contributor

@julienrbrt julienrbrt left a comment

Choose a reason for hiding this comment

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

Those new APIs are great. My comments are only nits now. Love the new flow.

Could you add yourself as code owner of simapp/v2 and server/v2 btw? You've did quite a few improvements there so it be great that you get always pinged for future PRs.

Comment thread simapp/v2/simdv2/cmd/config.go Outdated
Comment thread simapp/v2/simdv2/cmd/root_di.go Outdated
Comment thread simapp/v2/simdv2/cmd/root_di.go Outdated
Copy link
Copy Markdown
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.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (7)
simapp/v2/simdv2/cmd/root_di.go (1)

19-29: Consider using a real logger for initial command setup

Using a nop logger during initial command setup might hide important initialization issues. Consider using a real logger with appropriate log level to ensure proper debugging capabilities.

-configWriter, err := initRootCmd(rootCommand, log.NewNopLogger(), commandDependencies[T]{})
+logger := log.NewLogger(os.Stderr) // or appropriate logger setup
+configWriter, err := initRootCmd(rootCommand, logger, commandDependencies[T]{})
x/genutil/v2/cli/export.go (1)

Line range hint 36-52: Enhance warning message clarity

While the nil handling is well-implemented with efficient file streaming, the warning message could be more descriptive to help users understand the implications.

Consider this improvement:

-				if _, err := fmt.Fprintln(cmd.ErrOrStderr(), "WARNING: App exporter not defined. Returning genesis file."); err != nil {
+				if _, err := fmt.Fprintln(cmd.ErrOrStderr(), "WARNING: App exporter not defined. Returning unmodified genesis file without state export."); err != nil {
server/v2/commands.go (3)

20-28: Update function documentation to reflect new parameters

The function documentation should be updated to describe the new parameters (logger and globalAppConfig) and return values (ConfigWriter).

// AddCommands add the server commands to the root command
-// It configures the config handling and the logger handling
+// It configures the config handling and the logger handling.
+//
+// Parameters:
+//   - rootCmd: The root command to add server commands to
+//   - logger: Logger instance for command execution
+//   - globalAppConfig: Application-wide configuration map
+//   - globalServerConfig: Server-specific configuration
+//   - components: Server components to be initialized
+//
+// Returns a ConfigWriter interface and an error if no components are provided

64-68: Update function documentation for createStartCommand

The function documentation should be updated to reflect the new parameters.

-// createStartCommand creates the start command for the application.
+// createStartCommand creates the start command for the application.
+//
+// Parameters:
+//   - server: The server instance to be started
+//   - config: Server configuration map
+//   - logger: Logger instance for command execution

173-177: Document the structure of appBuildingCommands

Add documentation to explain the expected format of the command paths array.

-// appBuildingCommands are the commands which need a full application to be built
+// appBuildingCommands defines the command paths that require a full application to be built.
+// Each inner slice represents a command path from root to leaf, in that order.
+// For example, ["genesis", "export"] represents the "genesis export" command.
server/v2/command_builder.go (2)

27-31: Create tracking issue for TODO comment.

The TODO comment references merging #22267 and mentions that a new issue needs to be created. Please create the referenced issue to track the removal of the vipr field.

Would you like me to help create a GitHub issue to track this task?


177-182: Add nil check for cmd.OutOrStdout().

When creating the logger, cmd.OutOrStdout() is called without a nil check. While it's unlikely to be nil in practice, it's safer to add a defensive check.

Consider adding a nil check:

 if f.loggerFactory != nil {
+    out := cmd.OutOrStdout()
+    if out == nil {
+        out = os.Stdout
+    }
-    f.logger, err = f.loggerFactory(f.vipr.AllSettings(), cmd.OutOrStdout())
+    f.logger, err = f.loggerFactory(f.vipr.AllSettings(), out)
     if err != nil {
         return nil, nil, nil, err
     }
 }
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ff0fa66 and d3bb0c3.

📒 Files selected for processing (5)
  • server/v2/command_builder.go (1 hunks)
  • server/v2/commands.go (5 hunks)
  • simapp/v2/app_di.go (4 hunks)
  • simapp/v2/simdv2/cmd/root_di.go (1 hunks)
  • x/genutil/v2/cli/export.go (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
server/v2/command_builder.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/commands.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/app_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/root_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

x/genutil/v2/cli/export.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🔇 Additional comments (9)
x/genutil/v2/cli/export.go (2)

24-24: LGTM: Interface-based design improves modularity

The change from concrete type v2.AppExporter to interface type ExportableApp enhances modularity and follows good design principles by depending on abstractions rather than concrete implementations.


61-65: Verify height validation

While the height loading logic is well-structured, we should verify that negative heights (other than -1) are properly validated.

Let's check if there are any height validation patterns in the codebase:

server/v2/commands.go (1)

110-117: ⚠️ Potential issue

Add type assertion check for CPU profile path

The current implementation could panic if cpuProfileFile is not a string.

 func wrapCPUProfile(logger log.Logger, cfg server.ConfigMap, callbackFn func() error) error {
-    cpuProfileFile, ok := cfg[FlagCPUProfiling]
-    if !ok {
+    cpuProfileFile, exists := cfg[FlagCPUProfiling]
+    if !exists {
         // if cpu profiling is not enabled, just run the callback
         return callbackFn()
     }
+    
+    profilePath, ok := cpuProfileFile.(string)
+    if !ok {
+        return errors.New("cpu profile path must be a string")
+    }
-    f, err := os.Create(cpuProfileFile.(string))
+    f, err := os.Create(profilePath)

Likely invalid or redundant comment.

simapp/v2/app_di.go (6)

63-77: Well-structured configuration setup with proper modularity!

The configuration setup properly separates concerns by introducing specific account type providers and base account options. This modular approach enhances maintainability and flexibility.


87-89: Improved function signature enhances flexibility!

The new signature with depinject.Config and variadic outputs aligns well with dependency injection patterns and supports eager config loading as intended in the PR objectives.


101-153: Excellent documentation of configuration options!

The comprehensive comments provide clear guidance for customizing various aspects of the application, including authentication, staking, and minting modules. The included examples make it easier for developers to understand and implement custom configurations.


169-191: Robust error handling implementation!

The error handling has been properly implemented with clear error propagation and meaningful error messages. This aligns well with Go best practices for error handling.


241-243: Clean and focused configuration provider!

The ProvideRootStoreConfig function follows the single responsibility principle and properly handles store configuration unmarshaling.


195-203: ⚠️ Potential issue

Consider removing or refactoring this test helper

Based on the previous discussion, since this function is only used in tests within the same package, consider either:

  1. Removing it and using NewSimApp directly in tests, or
  2. If keeping it, refactor to return an error instead of panicking

If keeping the function, consider this refactor:

-func NewSimAppWithInputs[T transaction.Tx](
-	logger log.Logger,
-	viper *viper.Viper,
-) *SimApp[T] {
+func NewSimAppWithInputs[T transaction.Tx](
+	logger log.Logger,
+	viper *viper.Viper,
+) (*SimApp[T], error) {
	app, err := NewSimApp[T](depinject.Configs(
		depinject.Supply(logger, runtime.GlobalConfig(viper.AllSettings()))),
	)
	if err != nil {
-		panic(err)
+		return nil, err
	}
-	return app
+	return app, nil
}

Comment thread simapp/v2/simdv2/cmd/root_di.go Outdated
Comment thread simapp/v2/simdv2/cmd/root_di.go
Comment thread simapp/v2/simdv2/cmd/root_di.go
Comment thread server/v2/commands.go Outdated
Comment thread server/v2/command_builder.go Outdated
Copy link
Copy Markdown
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.

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (2)
server/v2/command_builder.go (2)

1-16: Consider using underscore in package name.

The package name serverv2 should be server_v2 to follow Go naming conventions for packages with version numbers. This improves readability and consistency.


27-32: Convert TODO comment into a tracked issue.

The TODO comment indicates technical debt regarding the viper instance field. This should be tracked in the issue system for better visibility and follow-up.

Would you like me to create a GitHub issue to track this technical debt item? The issue would reference #22267 and #22388 for context.

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d3bb0c3 and c48172d.

📒 Files selected for processing (2)
  • server/v2/command_builder.go (1 hunks)
  • simapp/v2/simdv2/cmd/root_di.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
server/v2/command_builder.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/root_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🔇 Additional comments (3)
simapp/v2/simdv2/cmd/root_di.go (2)

73-78: ⚠️ Potential issue

Add validation for command dependencies

The commandDependencies struct is populated without validation, which could lead to runtime panics if any required fields are nil.

+func (d commandDependencies[T]) validate() error {
+    if d.globalAppConfig == nil {
+        return fmt.Errorf("globalAppConfig is required")
+    }
+    if d.txConfig == nil {
+        return fmt.Errorf("txConfig is required")
+    }
+    if d.moduleManager == nil {
+        return fmt.Errorf("moduleManager is required")
+    }
+    return nil
+}

 commandDeps := commandDependencies[T]{
     globalAppConfig: configMap,
     txConfig:        clientCtx.TxConfig,
     moduleManager:   moduleManager,
     simApp:          simApp,
 }
+if err := commandDeps.validate(); err != nil {
+    return nil, fmt.Errorf("invalid command dependencies: %w", err)
+}

Likely invalid or redundant comment.


49-52: 🛠️ Refactor suggestion

Simplify dependency injection configuration

The nested depinject.Configs calls are redundant and can be simplified.

-depinjectConfig = depinject.Configs(
-    depinject.Supply(logger, runtime.GlobalConfig(configMap)),
-    depinject.Provide(ProvideClientContext),
-)
+depinjectConfig := depinject.Supply(
+    logger,
+    runtime.GlobalConfig(configMap),
+    depinject.Provide(ProvideClientContext),
+)

Likely invalid or redundant comment.

server/v2/command_builder.go (1)

57-83: Add path validation and security checks.

The home directory path construction could benefit from additional security measures:

  1. Validate that the path doesn't contain directory traversal attempts
  2. Check for absolute path when joining with defaultHomeBasename
  3. Consider adding path length limits to prevent potential DoS

Let's check for similar security measures in other parts of the codebase:

Comment thread simapp/v2/simdv2/cmd/root_di.go
Comment thread simapp/v2/simdv2/cmd/root_di.go
Comment thread simapp/v2/simdv2/cmd/root_di.go
Comment thread simapp/v2/simdv2/cmd/root_di.go
Comment thread server/v2/command_builder.go
Comment thread server/v2/command_builder.go
Copy link
Copy Markdown
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.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
server/v2/commands.go (2)

29-31: Enhance error message for better debugging

The error message when no components are provided could be more descriptive to help users understand what components are expected.

Apply this diff to improve the error message:

-		return nil, errors.New("no components provided")
+		return nil, errors.New("no server components provided - at least one ServerComponent must be configured")

173-177: Consider making appBuildingCommands unexported

Since this variable is only used internally by IsAppRequired, it should be unexported to prevent external modification.

Apply this diff:

-var appBuildingCommands = [][]string{
+var defaultAppBuildingCommands = [][]string{
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between c48172d and 9addef4.

📒 Files selected for processing (2)
  • server/v2/commands.go (5 hunks)
  • simapp/v2/simdv2/cmd/commands.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • simapp/v2/simdv2/cmd/commands.go
🧰 Additional context used
📓 Path-based instructions (1)
server/v2/commands.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🔇 Additional comments (1)
server/v2/commands.go (1)

189-207: LGTM! Well-implemented command path checking

The implementation is efficient with:

  • Clear documentation including complexity analysis
  • Pre-allocated slices for better performance
  • Proper handling of command hierarchy traversal

Copy link
Copy Markdown
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.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (1)
simapp/v2/simdv2/cmd/commands.go (1)

35-42: LGTM! Consider enhancing documentation.

The CommandDependencies struct is well-designed and effectively encapsulates command dependencies. Consider adding godoc comments for each field to document their purpose and requirements.

Add field documentation:

 type CommandDependencies[T transaction.Tx] struct {
+    // globalAppConfig contains the application's global configuration
     globalAppConfig    coreserver.ConfigMap
+    // txConfig provides transaction configuration and encoding
     txConfig           client.TxConfig
+    // moduleManager manages the application's modules
     moduleManager      *runtimev2.MM[T]
+    // simApp is the main application instance
     simApp             *simapp.SimApp[T]
+    // consensusComponent handles consensus-related operations
     consensusComponent serverv2.ServerComponent[T]
 }
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9addef4 and 6d18467.

📒 Files selected for processing (3)
  • .github/CODEOWNERS (1 hunks)
  • simapp/v2/simdv2/cmd/commands.go (2 hunks)
  • simapp/v2/simdv2/cmd/root_di.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
simapp/v2/simdv2/cmd/commands.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/root_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🔇 Additional comments (3)
.github/CODEOWNERS (1)

28-28: LGTM! The ownership update aligns with recent architectural changes.

Adding @kocubinski as a codeowner for the /server/v2/ directory is appropriate given their significant contributions to refactoring the configuration parsing system and addressing the dual dependency injection issues in this module.

simapp/v2/simdv2/cmd/commands.go (2)

137-150: Verify all callers are updated with new function signature.

The function signature has changed to accept an additional app parameter. Let's ensure all callers are updated accordingly.

✅ Verification successful

Let me verify the function calls by checking their context.


All callers are properly updated with the new function signature

The verification shows that both callers of genesisCommand are correctly passing all required parameters:

  • In simapp/v2/simdv2/cmd/commands.go: genesisCommand(deps.moduleManager, deps.simApp)
  • In simapp/simd/cmd/commands.go: genesisCommand(moduleManager, appExport)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for function calls to genesisCommand
ast-grep --pattern 'genesisCommand($$$)'

Length of output: 204


Script:

#!/bin/bash
# Get context around the genesisCommand calls
rg "genesisCommand" -B 3 -A 1

Length of output: 1566


66-82: Verify thread safety of component initialization.

The CLI skeleton initialization path creates default components when they're nil. In a concurrent environment, this could lead to race conditions if multiple goroutines attempt to initialize components simultaneously.

Comment thread simapp/v2/simdv2/cmd/root_di.go
Comment on lines +93 to +94
if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
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.

🛠️ Refactor suggestion

Improve error handling for AutoCLI enhancement

The error from EnhanceRootCommand should include more context for better debugging.

 if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to enhance root command with AutoCLI options: %w", err)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, fmt.Errorf("failed to enhance root command with AutoCLI options: %w", err)

Comment on lines +39 to +41
subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
if err != nil {
return nil, err
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.

🛠️ Refactor suggestion

Enhance error handling for command parsing

The error from ParseCommand could benefit from additional context to aid in debugging.

 subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to parse command %q: %w", rootCommand.Name(), err)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
if err != nil {
return nil, err
subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
if err != nil {
return nil, fmt.Errorf("failed to parse command %q: %w", rootCommand.Name(), err)

Comment on lines +54 to +70
if serverv2.IsAppRequired(subCommand) {
// server construction
simApp, err = simapp.NewSimApp[T](depinjectConfig, &autoCliOpts, &moduleManager, &clientCtx)
if err != nil {
return nil, err
}
} else {
// client construction
if err = depinject.Inject(
depinject.Configs(
simapp.AppConfig(),
depinjectConfig,
),
&autoCliOpts, &moduleManager, &clientCtx,
); err != nil {
return nil, err
}
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.

⚠️ Potential issue

Add validation for injected dependencies

The code should validate that critical dependencies are properly initialized after injection for both server and client paths.

 if serverv2.IsAppRequired(subCommand) {
     simApp, err = simapp.NewSimApp[T](depinjectConfig, &autoCliOpts, &moduleManager, &clientCtx)
     if err != nil {
         return nil, fmt.Errorf("failed to create SimApp: %w", err)
     }
+    if err := validateDependencies(&autoCliOpts, moduleManager, clientCtx); err != nil {
+        return nil, fmt.Errorf("invalid server dependencies: %w", err)
+    }
 } else {
     if err = depinject.Inject(
         depinject.Configs(
             simapp.AppConfig(),
             depinjectConfig,
         ),
         &autoCliOpts, &moduleManager, &clientCtx,
     ); err != nil {
         return nil, err
     }
+    if err := validateDependencies(&autoCliOpts, moduleManager, clientCtx); err != nil {
+        return nil, fmt.Errorf("invalid client dependencies: %w", err)
+    }
 }

+func validateDependencies(opts *autocli.AppOptions, mm *runtime.MM[T], ctx client.Context) error {
+    if opts == nil {
+        return fmt.Errorf("autocli options not initialized")
+    }
+    if mm == nil {
+        return fmt.Errorf("module manager not initialized")
+    }
+    if ctx.TxConfig == nil {
+        return fmt.Errorf("transaction config not initialized")
+    }
+    return nil
+}

Committable suggestion was skipped due to low confidence.

Comment thread simapp/v2/simdv2/cmd/commands.go Outdated
Comment on lines +197 to +221
func rootCommandPersistentPreRun(clientCtx client.Context) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())

// overwrite the FlagInvCheckPeriod
viper.Set(server.FlagInvCheckPeriod, 1)
viper.SetDefault(serverv2.FlagHome, simapp.DefaultNodeHome)
clientCtx = clientCtx.WithCmdContext(cmd.Context())
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}

var simApp *simapp.SimApp[T]
if height != -1 {
simApp = simapp.NewSimApp[T](logger, viper)
customClientTemplate, customClientConfig := initClientConfig()
clientCtx, err = config.CreateClientConfig(
clientCtx, customClientTemplate, customClientConfig)
if err != nil {
return err
}

if err := simApp.LoadHeight(uint64(height)); err != nil {
return genutilv2.ExportedApp{}, err
if err = client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
}
} else {
simApp = simapp.NewSimApp[T](logger, viper)
}

return simApp.ExportAppStateAndValidators(jailAllowedAddrs)
return nil
}
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.

🛠️ Refactor suggestion

Consider adding context timeout.

The command context setup could benefit from a timeout to prevent hanging in case of slow operations or network issues.

 func rootCommandPersistentPreRun(clientCtx client.Context) func(*cobra.Command, []string) error {
     return func(cmd *cobra.Command, args []string) error {
+        // Add timeout to prevent hanging
+        ctx, cancel := context.WithTimeout(cmd.Context(), 30*time.Second)
+        defer cancel()
-        clientCtx = clientCtx.WithCmdContext(cmd.Context())
+        clientCtx = clientCtx.WithCmdContext(ctx)
         // ... rest of the function
     }
 }

Committable suggestion was skipped due to low confidence.

Copy link
Copy Markdown
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.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (3)
simapp/v2/simdv2/cmd/root_di.go (3)

19-21: Add function documentation

Add a documentation comment explaining the purpose, parameters, and return values of the NewRootCmd function. This will improve code maintainability and help other developers understand the function's usage.

+// NewRootCmd creates and initializes a new root command for the simulation app.
+// It accepts optional command-line arguments and returns the configured root command
+// or an error if initialization fails.
 func NewRootCmd[T transaction.Tx](
 	args ...string,
 ) (*cobra.Command, error) {

35-38: Improve error handling for factory creation

Add context to the error returned from factory creation to aid in debugging.

 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to create command factory: %w", err)
 }

85-89: Improve error handling for command initialization

Add context to errors returned from command initialization steps to aid in debugging.

 factory.EnhanceRootCommand(rootCommand)
 _, err = InitRootCmd(rootCommand, logger, commandDeps)
 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to initialize root command: %w", err)
 }
📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9addef4 and 6d18467.

📒 Files selected for processing (3)
  • .github/CODEOWNERS (1 hunks)
  • simapp/v2/simdv2/cmd/commands.go (2 hunks)
  • simapp/v2/simdv2/cmd/root_di.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • simapp/v2/simdv2/cmd/commands.go
🧰 Additional context used
📓 Path-based instructions (1)
simapp/v2/simdv2/cmd/root_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

🔇 Additional comments (1)
.github/CODEOWNERS (1)

28-28: LGTM! Addition of code owner aligns with architectural changes.

The addition of @kocubinski as a code owner for /server/v2/ is appropriate given their significant contributions to the module's architecture, particularly the ongoing refactoring of configuration parsing and dependency injection improvements.

Comment on lines +73 to 78
commandDeps := CommandDependencies[T]{
globalAppConfig: configMap,
txConfig: clientCtx.TxConfig,
moduleManager: moduleManager,
simApp: simApp,
}
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.

🛠️ Refactor suggestion

Add validation for command dependencies

The CommandDependencies struct is populated without validation. Consider adding validation to ensure required fields are properly set before proceeding.

+func (d CommandDependencies[T]) validate() error {
+    if d.globalAppConfig == nil {
+        return fmt.Errorf("globalAppConfig is required")
+    }
+    if d.txConfig == nil {
+        return fmt.Errorf("txConfig is required")
+    }
+    if d.moduleManager == nil {
+        return fmt.Errorf("moduleManager is required")
+    }
+    return nil
+}

 commandDeps := CommandDependencies[T]{
     globalAppConfig: configMap,
     txConfig:        clientCtx.TxConfig,
     moduleManager:   moduleManager,
     simApp:          simApp,
 }
+if err := commandDeps.validate(); err != nil {
+    return nil, fmt.Errorf("invalid command dependencies: %w", err)
+}

Committable suggestion was skipped due to low confidence.

Comment on lines +49 to +70
depinjectConfig = depinject.Configs(
depinject.Supply(logger, runtime.GlobalConfig(configMap)),
depinject.Provide(ProvideClientContext),
)
)
if serverv2.IsAppRequired(subCommand) {
// server construction
simApp, err = simapp.NewSimApp[T](depinjectConfig, &autoCliOpts, &moduleManager, &clientCtx)
if err != nil {
return nil, err
}
} else {
// client construction
if err = depinject.Inject(
depinject.Configs(
simapp.AppConfig(),
depinjectConfig,
),
&autoCliOpts, &moduleManager, &clientCtx,
); err != nil {
return nil, err
}
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.

🛠️ Refactor suggestion

Extract common dependency injection logic

The dependency injection configuration is duplicated between server and client paths. Consider extracting the common configuration into a separate function.

+func createBaseConfig(logger log.Logger, configMap runtime.ConfigMap) depinject.Config {
+    return depinject.Configs(
+        depinject.Supply(logger, runtime.GlobalConfig(configMap)),
+        depinject.Provide(ProvideClientContext),
+    )
+}

-depinjectConfig = depinject.Configs(
-    depinject.Supply(logger, runtime.GlobalConfig(configMap)),
-    depinject.Provide(ProvideClientContext),
-)
+depinjectConfig = createBaseConfig(logger, configMap)

Committable suggestion was skipped due to low confidence.

Copy link
Copy Markdown
Contributor

@julienrbrt julienrbrt left a comment

Choose a reason for hiding this comment

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

lgtm! I just pinged you at two comments that were left unanswered

@julienrbrt
Copy link
Copy Markdown
Contributor

Added backport label for partial backport

Copy link
Copy Markdown
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.

Actionable comments posted: 15

🧹 Outside diff range and nitpick comments (5)
simapp/v2/simdv2/cmd/depinject.go (1)

53-69: Enhance documentation and error handling.

The comment about textual configuration could be more descriptive. Consider explaining:

  • Why textual is enabled by default
  • The implications of using gRPC instead of bank keeper
  • When someone might want to change this default

Suggested comment improvement:

-// textual is enabled by default, we need to re-create the tx config grpc instead of bank keeper.
+// Textual coin metadata querying is enabled by default for human-readable transaction display.
+// We use gRPC queries instead of the bank keeper to avoid circular dependencies and allow
+// metadata queries before the bank module is fully initialized.
simapp/v2/simdv2/cmd/root_di.go (1)

19-21: Consider adding documentation about the command initialization pattern

The new command initialization pattern is a significant architectural change. Consider adding documentation that explains:

  • Why the command needs to be initialized twice
  • The role of empty dependencies in the first initialization
  • The relationship between server and client construction paths
simapp/v2/app_di.go (1)

87-118: Fix typos in configuration documentation

There are a few typos in the documentation comments:

  • Line 111: "provinding" should be "providing"
  • Line 113: Consider adding commas for better readability in "and appends "valoper" and "valcons""
simapp/v2/simdv2/cmd/commands.go (1)

35-42: Well-structured dependency container!

The CommandDependencies struct provides a clean way to manage command dependencies. The comment about fetching dependencies later from command context suggests good forward-thinking about potential improvements.

Consider implementing a builder pattern for this struct in the future to make dependency injection more flexible and testable.

server/v2/api/grpcgateway/server.go (1)

78-78: Address the TODO: Register the gRPC-Gateway routes

The TODO comment indicates that the gRPC-Gateway routes need to be implemented. Registering the gRPC-Gateway routes is essential for the gateway to function correctly.

Would you like assistance in implementing the route registration or opening a GitHub issue to track this task?

📜 Review details

Configuration used: .coderabbit.yml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6d18467 and e7603cf.

📒 Files selected for processing (8)
  • runtime/v2/config.go (1 hunks)
  • server/v2/api/grpcgateway/server.go (4 hunks)
  • server/v2/command_factory.go (1 hunks)
  • simapp/v2/app_di.go (4 hunks)
  • simapp/v2/app_test.go (2 hunks)
  • simapp/v2/simdv2/cmd/commands.go (2 hunks)
  • simapp/v2/simdv2/cmd/depinject.go (1 hunks)
  • simapp/v2/simdv2/cmd/root_di.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • runtime/v2/config.go
  • simapp/v2/app_test.go
🧰 Additional context used
📓 Path-based instructions (6)
server/v2/api/grpcgateway/server.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

server/v2/command_factory.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/app_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/commands.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/depinject.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

simapp/v2/simdv2/cmd/root_di.go (1)

Pattern **/*.go: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.

📓 Learnings (1)
simapp/v2/simdv2/cmd/root_di.go (1)
Learnt from: kocubinski
PR: cosmos/cosmos-sdk#22267
File: simapp/v2/simdv2/cmd/root_di.go:26-26
Timestamp: 2024-10-28T18:07:44.817Z
Learning: In `simapp/v2/simdv2/cmd/root_di.go`, the initial call to `InitRootCmd` with empty `CommandDependencies` is required to initialize configuration.
🔇 Additional comments (7)
simapp/v2/simdv2/cmd/depinject.go (2)

1-18: LGTM! Well-organized imports.

The imports are properly organized and grouped by standard library, external, and internal packages.


31-39: LGTM with previous review comments.

The error handling concerns were already addressed in previous reviews.

simapp/v2/app_di.go (3)

49-63: LGTM! Well-structured configuration setup.

The configuration changes improve modularity by:

  • Separating module configuration
  • Adding explicit account type providers
  • Following dependency injection best practices

73-178: LGTM! Robust implementation with proper error handling.

The refactored NewSimApp function:

  • Uses dependency injection properly
  • Implements thorough error handling
  • Provides clear initialization flow

213-215: LGTM! Clean and focused implementation.

The function follows the single responsibility principle and provides a clear interface for root store configuration.

simapp/v2/simdv2/cmd/commands.go (2)

66-82: Clean separation of CLI skeleton initialization!

The conditional initialization based on deps.SimApp provides a clear separation between CLI skeleton and full app modes.


197-221: ⚠️ Potential issue

Enhance error handling with context

While the function correctly handles command setup, the error returns could be more informative.

Add context to error returns:

 clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
 if err != nil {
-    return err
+    return fmt.Errorf("failed to read persistent command flags: %w", err)
 }

 clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig)
 if err != nil {
-    return err
+    return fmt.Errorf("failed to create client config: %w", err)
 }

 if err = client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
-    return err
+    return fmt.Errorf("failed to set client context handler: %w", err)
 }

Likely invalid or redundant comment.

Comment on lines +41 to +52
clientCtx := client.Context{}.
WithCodec(appCodec).
WithInterfaceRegistry(interfaceRegistry).
WithLegacyAmino(amino).
WithInput(os.Stdin).
WithAccountRetriever(types.AccountRetriever{}).
WithAddressCodec(addressCodec).
WithValidatorAddressCodec(validatorAddressCodec).
WithConsensusAddressCodec(consensusAddressCodec).
WithHomeDir(homeDir).
WithViper("") // uses by default the binary name as prefix

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.

🛠️ Refactor suggestion

Consider making input source configurable.

The direct use of os.Stdin might make testing difficult and reduce flexibility. Consider accepting an io.Reader as a parameter or configuration option.

+type ClientContextConfig struct {
+    // ... other fields ...
+    Input io.Reader
+}

 	clientCtx := client.Context{}.
 		WithCodec(appCodec).
 		WithInterfaceRegistry(interfaceRegistry).
 		WithLegacyAmino(amino).
-		WithInput(os.Stdin).
+		WithInput(codecConfig.Input).

Committable suggestion was skipped due to low confidence.

Comment on lines +20 to +30
// ProvideClientContext is a depinject Provider function which assembles and returns a client.Context.
func ProvideClientContext(
configMap runtime.GlobalConfig,
appCodec codec.Codec,
interfaceRegistry codectypes.InterfaceRegistry,
txConfigOpts tx.ConfigOptions,
legacyAmino registry.AminoRegistrar,
addressCodec address.Codec,
validatorAddressCodec address.ValidatorAddressCodec,
consensusAddressCodec address.ConsensusAddressCodec,
) client.Context {
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.

🛠️ Refactor suggestion

Consider returning error and grouping parameters.

While the function is well-documented, consider these improvements:

  1. Return an error instead of using panics (as mentioned in previous reviews).
  2. Group related parameters (e.g., address codecs) into a configuration struct to improve maintainability.

Example refactor:

-func ProvideClientContext(
+type ClientContextConfig struct {
+    AddressCodec            address.Codec
+    ValidatorAddressCodec   address.ValidatorAddressCodec
+    ConsensusAddressCodec   address.ConsensusAddressCodec
+}
+
+func ProvideClientContext(
 	configMap runtime.GlobalConfig,
 	appCodec codec.Codec,
 	interfaceRegistry codectypes.InterfaceRegistry,
 	txConfigOpts tx.ConfigOptions,
 	legacyAmino registry.AminoRegistrar,
-	addressCodec address.Codec,
-	validatorAddressCodec address.ValidatorAddressCodec,
-	consensusAddressCodec address.ConsensusAddressCodec,
-) client.Context {
+	codecConfig ClientContextConfig,
+) (client.Context, error) {

Committable suggestion was skipped due to low confidence.

Comment on lines +26 to +29
configWriter, err := InitRootCmd(rootCommand, log.NewNopLogger(), CommandDependencies[T]{})
if err != nil {
return nil, err
}
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.

🛠️ Refactor suggestion

Improve error handling for InitRootCmd

The error from InitRootCmd should include more context for better debugging.

 configWriter, err := InitRootCmd(rootCommand, log.NewNopLogger(), CommandDependencies[T]{})
 if err != nil {
-    return nil, err
+    return nil, fmt.Errorf("failed to initialize root command: %w", err)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
configWriter, err := InitRootCmd(rootCommand, log.NewNopLogger(), CommandDependencies[T]{})
if err != nil {
return nil, err
}
configWriter, err := InitRootCmd(rootCommand, log.NewNopLogger(), CommandDependencies[T]{})
if err != nil {
return nil, fmt.Errorf("failed to initialize root command: %w", err)
}

Comment on lines +62 to +66
if err = depinject.Inject(
depinject.Configs(
simapp.AppConfig(),
depinjectConfig,
),
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.

🛠️ Refactor suggestion

Simplify dependency injection configuration

The nested depinject.Configs calls can be flattened as they serve the same purpose.

 if err = depinject.Inject(
-    depinject.Configs(
-        simapp.AppConfig(),
-        depinjectConfig,
-    ),
+    simapp.AppConfig(),
+    depinjectConfig,
     &autoCliOpts, &moduleManager, &clientCtx,
 ); err != nil {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if err = depinject.Inject(
depinject.Configs(
simapp.AppConfig(),
depinjectConfig,
),
if err = depinject.Inject(
simapp.AppConfig(),
depinjectConfig,

Comment on lines +90 to +92
nodeCmds := nodeservice.NewNodeCommands()
autoCliOpts.ModuleOptions = make(map[string]*autocliv1.ModuleOptions)
autoCliOpts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions()
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.

🛠️ Refactor suggestion

Consider error handling for node commands initialization

The node commands initialization and AutoCLI options setup should be wrapped in a separate function with proper error handling.

+func setupNodeCommands(opts *autocli.AppOptions) error {
+    nodeCmds := nodeservice.NewNodeCommands()
+    if nodeCmds == nil {
+        return fmt.Errorf("failed to create node commands")
+    }
+    if opts.ModuleOptions == nil {
+        opts.ModuleOptions = make(map[string]*autocliv1.ModuleOptions)
+    }
+    opts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions()
+    return nil
+}

-nodeCmds := nodeservice.NewNodeCommands()
-autoCliOpts.ModuleOptions = make(map[string]*autocliv1.ModuleOptions)
-autoCliOpts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions()
+if err := setupNodeCommands(&autoCliOpts); err != nil {
+    return nil, fmt.Errorf("failed to setup node commands: %w", err)
+}

Committable suggestion was skipped due to low confidence.

Comment on lines +151 to +152
if errors.Is(err, pflag.ErrHelp) {
return cmd, nil, nil, nil
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.

🛠️ Refactor suggestion

Use cobra.ErrHelp instead of pflag.ErrHelp for help requests

When checking for help requests, it's more appropriate to use cobra.ErrHelp to align with the Cobra library's error handling. This ensures consistency and better integration with Cobra's command parsing logic.

Apply this diff to use cobra.ErrHelp:

 if err = cmd.ParseFlags(args); err != nil {
 	// help requested, return the command early
 	if errors.Is(err, pflag.ErrHelp) {
-		return cmd, nil, nil, nil
+		return nil, nil, nil, cobra.ErrHelp
 	}
 	return nil, nil, nil, err
 }

Make sure to import the Cobra errors package if not already included:

import (
	// ...
	"github.com/spf13/cobra"
	// ...
)

Comment on lines +38 to +47
func NewCommandFactory(opts ...CommandFactoryOption) (*CommandFactory, error) {
f := &CommandFactory{}
for _, opt := range opts {
err := opt(f)
if err != nil {
return nil, err
}
}
return f, nil
}
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.

🛠️ Refactor suggestion

Consider initializing vipr in NewCommandFactory

Currently, vipr is not initialized in the NewCommandFactory function, which could lead to nil pointer dereferences when it's used before being set. Initialize vipr during the creation of the CommandFactory to ensure it's ready for use.

Modify the NewCommandFactory function as follows:

 func NewCommandFactory(opts ...CommandFactoryOption) (*CommandFactory, error) {
 	f := &CommandFactory{
+		vipr: viper.New(),
 	}
 	for _, opt := range opts {
 		err := opt(f)
 		if err != nil {
 			return nil, err
 		}
 	}
 	return f, nil
 }

This ensures that vipr is always available when methods like enhanceCommand are called.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func NewCommandFactory(opts ...CommandFactoryOption) (*CommandFactory, error) {
f := &CommandFactory{}
for _, opt := range opts {
err := opt(f)
if err != nil {
return nil, err
}
}
return f, nil
}
func NewCommandFactory(opts ...CommandFactoryOption) (*CommandFactory, error) {
f := &CommandFactory{
vipr: viper.New(),
}
for _, opt := range opts {
err := opt(f)
if err != nil {
return nil, err
}
}
return f, nil
}

Comment on lines +124 to +127
viper.SetEnvPrefix(f.envPrefix)
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
viper.AutomaticEnv()
}
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.

🛠️ Refactor suggestion

⚠️ Potential issue

Avoid using the global Viper instance; use the vipr field instead

In the enhanceCommand method, the global Viper instance is being modified. This can lead to unexpected behavior, especially if multiple instances of CommandFactory are used concurrently in different parts of the application. It's better to utilize the vipr field within CommandFactory to maintain instance-specific configurations and avoid side effects.

Apply this diff to use the local Viper instance:

 func (f *CommandFactory) enhanceCommand(cmd *cobra.Command) {
 	pflags := cmd.PersistentFlags()
 	pflags.String(FlagLogLevel, "info", "The logging level (trace|debug|info|warn|error|fatal|panic|disabled or '*:<level>,<key>:<level>')")
 	pflags.String(FlagLogFormat, "plain", "The logging format (json|plain)")
 	pflags.Bool(FlagLogNoColor, false, "Disable colored logs")
 	pflags.StringP(FlagHome, "", f.defaultHomeDir, "directory for config and data")
-	viper.SetEnvPrefix(f.envPrefix)
-	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
-	viper.AutomaticEnv()
+	f.vipr.SetEnvPrefix(f.envPrefix)
+	f.vipr.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
+	f.vipr.AutomaticEnv()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
viper.SetEnvPrefix(f.envPrefix)
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
viper.AutomaticEnv()
}
f.vipr.SetEnvPrefix(f.envPrefix)
f.vipr.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
f.vipr.AutomaticEnv()
}

Comment on lines +63 to +70
homeDir, envHome := "", "HOME"
if len(f.envPrefix) > 0 {
homeDir = os.Getenv(f.envPrefix + "_" + envHome)
} else {
homeDir = os.Getenv("NODE_" + envHome)
}
if homeDir != "" {
f.defaultHomeDir = filepath.Clean(homeDir)
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.

⚠️ Potential issue

Potential confusion with environment variable handling when envPrefix is empty

When envPrefix is empty, the code defaults to using the NODE_HOME environment variable to determine the home directory. This might not align with user expectations and could lead to unintended configurations. Consider defaulting to the standard HOME environment variable or ensuring that envPrefix is explicitly set to avoid ambiguity.

Apply this diff to default to the HOME environment variable when envPrefix is empty:

 if len(f.envPrefix) > 0 {
 	homeDir = os.Getenv(f.envPrefix + "_" + envHome)
 } else {
-	homeDir = os.Getenv("NODE_" + envHome)
+	homeDir = os.Getenv(envHome)
 }
 if homeDir != "" {
 	f.defaultHomeDir = filepath.Clean(homeDir)
 	return nil
 }

This change ensures that in the absence of an envPrefix, the standard HOME environment variable is used.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
homeDir, envHome := "", "HOME"
if len(f.envPrefix) > 0 {
homeDir = os.Getenv(f.envPrefix + "_" + envHome)
} else {
homeDir = os.Getenv("NODE_" + envHome)
}
if homeDir != "" {
f.defaultHomeDir = filepath.Clean(homeDir)
homeDir, envHome := "", "HOME"
if len(f.envPrefix) > 0 {
homeDir = os.Getenv(f.envPrefix + "_" + envHome)
} else {
homeDir = os.Getenv(envHome)
}
if homeDir != "" {
f.defaultHomeDir = filepath.Clean(homeDir)

Comment on lines +178 to +182
f.logger, err = f.loggerFactory(f.vipr.AllSettings(), cmd.OutOrStdout())
if err != nil {
return nil, nil, nil, err
}
}
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.

⚠️ Potential issue

Check for loggerFactory being nil before using f.logger

In the ParseCommand method, after creating the logger with loggerFactory, there is no check to handle the case where loggerFactory is nil. This could lead to a nil pointer dereference when f.logger is used later.

Add a check to ensure f.logger is not nil before proceeding, or provide a default logger implementation.

 if f.loggerFactory != nil {
 	f.logger, err = f.loggerFactory(f.vipr.AllSettings(), cmd.OutOrStdout())
 	if err != nil {
 		return nil, nil, nil, err
 	}
+} else {
+	return nil, nil, nil, errors.New("loggerFactory is not set")
 }

Alternatively, ensure that a default loggerFactory is assigned during the CommandFactory initialization if it's a required dependency.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
f.logger, err = f.loggerFactory(f.vipr.AllSettings(), cmd.OutOrStdout())
if err != nil {
return nil, nil, nil, err
}
}
f.logger, err = f.loggerFactory(f.vipr.AllSettings(), cmd.OutOrStdout())
if err != nil {
return nil, nil, nil, err
}
} else {
return nil, nil, nil, errors.New("loggerFactory is not set")
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: server/v2 snapshot restore panics