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: move cli args to separate crates #2681

Merged
merged 10 commits into from
Nov 13, 2024
Merged

refactor: move cli args to separate crates #2681

merged 10 commits into from
Nov 13, 2024

Conversation

glihm
Copy link
Collaborator

@glihm glihm commented Nov 12, 2024

This PR moves the CLI args for Torii and Katana out of the binary, into dedicated crates.

Even if for now the katana-cli is a bit big due to the configs being pulled out from the respective katana crates, it makes it easier for slot to re-use the argument for configuration without having to reimplement them.

Summary by CodeRabbit

  • New Features

    • Introduced new CLI components for both Katana and Torii, enhancing command-line functionality.
    • Added configuration file support for NodeArgs, allowing users to specify settings via a file.
    • New ServerOptions struct for HTTP-RPC server configuration.
  • Bug Fixes

    • Improved argument parsing and configuration merging logic for better usability.
  • Documentation

    • Enhanced visibility of several constants and structures for easier access and configuration.
  • Chores

    • Cleaned up unused imports and commented code to streamline the codebase.

@glihm glihm requested review from kariy and Larkooo November 12, 2024 02:40
Copy link

coderabbitai bot commented Nov 12, 2024

Walkthrough

Ohayo, sensei! This pull request introduces several updates across multiple Cargo.toml files and source code files for the Katana and Torii projects. Key changes include the addition of new workspace members and dependencies for CLI components, modifications to existing dependencies, and restructuring of command-line argument handling. Notably, the NodeArgs structure has been enhanced to support configuration files, while the CLI functionality has been streamlined. New utility functions and modules have also been introduced to improve organization and usability.

Changes

File Path Change Summary
Cargo.toml Added workspace members: crates/katana/cli, crates/torii/cli; added dependencies: katana-cli, torii-cli.
bin/katana/Cargo.toml Removed katana-core, katana-slot-controller; added katana-cli; updated features to reference katana-cli.
bin/katana/src/cli/mod.rs Updated Cli struct's node field type from node::NodeArgs to NodeArgs from katana_cli.
bin/katana/src/main.rs Removed mod utils; declaration.
bin/torii/Cargo.toml Added dependency: torii-cli.
bin/torii/src/main.rs Removed ToriiArgs struct and related functionality; simplified command-line argument parsing.
crates/katana/cli/Cargo.toml Introduced new Cargo.toml for katana-cli, with various dependencies and features.
crates/katana/cli/src/lib.rs Added modules: args, file, options, utils; exported NodeArgs from args.
crates/katana/cli/src/utils.rs Added functions for seed parsing, genesis parsing, block hash/number parsing, and logging format enum.
crates/torii/cli/Cargo.toml Introduced new Cargo.toml for torii-cli, detailing dependencies and features.
crates/torii/cli/src/args.rs Added ToriiArgs struct for command-line options; implemented configuration loading.
crates/torii/cli/src/lib.rs Added modules: args, options; exported ToriiArgs.
crates/torii/cli/src/options.rs Changed visibility of several constants to public.
crates/katana/cli/src/options.rs Added ServerOptions struct for server configuration options.
crates/katana/core/src/service/messaging/mod.rs Updated MessagingConfig to derive PartialEq.
crates/katana/cli/src/args.rs Updated NodeArgs struct to include a configuration file field; modified methods for better efficiency.
crates/katana/cli/src/file.rs Introduced NodeArgsConfig struct for node configuration management.

Possibly related PRs

Suggested reviewers

  • glihm

🪧 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

@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: 3

🧹 Outside diff range and nitpick comments (13)
crates/katana/cli/src/lib.rs (2)

3-5: Clean module organization, sensei!

The separation into node, options, and utils modules provides a clear and maintainable structure. This modular approach aligns perfectly with the PR's objective of better CLI argument organization.

Consider documenting the responsibility of each module in the module-level documentation (//! comments) to help future contributors understand the codebase organization better.


7-8: Consider making the options re-exports more explicit, sensei!

While the specific re-exports from the node module are great, the wildcard re-export from options might make it harder to track the public API surface.

Consider listing out specific re-exports from the options module:

pub use node::{NodeArgs, NodeArgsConfig};
-pub use options::*;
+pub use options::{
+    // List specific types/functions here
+    // Example: OptionType1, OptionType2
+};
bin/katana/src/cli/mod.rs (1)

29-29: Ohayo! Good separation of execution logic, sensei!

The execution flow change nicely separates concerns by delegating to node::execute. Consider adding a brief comment explaining this architectural decision for future maintainers.

+    // Delegate execution to node module for better separation of concerns
     node::execute(&self.node.with_config_file()?)
bin/torii/Cargo.toml (1)

Line range hint 1-100: Consider standardizing dependency version management

Ohayo sensei! I notice we have a mix of workspace-managed versions and specifically pinned versions. For better maintainability, consider:

  1. Moving these direct version dependencies to workspace-level management:

    • ctrlc = "3.4"
    • either = "1.9.0"
    • http-body = "0.4.5"
    • tokio-stream = "0.1.11"
    • tokio-util = "0.7.7"
    • webbrowser = "0.8"
    • clap_config = "0.1.1"
  2. Evaluating if the git dependency could be replaced with a published version:

    • hyper-reverse-proxy = { git = "https://github.com/tarrencev/hyper-reverse-proxy" }
Cargo.toml (1)

39-39: Ohayo! The new CLI workspace members look good, sensei!

The addition of separate CLI crates for both Katana and Torii aligns perfectly with the modularization objective. This separation will make the CLI components more maintainable and reusable.

This modular approach will make it easier to:

  • Share CLI configurations across different components
  • Test CLI components in isolation
  • Maintain version control of CLI features independently

Also applies to: 49-49

crates/torii/cli/src/options.rs (2)

10-21: Ohayo! The constants look good, but could use some documentation.

The change to make these constants public aligns well with the PR objectives for better CLI arg modularity. However, adding documentation comments would make it easier for other developers to understand the purpose and impact of each constant.

Consider adding doc comments like this:

+/// Default HTTP server address (localhost)
pub const DEFAULT_HTTP_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
+/// Default HTTP server port
pub const DEFAULT_HTTP_PORT: u16 = 8080;

Line range hint 47-54: Ohayo sensei! Found a small documentation error in the help text.

The help text for websocket_port incorrectly mentions WebRTC transport instead of WebSocket transport.

Apply this fix:

     /// Port to serve Libp2p WebRTC transport
     #[arg(
         long = "relay.websocket_port",
         value_name = "PORT",
         default_value_t = DEFAULT_RELAY_WEBSOCKET_PORT,
-        help = "Port to serve Libp2p WebRTC transport."
+        help = "Port to serve Libp2p WebSocket transport."
     )]
crates/torii/cli/src/args.rs (6)

26-34: Ohayo, sensei! Inconsistent documentation for db_dir.

There is a mismatch between the comments and the help message for db_dir. The comments mention "file," while the help message refers to "directory." This might confuse users about what path to provide.

Consider standardizing the terminology. Here's a suggested change:

 /// Database filepath (ex: indexer.db). If specified file doesn't exist, it will be
-/// created. Defaults to in-memory database.
+/// created. Defaults to in-memory database.
 #[arg(long)]
 #[arg(
     value_name = "PATH",
-    help = "Database filepath. If specified directory doesn't exist, it will be created. \
+    help = "Database filepath. If specified file doesn't exist, it will be created. \
             Defaults to in-memory database."
 )]
 pub db_dir: Option<PathBuf>,

68-68: Ohayo, sensei! Enhance error context when reading config file.

When reading the configuration file, adding context to the error can help users diagnose issues more effectively.

Consider adjusting the error handling:

- toml::from_str(&std::fs::read_to_string(path)?)?
+ toml::from_str(
+     &std::fs::read_to_string(path)
+         .with_context(|| format!("Failed to read config file at {}", path.display()))?
+ )?

81-85: Ohayo, sensei! Avoid using unwrap() on URL parsing.

Using unwrap() on Url::parse can cause a panic if the URL is invalid. Although DEFAULT_RPC_URL is a constant, it's safer to handle potential errors gracefully.

Consider handling the potential error:

- if self.rpc == Url::parse(DEFAULT_RPC_URL).unwrap() {
+ if self.rpc == Url::parse(DEFAULT_RPC_URL).expect("Invalid default RPC URL") {

Or, better yet, parse the URL once at the start and handle any errors:

 pub const DEFAULT_RPC_URL: &str = "http://0.0.0.0:5050";

+lazy_static::lazy_static! {
+    static ref DEFAULT_RPC_URL_PARSED: Url = Url::parse(DEFAULT_RPC_URL).expect("Invalid default RPC URL");
+}
 
 // ...
 
 if self.rpc == *DEFAULT_RPC_URL_PARSED {
     if let Some(rpc) = config.rpc {
         self.rpc = rpc;
     }
 }

95-97: Ohayo, sensei! Consider implementing recursive configuration merging.

The current configuration merging operates only at the top level. Implementing recursive merging would allow more granular control over nested configurations, enhancing flexibility for users.


164-164: Ohayo, sensei! File extension mismatch in test configuration.

In the test_cli_precedence function, the test writes TOML content to a file named torii-config2.json. For clarity and consistency, consider changing the file extension to .toml.

Suggested change:

- let path = std::env::temp_dir().join("torii-config2.json");
+ let path = std::env::temp_dir().join("torii-config2.toml");

224-224: Ohayo, sensei! File extension mismatch in test configuration.

In the test_config_fallback function, the test writes TOML content to a file named torii-config.json. To maintain consistency, consider changing the file extension to .toml.

Suggested change:

- let path = std::env::temp_dir().join("torii-config.json");
+ let path = std::env::temp_dir().join("torii-config.toml");
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between caaf06b and 63e00ae.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • Cargo.toml (4 hunks)
  • bin/katana/Cargo.toml (2 hunks)
  • bin/katana/src/cli/mod.rs (3 hunks)
  • bin/katana/src/cli/node.rs (1 hunks)
  • bin/katana/src/main.rs (0 hunks)
  • bin/torii/Cargo.toml (1 hunks)
  • bin/torii/src/main.rs (1 hunks)
  • crates/katana/cli/Cargo.toml (1 hunks)
  • crates/katana/cli/src/lib.rs (1 hunks)
  • crates/katana/cli/src/node.rs (1 hunks)
  • crates/katana/cli/src/utils.rs (1 hunks)
  • crates/torii/cli/Cargo.toml (1 hunks)
  • crates/torii/cli/src/args.rs (1 hunks)
  • crates/torii/cli/src/lib.rs (1 hunks)
  • crates/torii/cli/src/options.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • bin/katana/src/main.rs
✅ Files skipped from review due to trivial changes (3)
  • crates/katana/cli/Cargo.toml
  • crates/torii/cli/Cargo.toml
  • crates/torii/cli/src/lib.rs
🔇 Additional comments (12)
crates/katana/cli/src/lib.rs (1)

1-1: Ohayo! Nice compiler attribute configuration, sensei!

The conditional warning for unused crate dependencies is a great practice. It helps keep the dependency tree clean during development while avoiding false positives during testing.

bin/katana/Cargo.toml (2)

13-13: Ohayo! The dependency change aligns with the refactoring goal.

The addition of katana-cli as a workspace dependency correctly implements the PR's objective of moving CLI arguments to separate crates.


37-37: Feature flag update looks good, sensei!

The slot feature has been properly updated to use the CLI-specific feature flag katana-cli/slot instead of the direct dependency, maintaining the functionality while improving modularity.

Let's verify the workspace structure and feature availability:

bin/katana/src/cli/mod.rs (2)

17-17: Ohayo! Clean type update, sensei!

The field type change is consistent with the new import while maintaining the flatten behavior for CLI parsing.


7-7: Ohayo! Import change looks good but let's verify dependencies

The move of NodeArgs to katana_cli aligns well with the modularization objective, sensei!

Let's verify the impact of this change:

✅ Verification successful

The previous results show that NodeArgs is still referenced from node.rs and katana-cli is properly added as a dependency, but let's verify the actual implementation and usage to ensure consistency.


Ohayo! The import change is perfectly safe, sensei!

The move of NodeArgs to katana-cli is properly implemented:

  • The dependency is correctly added in Cargo.toml files
  • All usages of NodeArgs now reference it from katana_cli
  • The node.rs file correctly imports it via katana_cli::node::NodeArgs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if NodeArgs is still referenced from the old location
rg "node::NodeArgs" 

# Verify that katana_cli is properly added as a dependency
rg "katana-cli" -g "Cargo.toml"

Length of output: 339


Script:

#!/bin/bash
# Let's check the content of node.rs to understand the usage
cat bin/katana/src/cli/node.rs

# Check if there are any other references to NodeArgs in the codebase
rg "NodeArgs" -A 2

Length of output: 11204

bin/torii/Cargo.toml (1)

36-36: Ohayo! The torii-cli workspace dependency looks good!

The addition of torii-cli as a workspace dependency aligns perfectly with the PR's objective of moving CLI arguments to separate crates, sensei! This will help improve modularity and reusability.

crates/katana/cli/src/utils.rs (1)

76-76: Ohayo! Verify test data location, sensei!

The test file path has been simplified. Let's ensure the test data is properly organized.

✅ Verification successful

Let me search for more context about the test data organization.

This will help us understand the test data organization patterns and locate the correct path for the genesis.json file.


Ohayo! The test data path is correct, sensei!

The path change is valid as ./test-data/genesis.json exists at crates/katana/cli/test-data/genesis.json. This matches the new test file location used in the CLI tests. The change aligns with the project's test data organization, where each crate maintains its own test data directory.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify test data organization

# Check if the test data exists at the new location
if [ -f "./test-data/genesis.json" ]; then
    echo "✓ Test data found at new location"
else
    echo "✗ Test data not found at new location"
fi

# Check for any other test files following the old pattern
echo "Checking for other test files following old pattern..."
fd -g "**/tests/test-data/genesis.json"

# Check for any other test files following the new pattern
echo "Checking for other test files following new pattern..."
fd -g "**/test-data/genesis.json"

Length of output: 438


Script:

#!/bin/bash
# Let's check the actual test file content and surrounding context
rg -B 5 -A 5 "genesis\.json" --type rust

# Also check if there are any other genesis.json files in the repository
fd "genesis.json"

# Look for test data directory patterns
fd "test-data"
fd "tests/test-data"

Length of output: 5439

Cargo.toml (1)

108-108: The workspace dependencies are properly configured!

The new CLI dependencies are correctly referenced with relative paths, maintaining consistency with other workspace dependencies.

Let's verify the crate structure exists:

Also applies to: 117-117

✅ Verification successful

Ohayo sensei! The CLI crates structure is properly configured! ✨

The verification confirms that both CLI crates exist and are properly structured:

  • crates/katana/cli exists with a valid Cargo.toml that uses workspace dependencies
  • crates/torii/cli exists with a valid Cargo.toml that uses workspace dependencies

Both crates follow the workspace configuration pattern consistently, with proper directory structure and dependency management.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the CLI crates exist and have proper Cargo.toml files

# Check if the CLI crates exist and have Cargo.toml files
for crate in "crates/katana/cli" "crates/torii/cli"; do
    if [ ! -f "${crate}/Cargo.toml" ]; then
        echo "Missing Cargo.toml in ${crate}"
        exit 1
    fi
done

Length of output: 198


Script:

#!/bin/bash
# Let's verify the existence and content of the CLI crates more thoroughly
echo "=== Checking katana CLI crate ==="
if [ -d "crates/katana/cli" ]; then
    ls -la crates/katana/cli/
    if [ -f "crates/katana/cli/Cargo.toml" ]; then
        echo "\nContents of katana CLI Cargo.toml:"
        cat crates/katana/cli/Cargo.toml
    fi
fi

echo -e "\n=== Checking torii CLI crate ==="
if [ -d "crates/torii/cli" ]; then
    ls -la crates/torii/cli/
    if [ -f "crates/torii/cli/Cargo.toml" ]; then
        echo "\nContents of torii CLI Cargo.toml:"
        cat crates/torii/cli/Cargo.toml
    fi
fi

Length of output: 2202

bin/torii/src/main.rs (1)

32-32: Ohayo, Sensei! Importing ToriiArgs from torii_cli enhances modularity

The import statement correctly brings in ToriiArgs from the torii_cli crate, aligning with the goal of separating CLI arguments into dedicated crates. This improves the modularity and reusability of the codebase.

crates/torii/cli/src/args.rs (2)

149-193: Ohayo, sensei! Excellent unit test for CLI precedence.

The test_cli_precedence function thoroughly verifies that command-line arguments take precedence over configuration file settings. This ensures robust and predictable behavior for users.


195-263: Ohayo, sensei! Excellent unit test for configuration fallback.

The test_config_fallback function effectively tests that configuration file values are correctly used when command-line arguments are not provided, ensuring reliable fallback mechanisms.

crates/katana/cli/src/node.rs (1)

110-122: Implementation of config method is clear and correct

Ohayo, sensei! The config method effectively aggregates configurations by calling helper methods and constructs the overall Config object accurately.

Comment on lines +10 to +21
pub const DEFAULT_HTTP_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
pub const DEFAULT_HTTP_PORT: u16 = 8080;
pub const DEFAULT_METRICS_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
pub const DEFAULT_METRICS_PORT: u16 = 9200;
pub const DEFAULT_EVENTS_CHUNK_SIZE: u64 = 1024;
pub const DEFAULT_BLOCKS_CHUNK_SIZE: u64 = 10240;
pub const DEFAULT_POLLING_INTERVAL: u64 = 500;
pub const DEFAULT_MAX_CONCURRENT_TASKS: usize = 100;

pub const DEFAULT_RELAY_PORT: u16 = 9090;
pub const DEFAULT_RELAY_WEBRTC_PORT: u16 = 9091;
pub const DEFAULT_RELAY_WEBSOCKET_PORT: u16 = 9092;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Found duplicate metrics constants with different values

Ohayo sensei! Found duplicate definitions of metrics-related constants with different values:

  • DEFAULT_METRICS_ADDR is defined in:

    • crates/torii/cli/src/options.rs (LOCALHOST)
    • crates/katana/node/src/config/metrics.rs (LOCALHOST)
  • DEFAULT_METRICS_PORT is defined in:

    • crates/torii/cli/src/options.rs (9200)
    • crates/katana/node/src/config/metrics.rs (9100)

The metrics constants should be consolidated to avoid confusion and potential conflicts. Consider moving these to a shared location or ensuring the values are intentionally different between Torii and Katana.

🔗 Analysis chain

Verify no duplicate constants exist in the codebase.

Since these constants are now public and part of the CLI separation, let's ensure there are no duplicate definitions elsewhere.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any duplicate definitions of these constants
for const in "DEFAULT_HTTP_ADDR" "DEFAULT_HTTP_PORT" "DEFAULT_METRICS_ADDR" "DEFAULT_METRICS_PORT" "DEFAULT_EVENTS_CHUNK_SIZE" "DEFAULT_BLOCKS_CHUNK_SIZE" "DEFAULT_POLLING_INTERVAL" "DEFAULT_MAX_CONCURRENT_TASKS" "DEFAULT_RELAY_PORT" "DEFAULT_RELAY_WEBRTC_PORT" "DEFAULT_RELAY_WEBSOCKET_PORT"; do
    echo "Checking for duplicate definitions of $const:"
    rg "const\s+$const\s*:" --type rust
done

Length of output: 6440

Comment on lines 71 to 75
let filter = if args.development.dev {
&format!("{DEFAULT_LOG_FILTER},server=debug")
} else {
DEFAULT_LOG_FILTER
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix type mismatch in let filter assignment

Ohayo sensei, in the let filter assignment, when args.development.dev is true, you're using &format!(...) which returns a &String, while the else branch returns a &str. This causes a type mismatch because the two branches must return the same type.

To resolve the issue, consider returning a String from both branches:

-let filter = if args.development.dev {
-    &format!("{DEFAULT_LOG_FILTER},server=debug")
-} else {
-    DEFAULT_LOG_FILTER
-};
+let filter = if args.development.dev {
+    format!("{DEFAULT_LOG_FILTER},server=debug")
+} else {
+    DEFAULT_LOG_FILTER.to_string()
+};

Then, when using EnvFilter::try_new(filter)?, you can pass &filter to match the expected &str type.

📝 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
let filter = if args.development.dev {
&format!("{DEFAULT_LOG_FILTER},server=debug")
} else {
DEFAULT_LOG_FILTER
};
let filter = if args.development.dev {
format!("{DEFAULT_LOG_FILTER},server=debug")
} else {
DEFAULT_LOG_FILTER.to_string()
};

Comment on lines 245 to 251
if !self.silent {
self.silent = config.silent.unwrap_or_default();
}

if !self.no_mining {
self.no_mining = config.no_mining.unwrap_or_default();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential issue with merging boolean flags: consider using Option<bool>

Ohayo, sensei! In the with_config_file method, the logic for merging boolean flags like silent and no_mining may not handle cases where the command-line arguments are explicitly set to false. Since boolean flags default to false, it's challenging to distinguish between an unset value and one explicitly set to false.

Consider changing the boolean fields in NodeArgs to Option<bool> to differentiate between unset and set values. This adjustment will allow for accurate merging of command-line arguments and configuration file settings.

Apply this diff to fix the issue:

-    pub silent: bool,
+    pub silent: Option<bool>,

And update the merging logic in with_config_file:

-        if !self.silent {
+        if self.silent.is_none() {
             self.silent = config.silent.unwrap_or_default();
         }

Committable suggestion skipped: line range outside the PR's diff.

Copy link

codecov bot commented Nov 12, 2024

Codecov Report

Attention: Patch coverage is 54.02597% with 177 lines in your changes missing coverage. Please review.

Project coverage is 57.51%. Comparing base (caaf06b) to head (8cb1119).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
crates/katana/cli/src/utils.rs 20.86% 110 Missing ⚠️
crates/katana/cli/src/file.rs 16.12% 26 Missing ⚠️
crates/torii/cli/src/args.rs 85.22% 26 Missing ⚠️
bin/torii/src/main.rs 0.00% 8 Missing ⚠️
crates/katana/cli/src/args.rs 80.00% 6 Missing ⚠️
crates/katana/core/src/service/messaging/mod.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2681      +/-   ##
==========================================
- Coverage   57.57%   57.51%   -0.06%     
==========================================
  Files         404      406       +2     
  Lines       51139    51197      +58     
==========================================
+ Hits        29441    29447       +6     
- Misses      21698    21750      +52     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

bin/katana/src/cli/node.rs Outdated Show resolved Hide resolved
Copy link

@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: 1

🧹 Outside diff range and nitpick comments (5)
crates/katana/cli/src/utils.rs (3)

36-51: Enhance test coverage for genesis parsing

The current test only verifies successful parsing. Consider adding tests for:

  • Invalid JSON format
  • Missing required fields
  • Shell expansion edge cases
  • File not found scenarios
#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::NamedTempFile;
    use std::io::Write;

    #[test]
    fn test_parse_genesis_various_cases() {
        // Test invalid JSON
        let mut invalid_json = NamedTempFile::new().unwrap();
        write!(invalid_json, "{{invalid}}").unwrap();
        assert!(parse_genesis(invalid_json.path().to_str().unwrap()).is_err());

        // Test missing required fields
        let mut missing_fields = NamedTempFile::new().unwrap();
        write!(missing_fields, "{{}}").unwrap();
        assert!(parse_genesis(missing_fields.path().to_str().unwrap()).is_err());

        // Test file not found
        assert!(parse_genesis("/nonexistent/path").is_err());
    }
}

Also applies to: 194-203


82-125: Consider optimizing the ASCII art display

The ASCII art banner increases binary size. Consider:

  1. Making it optional via a feature flag
  2. Moving it to a separate resource file
  3. Adding a --no-banner flag

163-192: Optimize string formatting in print_genesis_accounts

Consider using a string builder pattern or format_args! for more efficient string formatting, especially when dealing with multiple accounts.

 fn print_genesis_accounts<'a, Accounts>(accounts: Accounts)
 where
     Accounts: Iterator<Item = (&'a ContractAddress, &'a GenesisAccountAlloc)>,
 {
+    use std::fmt::Write;
+    let mut output = String::with_capacity(1024);
     println!(
         r"

 PREFUNDED ACCOUNTS
 =================="
     );

     for (addr, account) in accounts {
         if let Some(pk) = account.private_key() {
-            println!(
-                r"
-| Account address |  {addr}
-| Private key     |  {pk:#x}
-| Public key      |  {:#x}",
-                account.public_key()
-            )
+            writeln!(output, "\n| Account address |  {addr}").unwrap();
+            writeln!(output, "| Private key     |  {pk:#x}").unwrap();
+            writeln!(output, "| Public key      |  {:#x}", account.public_key()).unwrap();
         } else {
-            println!(
-                r"
-| Account address |  {addr}
-| Public key      |  {:#x}",
-                account.public_key()
-            )
+            writeln!(output, "\n| Account address |  {addr}").unwrap();
+            writeln!(output, "| Public key      |  {:#x}", account.public_key()).unwrap();
         }
     }
+    print!("{output}");
 }
crates/katana/cli/src/node.rs (2)

Line range hint 116-125: Ohayo, sensei! Enhance error context in execute and start_node methods

Consider adding more descriptive error contexts to help with debugging:

     pub fn execute(&self) -> Result<()> {
         self.init_logging()?;
         tokio::runtime::Builder::new_multi_thread()
             .enable_all()
             .build()
-            .context("failed to build tokio runtime")?
+            .context("failed to build tokio runtime: check system resources and thread limits")?
             .block_on(self.start_node())
     }

     async fn start_node(&self) -> Result<()> {
         // Build the node
         let config = self.config()?;
-        let node = katana_node::build(config).await.context("failed to build node")?;
+        let node = katana_node::build(config).await
+            .context("failed to build node: verify configuration and system requirements")?;

520-520: Ohayo, sensei! Consider making test data paths configurable

The hardcoded test data paths "./test-data/genesis.json" might cause issues if the test directory structure changes. Consider:

  1. Using a constant or environment variable for the test data directory
  2. Moving test data to a standard location like tests/data/
  3. Using relative paths from the test file's location
+    const TEST_DATA_DIR: &str = "./test-data";
+    const GENESIS_FILE: &str = "genesis.json";
+
     #[test]
     fn genesis_with_fixed_gas_prices() {
         let config = NodeArgs::parse_from([
             "katana",
             "--genesis",
-            "./test-data/genesis.json",
+            &format!("{}/{}", TEST_DATA_DIR, GENESIS_FILE),

Also applies to: 576-576

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 63e00ae and da719b5.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • bin/katana/Cargo.toml (1 hunks)
  • bin/katana/src/cli/mod.rs (2 hunks)
  • crates/katana/cli/Cargo.toml (1 hunks)
  • crates/katana/cli/src/node.rs (8 hunks)
  • crates/katana/cli/src/utils.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • bin/katana/src/cli/mod.rs
🔇 Additional comments (11)
bin/katana/Cargo.toml (2)

10-10: Ohayo sensei! Dependencies restructuring looks good!

The addition of katana-cli and removal of direct dependencies aligns perfectly with the PR's objective of moving CLI arguments to separate crates. Using workspace dependencies is also a solid practice for maintaining version consistency.


26-29: Verify feature flag propagation

The feature flags have been updated to use the new katana-cli crate, but let's verify that all necessary features are properly transferred and accessible.

✅ Verification successful

Let me gather more specific information about the feature dependencies.

This will help us verify the complete feature dependency chain and ensure proper propagation between the crates.


Feature flags are properly propagated, sensei! ✨

The feature flag chain is correctly implemented:

  • bin/katana correctly depends on katana-cli/slot in its default features
  • katana-cli properly manages the slot feature with katana-slot-controller dependency
  • The starknet-messaging feature chain flows correctly: bin/katana -> katana-cli -> katana-node -> katana-core
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify feature flags in katana-cli crate match the removed dependencies

# Check if all features from katana-core and katana-slot-controller are available in katana-cli
echo "Checking katana-cli Cargo.toml for feature definitions..."
rg -A 5 '^\[features\]' $(fd -t f 'Cargo.toml' | grep 'katana-cli')

# Verify no remaining references to old dependencies
echo "Checking for any remaining references to removed dependencies..."
rg -l 'katana-core|katana-slot-controller' $(fd -t f 'Cargo.toml')

Length of output: 7517


Script:

#!/bin/bash
# Check the actual feature dependencies in the relevant Cargo.toml files
echo "Checking katana-cli feature dependencies..."
cat crates/katana/cli/Cargo.toml

echo -e "\nChecking katana-core feature dependencies..."
cat crates/katana/core/Cargo.toml

echo -e "\nChecking katana-node feature dependencies..."
cat crates/katana/node/Cargo.toml

Length of output: 4003

crates/katana/cli/Cargo.toml (5)

1-6: Ohayo! Package metadata looks good, sensei!

The package configuration properly inherits workspace-level settings while explicitly setting the package name.


8-13: Main dependencies are well structured!

Good use of workspace versioning and proper configuration of optional dependencies.


30-32: Dev dependencies are properly configured!

Good use of workspace versioning for test dependencies.


34-37: Verify the impact of default features

The "slot" feature is enabled by default, which automatically includes katana-slot-controller. Let's verify if this aligns with the expected default behavior across the workspace.

✅ Verification successful

Ohayo sensei! After analyzing the feature configuration, I can now provide the final response:

Default slot feature is properly configured ✨

The default slot feature is well-aligned across the workspace:

  • In katana-primitives, the slot feature only enables the minimal controller feature
  • In katana-cli, it correctly pulls in both the controller dependency and primitives' slot feature
  • No other crates require the slot feature as a dependency
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how slot feature is used in other crates
echo "Checking slot feature usage:"
rg 'slot.*=.*\[' -g 'Cargo.toml' -A 2

echo -e "\nChecking katana-slot-controller usage:"
rg 'katana-slot-controller.*=' -g 'Cargo.toml'

Length of output: 655


Script:

#!/bin/bash
# Check if slot feature is used in dependencies or build requirements
echo "Checking dependencies requiring slot feature:"
rg 'features.*=.*slot' -g 'Cargo.toml'

echo -e "\nChecking where katana-primitives is used with slot feature:"
rg 'katana-primitives.*slot' -g 'Cargo.toml'

echo -e "\nChecking controller feature usage in primitives:"
cat crates/katana/primitives/Cargo.toml

Length of output: 1870


21-22: Verify fixed dependency versions across workspace

The fixed versions for serde_json and shellexpand might cause version conflicts if these packages are used elsewhere in the workspace.

crates/katana/cli/src/utils.rs (2)

53-80: Ohayo! Clean enum implementation, sensei!

The LogFormat enum is well-structured with appropriate trait implementations for clap integration and display formatting.


127-161: Consider extracting contract constants to configuration

The function uses hardcoded contract addresses and class hashes. Consider moving these to a configuration file or environment variables for better flexibility.

crates/katana/cli/src/node.rs (2)

Line range hint 1-31: Ohayo, sensei! Documentation and imports look good!

The file documentation and imports have been properly updated to reflect the new CLI-focused purpose of this module.


Line range hint 33-365: Ohayo, sensei! Consider using Option<bool> for boolean flags

The boolean flags silent and no_mining in NodeArgs might not handle cases where they are explicitly set to false in the config file. Since boolean flags default to false, it's challenging to distinguish between unset values and explicit false values.

Consider changing these fields to Option<bool> to differentiate between unset and set values:

 pub struct NodeArgs {
-    pub silent: bool,
-    pub no_mining: bool,
+    pub silent: Option<bool>,
+    pub no_mining: Option<bool>,

And update the merging logic in with_config_file:

-        if !self.silent {
+        if self.silent.is_none() {
             self.silent = config.silent.unwrap_or_default();
         }

-        if !self.no_mining {
+        if self.no_mining.is_none() {
             self.no_mining = config.no_mining.unwrap_or_default();
         }

Comment on lines +24 to +34
pub fn parse_seed(seed: &str) -> [u8; 32] {
let seed = seed.as_bytes();

if seed.len() >= 32 {
unsafe { *(seed[..32].as_ptr() as *const [u8; 32]) }
} else {
let mut actual_seed = [0u8; 32];
seed.iter().enumerate().for_each(|(i, b)| actual_seed[i] = *b);
actual_seed
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo sensei! Consider a safer implementation for seed parsing

The current implementation uses unsafe code which could lead to undefined behavior if the memory is not properly aligned. Consider using a safer alternative:

 pub fn parse_seed(seed: &str) -> [u8; 32] {
     let seed = seed.as_bytes();
 
     if seed.len() >= 32 {
-        unsafe { *(seed[..32].as_ptr() as *const [u8; 32]) }
+        let mut result = [0u8; 32];
+        result.copy_from_slice(&seed[..32]);
+        result
     } else {
         let mut actual_seed = [0u8; 32];
         seed.iter().enumerate().for_each(|(i, b)| actual_seed[i] = *b);
         actual_seed
     }
 }
📝 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
pub fn parse_seed(seed: &str) -> [u8; 32] {
let seed = seed.as_bytes();
if seed.len() >= 32 {
unsafe { *(seed[..32].as_ptr() as *const [u8; 32]) }
} else {
let mut actual_seed = [0u8; 32];
seed.iter().enumerate().for_each(|(i, b)| actual_seed[i] = *b);
actual_seed
}
}
pub fn parse_seed(seed: &str) -> [u8; 32] {
let seed = seed.as_bytes();
if seed.len() >= 32 {
let mut result = [0u8; 32];
result.copy_from_slice(&seed[..32]);
result
} else {
let mut actual_seed = [0u8; 32];
seed.iter().enumerate().for_each(|(i, b)| actual_seed[i] = *b);
actual_seed
}
}

Copy link
Collaborator

@Larkooo Larkooo left a comment

Choose a reason for hiding this comment

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

Looks good to me

Copy link

@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 (8)
crates/torii/cli/Cargo.toml (1)

18-20: Consider adding more testing utilities, sensei!

While assert_matches and camino are good choices, consider adding common testing utilities like:

  • test-case for parameterized tests
  • pretty_assertions for readable test output
crates/katana/core/src/service/messaging/mod.rs (1)

97-97: Ohayo sensei! The PartialEq addition looks good!

Adding PartialEq to MessagingConfig is a sensible change that aligns well with moving CLI args to separate crates, as it enables configuration comparison functionality. However, consider also adding Eq since the struct doesn't have any floating-point fields that would make equality non-transitive.

-#[derive(Debug, Default, Deserialize, Clone, Serialize, PartialEq)]
+#[derive(Debug, Default, Deserialize, Clone, Serialize, PartialEq, Eq)]
crates/torii/cli/src/args.rs (3)

12-12: Document DEFAULT_RPC_URL usage context

Ohayo sensei! Consider adding a doc comment explaining that this URL is for local development/testing purposes.

-pub const DEFAULT_RPC_URL: &str = "http://0.0.0.0:5050";
+/// Default RPC URL for local development/testing.
+/// In production environments, this should be overridden via CLI args or config file.
+pub const DEFAULT_RPC_URL: &str = "http://0.0.0.0:5050";

70-75: Enhance error handling with context

Consider adding context to the errors for better debugging.

 pub fn with_config_file(mut self) -> Result<Self> {
     let config: ToriiArgsConfig = if let Some(path) = &self.config {
-        toml::from_str(&std::fs::read_to_string(path)?)?
+        std::fs::read_to_string(path)
+            .map_err(|e| anyhow::anyhow!("Failed to read config file {}: {}", path.display(), e))?;
+            .and_then(|content| toml::from_str(&content)
+                .map_err(|e| anyhow::anyhow!("Failed to parse config file {}: {}", path.display(), e)))?
     } else {
         return Ok(self);
     };

188-312: Add negative test cases

The tests cover the happy path well, but consider adding tests for:

  • Invalid config file format
  • Missing config file
  • Invalid URLs
  • Invalid world addresses

Example test case:

#[test]
fn test_invalid_config_file() {
    let content = r#"
    invalid_toml_content
    "#;
    let path = std::env::temp_dir().join("invalid-config.toml");
    std::fs::write(&path, content).unwrap();

    let args = vec!["torii", "--config", path.to_str().unwrap()];
    let result = ToriiArgs::parse_from(args).with_config_file();
    assert!(result.is_err());
}
crates/katana/cli/src/options.rs (2)

Line range hint 61-88: Ohayo sensei! Consider validating CORS origins.

The ServerOptions struct is well-designed, but the http_cors_origins field might benefit from validation to ensure proper CORS origin format and security.

Consider adding a custom parser for CORS origins:

fn parse_cors_origins(s: &str) -> Result<Vec<String>, String> {
    let origins: Vec<String> = s.split(',')
        .map(|origin| origin.trim().to_string())
        .filter(|origin| !origin.is_empty())
        .collect();
    
    // Validate each origin
    for origin in &origins {
        if !origin.starts_with("http://") && !origin.starts_with("https://") && origin != "*" {
            return Err(format!("Invalid CORS origin: {}", origin));
        }
    }
    
    Ok(origins)
}

Then update the field definition:

#[arg(long = "http.cors_origins", value_parser = parse_cors_origins)]

338-350: Ohayo sensei! Consider adding documentation for default functions.

While the default functions are correctly implemented, they would benefit from documentation explaining their purpose and usage in the context of serde deserialization.

Add documentation like this:

/// Returns the default HTTP address for the RPC server.
/// Used by serde when deserializing configuration.
#[cfg(feature = "server")]
fn default_http_addr() -> IpAddr {
    DEFAULT_RPC_ADDR
}
crates/katana/cli/src/node.rs (1)

Line range hint 94-120: Add documentation for NodeArgsConfig fields

Ohayo! Consider adding documentation comments for each field to explain their purpose and expected values, especially for fields that have specific constraints or behaviors.

 #[derive(Debug, Serialize, Deserialize, Default)]
+/// Configuration structure that mirrors NodeArgs but with all fields optional
+/// for flexible configuration file support
 pub struct NodeArgsConfig {
+    /// When true, suppresses all startup output
     pub silent: Option<bool>,
+    /// When true, disables automatic and interval mining
     pub no_mining: Option<bool>,
     // ... add docs for other fields
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between da719b5 and c65649e.

📒 Files selected for processing (6)
  • crates/katana/cli/Cargo.toml (1 hunks)
  • crates/katana/cli/src/node.rs (13 hunks)
  • crates/katana/cli/src/options.rs (4 hunks)
  • crates/katana/core/src/service/messaging/mod.rs (1 hunks)
  • crates/torii/cli/Cargo.toml (1 hunks)
  • crates/torii/cli/src/args.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/katana/cli/Cargo.toml
🔇 Additional comments (10)
crates/torii/cli/Cargo.toml (3)

1-7: Ohayo! Package metadata looks great, sensei!

The package configuration follows Rust workspace best practices by inheriting common fields from the workspace while explicitly setting the package name.


8-17: Dependencies are well-organized, sensei!

All dependencies use workspace inheritance which is excellent for maintaining consistent versions across the project. The selected dependencies are appropriate for a CLI crate, covering argument parsing, error handling, and configuration management.


22-24: Verify the purpose of the empty server feature, sensei!

The "server" feature is currently empty but included in default features. Let's verify its intended usage.

✅ Verification successful

Ohayo, sensei!

The empty server feature is correctly utilized for conditional compilation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of the server feature in the codebase
echo "Searching for #[cfg(feature = \"server\")] usage..."
rg --type rust "cfg.*feature.*server" 

echo "\nSearching for conditional dependencies using the server feature..."
rg "server.*=" crates/torii/cli/Cargo.toml

Length of output: 3327

crates/torii/cli/src/args.rs (1)

18-67: Consider making world_address required

The world_address seems to be a critical parameter for indexing. Consider making it required unless there's a specific reason for it to be optional.

✅ Verification successful

Ohayo, sensei.

No need to make world_address required

The world_address is correctly handled as optional across the codebase, ensuring flexibility and robustness.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if world_address is used as required in other parts of the codebase
rg -A 5 "world_address" --type rust

Length of output: 60290

crates/katana/cli/src/options.rs (3)

15-15: Ohayo sensei! Clean import with proper feature gating.

The import of RPC constants is correctly feature-gated and well-organized.


Line range hint 89-98: Ohayo sensei! Clean Default implementation.

The Default implementation for ServerOptions is well-structured and properly uses the predefined constants.


Line range hint 61-350: Ohayo sensei! Verify server feature usage.

The server-related code is properly feature-gated, but let's verify the feature flag usage across the codebase.

✅ Verification successful

Ohayo sensei! Server feature usage is properly gated and declared.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of the "server" feature flag

# Check for any ungated server-related code
rg -l "DEFAULT_RPC|ServerOptions|http_addr|http_port|max_connections" | \
  xargs rg -L '#\[cfg\(feature = "server"\)\]'

# Check Cargo.toml files for proper feature declaration
fd Cargo.toml | xargs rg 'server.*=.*\['

Length of output: 1695

crates/katana/cli/src/node.rs (3)

Line range hint 379-386: Improve boolean flag merging logic

Ohayo! The current boolean flag merging logic might not correctly handle cases where flags are explicitly set to false in CLI arguments.

Consider changing the boolean fields to Option<bool> as suggested in the previous review. The current implementation:

if !self.silent {
    self.silent = config.silent.unwrap_or_default();
}

Cannot distinguish between "unset" and "explicitly set to false" in CLI args.


Line range hint 456-678: Test coverage looks comprehensive!

Ohayo, sensei! The test suite thoroughly covers:

  • Default configurations
  • Custom configurations
  • Gas price combinations
  • Config file and CLI argument interaction

Line range hint 170-179: Consider thread safety implications

Ohayo, sensei! The change from self to &self is good for reusability, but since this allows shared access, we should ensure thread safety if the NodeArgs instance might be accessed from multiple threads.

✅ Verification successful

Ohayo, sensei! Since no Arc or Mutex usages were found with NodeArgs, I'll further check if it's being accessed concurrently in other ways.


Ohayo, sensei! Verified that NodeArgs isn't accessed concurrently without synchronization.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential concurrent usage of NodeArgs
rg -A 5 "NodeArgs.*=.*Arc::new" 
rg -A 5 "NodeArgs.*=.*Mutex::new"

Length of output: 69


Script:

#!/bin/bash
# Search for NodeArgs being used within tokio::spawn blocks
rg 'tokio::spawn\s*\(' -A 5 | rg 'NodeArgs'

# Search for NodeArgs being moved into async blocks
rg 'async\s*\|' -A 5 | rg 'NodeArgs'

Length of output: 80

Comment on lines +157 to +161
let mut config =
ToriiArgsConfig { world_address: args.world_address, ..Default::default() };

config.world_address = args.world_address;
config.rpc =
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove redundant world_address assignment

The world_address is assigned twice:

  1. In the struct initialization
  2. Immediately after initialization
 let mut config =
-    ToriiArgsConfig { world_address: args.world_address, ..Default::default() };
+    ToriiArgsConfig { ..Default::default() };

 config.world_address = args.world_address;
📝 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
let mut config =
ToriiArgsConfig { world_address: args.world_address, ..Default::default() };
config.world_address = args.world_address;
config.rpc =
let mut config =
ToriiArgsConfig { ..Default::default() };
config.world_address = args.world_address;
config.rpc =

Comment on lines 57 to 59
/// Configuration file
#[arg(long)]
config: Option<PathBuf>,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance config file error handling

Ohayo, sensei! The config file handling could be more robust with better error messages.

 /// Configuration file
 #[arg(long)]
-config: Option<PathBuf>,
+config: Option<PathBuf>,
+
+#[arg(skip)]
+config_loaded: bool,

And in with_config_file:

 let config: NodeArgsConfig = if let Some(path) = &self.config {
-    toml::from_str(&std::fs::read_to_string(path)?)?
+    if !path.exists() {
+        return Err(anyhow::anyhow!("Config file not found: {}", path.display()));
+    }
+    let content = std::fs::read_to_string(path)
+        .with_context(|| format!("Failed to read config file: {}", path.display()))?;
+    toml::from_str(&content)
+        .with_context(|| format!("Failed to parse TOML from config file: {}", path.display()))?

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@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: 1

🧹 Outside diff range and nitpick comments (2)
crates/katana/cli/src/node.rs (2)

121-165: Consider enhancing error handling in TryFrom implementation.

Ohayo, sensei! While the implementation is good, we could improve error handling by providing more context when the config merge fails.

 impl TryFrom<NodeArgs> for NodeArgsConfig {
     type Error = anyhow::Error;
 
     fn try_from(args: NodeArgs) -> Result<Self> {
         // Ensure the config file is merged with the CLI arguments.
-        let args = args.with_config_file()?;
+        let args = args.with_config_file()
+            .with_context(|| "failed to merge config file with CLI arguments")?;

256-265: Consider consolidating feature-gated code blocks.

Ohayo, sensei! The feature-gated code for server and metrics configurations is spread across multiple locations. Consider consolidating these into a single module to improve maintainability.

Consider moving all server-related feature-gated code into a separate module like server_config.rs:

#[cfg(feature = "server")]
mod server_config {
    pub fn build_rpc_config(args: &NodeArgs) -> RpcConfig {
        RpcConfig {
            apis,
            port: args.server.http_port,
            addr: args.server.http_addr,
            max_connections: args.server.max_connections,
            cors_origins: args.server.http_cors_origins.clone(),
        }
    }

    pub fn build_metrics_config(args: &NodeArgs) -> Option<MetricsConfig> {
        if args.metrics.metrics {
            Some(MetricsConfig {
                addr: args.metrics.metrics_addr,
                port: args.metrics.metrics_port,
            })
        } else {
            None
        }
    }
}

Also applies to: 354-362

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c65649e and f9523ee.

📒 Files selected for processing (1)
  • crates/katana/cli/src/node.rs (13 hunks)
🔇 Additional comments (2)
crates/katana/cli/src/node.rs (2)

57-59: LGTM! Config file support added.

The addition of the config file option enhances flexibility in node configuration.


168-168: LGTM! Method signature changes improve efficiency.

The change from self to &self in execute and start_node methods prevents unnecessary moves, allowing for better resource management.

Also applies to: 177-177

@@ -644,7 +580,7 @@ mod test {
let config = NodeArgs::parse_from([
"katana",
"--genesis",
"./tests/test-data/genesis.json",
"./test-data/genesis.json",
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Issue Found: Test data path resolution may be incorrect.

Ohayo, sensei! No valid genesis file found in the specified test data paths.

  • ./crates/katana/primitives/src/genesis/test-genesis.json
  • ./crates/katana/cli/test-data/genesis.json
🔗 Analysis chain

Verify test data path resolution.

Ohayo, sensei! The test is using a hardcoded path to test data. This might cause issues when running tests from different directories.

Also applies to: 639-639

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if test data exists and is accessible
fd -t f "genesis.json" -x echo "Found test data at: {}"

# Verify the content of genesis.json files
fd -t f "genesis.json" -x cat {} | jq -r 'if (.number == 0 and .parent_hash == "0x999" and .timestamp == 5123512314) then "Valid genesis file found at: {}" else empty end'

Length of output: 369

Copy link

@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: 1

🧹 Outside diff range and nitpick comments (2)
bin/torii/src/main.rs (2)

32-32: Ohayo sensei! Clean architectural separation achieved!

The migration of CLI arguments to torii-cli crate aligns perfectly with the modular design principles. This separation of concerns will make the codebase more maintainable and reusable.


Line range hint 47-209: Ohayo sensei! Consider further modularization of service initialization!

While moving CLI args to a separate crate was a great first step, the main function is still handling multiple responsibilities. Consider extracting service initialization into a dedicated builder or factory pattern.

This could look like:

struct ToriiServer {
    engine: Engine<Arc<JsonRpcClient<HttpTransport>>>,
    proxy: Arc<Proxy>,
    graphql: GraphQLServer,
    grpc: GrpcServer,
    relay: Relay,
}

impl ToriiServer {
    async fn new(args: ToriiArgs) -> Result<Self> {
        // Current initialization logic moved here
    }
    
    async fn start(self) -> Result<()> {
        // Current service spawning logic moved here
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let args = ToriiArgs::parse().with_config_file()?;
    let server = ToriiServer::new(args).await?;
    server.start().await
}

This would:

  1. Make the code more testable
  2. Separate initialization from runtime concerns
  3. Make it easier to modify individual services
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f9523ee and d6b3b67.

📒 Files selected for processing (1)
  • bin/torii/src/main.rs (2 hunks)

Comment on lines +79 to +86
let database_path = if let Some(db_dir) = args.db_dir {
// Create the directory if it doesn't exist
std::fs::create_dir_all(&db_dir)?;
// Set the database file path inside the directory
db_dir.join("torii.db")
} else {
tempfile.path().to_path_buf()
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ohayo sensei! Let's enhance the database path handling robustness!

The current implementation could benefit from additional error handling and validation:

  1. Check directory permissions before creation
  2. Validate path is writable
  3. Handle potential race conditions in directory creation

Consider this enhanced implementation:

     let database_path = if let Some(db_dir) = args.db_dir {
-        // Create the directory if it doesn't exist
-        std::fs::create_dir_all(&db_dir)?;
-        // Set the database file path inside the directory
-        db_dir.join("torii.db")
+        // First check if directory exists and is writable
+        if db_dir.exists() && !db_dir.is_dir() {
+            return Err(anyhow::anyhow!("Database path exists but is not a directory"));
+        }
+        
+        // Create directory with specific permissions
+        std::fs::create_dir_all(&db_dir)
+            .map_err(|e| anyhow::anyhow!("Failed to create database directory: {}", e))?;
+            
+        // Verify directory is writable
+        let db_path = db_dir.join("torii.db");
+        std::fs::OpenOptions::new()
+            .write(true)
+            .create(true)
+            .open(&db_path)
+            .map_err(|e| anyhow::anyhow!("Database path is not writable: {}", e))?;
+            
+        db_path
     } else {
         tempfile.path().to_path_buf()
     };
📝 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
let database_path = if let Some(db_dir) = args.db_dir {
// Create the directory if it doesn't exist
std::fs::create_dir_all(&db_dir)?;
// Set the database file path inside the directory
db_dir.join("torii.db")
} else {
tempfile.path().to_path_buf()
};
let database_path = if let Some(db_dir) = args.db_dir {
// First check if directory exists and is writable
if db_dir.exists() && !db_dir.is_dir() {
return Err(anyhow::anyhow!("Database path exists but is not a directory"));
}
// Create directory with specific permissions
std::fs::create_dir_all(&db_dir)
.map_err(|e| anyhow::anyhow!("Failed to create database directory: {}", e))?;
// Verify directory is writable
let db_path = db_dir.join("torii.db");
std::fs::OpenOptions::new()
.write(true)
.create(true)
.open(&db_path)
.map_err(|e| anyhow::anyhow!("Database path is not writable: {}", e))?;
db_path
} else {
tempfile.path().to_path_buf()
};

Copy link

@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: 3

🧹 Outside diff range and nitpick comments (11)
crates/katana/cli/src/lib.rs (1)

3-6: Clean module organization aligning with the refactoring goals!

The module structure nicely separates concerns:

  • args: Core argument handling
  • file: Configuration file management
  • options: CLI options
  • utils: Shared utilities

This organization supports the PR's goal of making CLI arguments more modular and reusable.

Consider documenting each module's responsibility in the module declarations to help future contributors understand the codebase structure better.

crates/katana/cli/src/file.rs (3)

10-27: Ohayo sensei! Consider adding field-level documentation.

While the struct has a high-level doc comment, adding documentation for individual fields would improve the configuration's usability and maintainability. This is especially important for a configuration struct that will be used across different crates.

Example improvement:

 /// Node arguments configuration file.
 #[derive(Debug, Serialize, Deserialize, Default)]
 pub struct NodeArgsConfig {
+    /// When true, disables block mining
     pub no_mining: Option<bool>,
+    /// Time between blocks in milliseconds
     pub block_time: Option<u64>,
     // ... add docs for other fields

30-33: Enhance error context for better debugging.

The error handling could be more descriptive to help users identify configuration issues more easily.

Consider this improvement:

 pub fn read(path: impl AsRef<Path>) -> Result<Self> {
-    let file = std::fs::read_to_string(path)?;
-    Ok(toml::from_str(&file)?)
+    let path = path.as_ref();
+    let file = std::fs::read_to_string(path)
+        .map_err(|e| anyhow::anyhow!("Failed to read config file {}: {}", path.display(), e))?;
+    toml::from_str(&file)
+        .map_err(|e| anyhow::anyhow!("Failed to parse config file {}: {}", path.display(), e))
 }

53-62: Consider extracting the default value comparison pattern.

The repeated pattern for handling default values could be simplified using a helper function.

Consider this improvement:

+fn option_if_not_default<T: Default + PartialEq>(value: T) -> Option<T> {
+    if value == T::default() { None } else { Some(value) }
+}
+
 impl TryFrom<NodeArgs> for NodeArgsConfig {
     // ...
-    node_config.logging =
-        if args.logging == LoggingOptions::default() { None } else { Some(args.logging) };
-    node_config.starknet =
-        if args.starknet == StarknetOptions::default() { None } else { Some(args.starknet) };
+    node_config.logging = option_if_not_default(args.logging);
+    node_config.starknet = option_if_not_default(args.starknet);
     // ... apply to other fields
crates/katana/cli/src/utils.rs (3)

36-41: Ohayo sensei! Consider adding file existence check

The function should verify if the file exists before attempting to load it to provide a more user-friendly error message.

 pub fn parse_genesis(value: &str) -> Result<Genesis> {
     let path = PathBuf::from(shellexpand::full(value)?.into_owned());
+    if !path.exists() {
+        anyhow::bail!("Genesis file not found: {}", path.display());
+    }
     let genesis = Genesis::try_from(GenesisJson::load(path)?)?;
     Ok(genesis)
 }

43-51: Ohayo sensei! Enhance error message for block number parsing

Consider providing a more descriptive error message that includes the invalid value.

-        let num = value.parse::<BlockNumber>().context("could not parse block number")?;
+        let num = value.parse::<BlockNumber>()
+            .with_context(|| format!("invalid block number: {}", value))?;

127-161: Ohayo sensei! Consider extracting template strings

The hardcoded template strings could be moved to constants or a separate configuration file for better maintainability.

+const CONTRACT_TEMPLATE: &str = r"
+| Contract        | {}
+| Address         | {}
+| Class Hash      | {:#064x}
+";
+
 fn print_genesis_contracts(chain: &ChainSpec, account_class_hash: Option<ClassHash>) {
     println!(
-        r"
-| Contract        | ETH Fee Token
-| Address         | {}
-| Class Hash      | {:#064x}
-
-| Contract        | STRK Fee Token
-| Address         | {}
-| Class Hash      | {:#064x}",
+        concat!(
+            CONTRACT_TEMPLATE,
+            "\n",
+            CONTRACT_TEMPLATE
+        ),
+        "ETH Fee Token",
         chain.fee_contracts.eth,
         DEFAULT_LEGACY_ERC20_CLASS_HASH,
+        "STRK Fee Token",
         chain.fee_contracts.strk,
         DEFAULT_LEGACY_ERC20_CLASS_HASH
     );
crates/katana/cli/src/args.rs (4)

Line range hint 300-316: Potential issue with merging boolean options in with_config_file method

Ohayo sensei!

In the with_config_file method, the logic for merging boolean fields like no_mining may override command-line arguments unintentionally. Specifically:

if !self.no_mining {
    self.no_mining = config.no_mining.unwrap_or_default();
}

If self.no_mining is false (mining is enabled via CLI), it will be set to the value from the config file, possibly overriding the user's intent. Consider checking if the CLI option was provided instead.

You might update the merging logic to:

if matches!(self.no_mining, false) && config.no_mining.is_some() {
    self.no_mining = config.no_mining.unwrap_or_default();
}

Line range hint 375-512: Add unit tests for the new configuration merging logic

Ohayo sensei!

To ensure the robustness of the with_config_file method, it would be beneficial to add unit tests that cover various scenarios of merging command-line arguments with configuration files. This will help prevent regression and ensure that precedence rules are correctly applied.


508-508: Check the validity of the genesis file path in tests

Ohayo sensei!

In the test cases, the path to the genesis file is set to "./test-data/genesis.json". Please ensure that this file exists at the specified location in the test environment to prevent test failures due to missing files.


74-78: Conditional compilation may affect CLI options availability

Ohayo sensei!

The metrics and server options are conditionally compiled with #[cfg(feature = "server")]. Be aware that when the server feature is disabled, these options won't be available, which might cause confusion if users expect these options in all builds.

Consider providing feedback or documentation to inform users about the feature-dependent availability of these options.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d6b3b67 and 8cb1119.

📒 Files selected for processing (4)
  • crates/katana/cli/src/args.rs (13 hunks)
  • crates/katana/cli/src/file.rs (1 hunks)
  • crates/katana/cli/src/lib.rs (1 hunks)
  • crates/katana/cli/src/utils.rs (1 hunks)
🔇 Additional comments (9)
crates/katana/cli/src/lib.rs (1)

1-1: Ohayo sensei! Nice compiler attribute for dependency hygiene!

The warn(unused_crate_dependencies) attribute is a good practice to keep dependencies clean in production code while allowing flexibility during testing.

crates/katana/cli/src/file.rs (1)

40-41: Verify config file merging implementation.

The comment suggests that config file is merged with CLI arguments, but we should verify this behavior in the with_config_file method.

✅ Verification successful

Ohayo, sensei! I'm generating a new script to search for any instances of with_config_file in the codebase. Let's see what we find! 🌅


Ohayo, sensei! Verified that the with_config_file method correctly merges the config file with the CLI arguments. 🌟


🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the with_config_file implementation
ast-grep --pattern 'fn with_config_file($$$) {
  $$$
}'

Length of output: 57


Script:

#!/bin/bash
# Search for any definition or usage of `with_config_file`
rg 'with_config_file' --context 3

Length of output: 4114

crates/katana/cli/src/utils.rs (2)

24-34: Ohayo sensei! The previous review comment about unsafe seed parsing is still valid

The current implementation uses unsafe code which could lead to undefined behavior. Please refer to the previous review comment for the suggested safer implementation.


53-80: Ohayo sensei! Clean enum implementation

The LogFormat enum and its trait implementations are well-structured and follow Rust best practices.

crates/katana/cli/src/args.rs (5)

Line range hint 100-109: Changing method receivers to &self may affect future modifications

Ohayo sensei!

The methods execute and start_node have been changed to take &self instead of consuming self. While this is efficient, ensure that these methods won't need ownership of self in the future, especially if modifications or ownership transfers are required.


26-27: Verify the existence and accessibility of NodeArgsConfig

Ohayo sensei!

Ensure that the NodeArgsConfig struct in crate::file is properly defined and accessible. This will prevent potential compilation errors due to missing modules or incorrect paths.


188-201: Ensure the RpcConfig defaults are appropriate when server feature is disabled

Ohayo sensei!

In the rpc_config method, when the server feature is disabled, default values are used for the RpcConfig. Verify that these defaults are appropriate and won't lead to issues like binding to unintended addresses or ports.


286-294: Confirm that metrics are appropriately disabled without the server feature

Ohayo sensei!

The metrics_config function returns None when the server feature is not enabled. Ensure that this doesn't inadvertently disable necessary metrics or conflict with other components expecting metrics to be available.


33-33: Deriving Clone for NodeArgs

Ohayo sensei!

Good job on adding Clone to the NodeArgs struct derivations. This will facilitate easier copying of instances when needed.

Comment on lines +8 to +9
pub use args::NodeArgs;
pub use options::*;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Ohayo, sensei!

Missing NodeArgs definition in args.rs!

The NodeArgs struct is not found in the crates/katana/cli/src/args.rs.

  • Ensure that the NodeArgs struct is properly defined within args.rs.
🔗 Analysis chain

Clean and focused re-exports!

The selective re-export of NodeArgs and wildcard re-export of options provide a good balance between explicit and convenient public API design.

Let's verify the module structure and exports:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the module structure and exports

# Check if all declared modules exist
for module in args file options utils; do
    echo "Checking module: $module"
    fd --type f "^${module}\.rs$" "crates/katana/cli/src"
done

# Look for NodeArgs definition
ast-grep --pattern 'struct NodeArgs {
  $$$
}'

# Check options module exports
rg --type rust "pub (struct|enum|fn|type|const|static)" "crates/katana/cli/src/options.rs"

Length of output: 1255

Comment on lines +194 to +203
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn parse_genesis_file() {
let path = "./test-data/genesis.json";
parse_genesis(path).unwrap();
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ohayo sensei! Enhance test coverage

Consider:

  1. Adding test cases for invalid genesis files
  2. Documenting the required test data file structure
  3. Adding tests for other utility functions
 #[cfg(test)]
 mod tests {
     use super::*;
 
     #[test]
     fn parse_genesis_file() {
         let path = "./test-data/genesis.json";
         parse_genesis(path).unwrap();
     }
+
+    #[test]
+    fn parse_genesis_file_not_found() {
+        assert!(parse_genesis("./non-existent.json").is_err());
+    }
+
+    #[test]
+    fn test_parse_block_hash_or_number() {
+        assert!(matches!(
+            parse_block_hash_or_number("0x1234").unwrap(),
+            BlockHashOrNumber::Hash(_)
+        ));
+        assert!(matches!(
+            parse_block_hash_or_number("1234").unwrap(),
+            BlockHashOrNumber::Num(1234)
+        ));
+    }
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +58 to +60
/// Configuration file
#[arg(long)]
config: Option<PathBuf>,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

The config field should be public to ensure accessibility

Ohayo sensei!

I noticed that the config field in the NodeArgs struct is not declared as pub, unlike the other fields. This might lead to issues when trying to access it from outside the struct. Consider adding the pub keyword to make it public.

Apply this diff to fix the issue:

 /// Configuration file
 #[arg(long)]
- config: Option<PathBuf>,
+ pub config: Option<PathBuf>,
📝 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
/// Configuration file
#[arg(long)]
config: Option<PathBuf>,
/// Configuration file
#[arg(long)]
pub config: Option<PathBuf>,

@glihm glihm merged commit cbdd2f0 into main Nov 13, 2024
12 of 14 checks passed
@glihm glihm deleted the refactor/args-cli branch November 13, 2024 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants