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

feat(katana-rpc): rpc server builder #2788

Merged
merged 5 commits into from
Dec 10, 2024
Merged

feat(katana-rpc): rpc server builder #2788

merged 5 commits into from
Dec 10, 2024

Conversation

kariy
Copy link
Member

@kariy kariy commented Dec 9, 2024

basically encapsulating most of the rpc building logic into a struct, and implement a Cors struct to manage how we handle wildcard (ie *) in the allowed origins list. see the comment in:

/// Holds configuration for how to set the [`Access-Control-Allow-Origin`][mdn] header.
///
/// This is just a lightweight wrapper of [`cors::AllowOrigin`] that doesn't fail when a wildcard,
/// `*`, is passed to [`cors::AllowOrigin::list`]. See [`cors::AllowOrigin`] for more details.
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
#[derive(Debug, Clone, Default)]
pub struct AllowOrigins(cors::AllowOrigin);

this pr also move where we handle the parsing of the origins to the cli phase.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced CORS configuration options for enhanced handling of cross-origin requests.
    • Added health check endpoint for the JSON-RPC server.
    • New RPC server structure with improved error handling and configuration capabilities.
    • Enhanced CORS middleware with flexible configuration methods.
  • Bug Fixes

    • Updated CORS origins handling to ensure more robust and type-safe configurations.
  • Documentation

    • Enhanced test coverage for CORS origins parsing and health check functionality.
  • Chores

    • Added new dependencies to improve HTTP handling and JSON serialization capabilities.

Copy link

coderabbitai bot commented Dec 9, 2024

Walkthrough

Ohayo, sensei! This pull request introduces significant changes across various files, primarily focusing on the handling of CORS (Cross-Origin Resource Sharing) configurations. Key modifications include updating the RpcConfig to initialize cors_origins as an empty vector, enhancing type safety with HeaderValue, and adding new serialization and deserialization functions. A new CORS middleware implementation is also introduced, along with a health check endpoint for the RPC server. Additionally, several dependencies are added to support these functionalities.

Changes

File Path Change Summary
crates/dojo/test-utils/src/sequencer.rs Updated cors_origins in RpcConfig from None to Vec::new().
crates/katana/cli/Cargo.toml Added dependency katana-rpc.workspace = true.
crates/katana/cli/src/args.rs Added test function parse_cors_origins and imported HeaderValue.
crates/katana/cli/src/options.rs Changed http_cors_origins from Option<Vec<String>> to Vec<HeaderValue>.
crates/katana/cli/src/utils.rs Added serialize_cors_origins and deserialize_cors_origins functions.
crates/katana/node/src/config/rpc.rs Updated cors_origins in RpcConfig from Option<Vec<String>> to Vec<HeaderValue>.
crates/katana/node/src/lib.rs Replaced RpcServer with RpcServerHandle and updated spawn function signature.
crates/katana/rpc/rpc/Cargo.toml Added dependencies: http, serde_json, tower, and tower-http, all with workspace = true.
crates/katana/rpc/rpc/src/cors.rs Introduced new CORS middleware implementation with Cors and AllowOrigins structs.
crates/katana/rpc/rpc/src/health.rs Added HealthCheck struct for health check functionality.
crates/katana/rpc/rpc/src/lib.rs Introduced RpcServerHandle, RpcServer, and new methods for server management and configuration.

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 generate docstrings to generate docstrings for this PR. (Experiment)
  • @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 (5)
crates/katana/rpc/rpc/src/lib.rs (1)

117-132: Ohayo sensei! Consider refactoring to reduce code duplication in the start() method.

The blocks of code for starting the server with and without metrics are similar. Extracting the common logic into a helper function can improve maintainability and readability.

Here's a suggested refactor:

 pub async fn start(&self, addr: SocketAddr) -> Result<RpcServerHandle, Error> {
     let mut modules = self.module.clone();

     let health_check_proxy = if self.health_check {
         modules.merge(HealthCheck)?;
         Some(HealthCheck::proxy())
     } else {
         None
     };

     let middleware = ServiceBuilder::new()
         .option_layer(self.cors.clone())
         .option_layer(health_check_proxy)
         .timeout(Duration::from_secs(20));

     let builder = ServerBuilder::new()
         .set_middleware(middleware)
         .set_host_filtering(AllowHosts::Any)
         .max_connections(self.max_connections);

-    let handle = if self.metrics {
-        let logger = RpcServerMetrics::new(&modules);
-        let server = builder.set_logger(logger).build(addr).await?;
-
-        let addr = server.local_addr()?;
-        let handle = server.start(modules)?;
-
-        RpcServerHandle { addr, handle }
-    } else {
-        let server = builder.build(addr).await?;
-
-        let addr = server.local_addr()?;
-        let handle = server.start(modules)?;
-
-        RpcServerHandle { addr, handle }
-    };
+    let server = if self.metrics {
+        let logger = RpcServerMetrics::new(&modules);
+        builder.set_logger(logger).build(addr).await?
+    } else {
+        builder.build(addr).await?
+    };
+
+    let addr = server.local_addr()?;
+    let handle = server.start(modules)?;
+
+    let handle = RpcServerHandle { addr, handle };

     info!(target: "rpc", %addr, "RPC server started.");

     Ok(handle)
 }
crates/katana/node/src/config/rpc.rs (1)

33-33: Consider documenting CORS configuration

Sensei, please consider adding documentation for the cors_origins field to explain:

  • Expected format of CORS origins
  • How to configure common scenarios
  • Impact of empty vector vs. previous None behavior
crates/katana/rpc/rpc/Cargo.toml (1)

13-13: Ohayo! Clean dependency additions for RPC enhancement

The new dependencies are well-chosen for building a robust RPC server:

  • http: Core HTTP types
  • tower: Middleware framework
  • tower-http: HTTP-specific middleware including CORS
  • serde_json: JSON serialization

Consider documenting the middleware stack architecture in the README or module documentation, showing how these components work together in the RPC server builder.

Also applies to: 25-25, 29-30

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

195-220: Ohayo, sensei! The CORS serialization implementation looks solid!

The implementation is well-structured with proper error handling. A small suggestion to make the code more robust:

Consider adding debug context to the error messages to make troubleshooting easier:

 pub fn serialize_cors_origins<S>(values: &[HeaderValue], serializer: S) -> Result<S::Ok, S::Error>
 where
     S: Serializer,
 {
     let string = values
         .iter()
         .map(|v| v.to_str())
         .collect::<Result<Vec<_>, _>>()
-        .map_err(serde::ser::Error::custom)?
+        .map_err(|e| serde::ser::Error::custom(format!("Invalid header value: {}", e)))?
         .join(",");

     serializer.serialize_str(&string)
 }
crates/katana/cli/src/args.rs (1)

620-637: Ohayo! The CORS origins test looks solid, sensei!

The test effectively validates:

  • Multiple origin parsing
  • Support for wildcard (*)
  • Both HTTP and HTTPS origins
  • Proper HeaderValue conversion

However, consider adding a test case for invalid CORS origins to ensure proper error handling.

Add this test case:

 #[test]
 #[cfg(feature = "server")]
 fn parse_cors_origins() {
     let config = NodeArgs::parse_from([
         "katana",
         "--http.cors_origins",
         "*,http://localhost:3000,https://example.com",
     ])
     .config()
     .unwrap();

     let cors_origins = config.rpc.cors_origins;

     assert_eq!(cors_origins.len(), 3);
     assert!(cors_origins.contains(&HeaderValue::from_static("*")));
     assert!(cors_origins.contains(&HeaderValue::from_static("http://localhost:3000")));
     assert!(cors_origins.contains(&HeaderValue::from_static("https://example.com")));
+
+    // Test invalid CORS origin
+    let result = NodeArgs::parse_from([
+        "katana",
+        "--http.cors_origins",
+        "not-a-valid-origin",
+    ])
+    .config();
+
+    assert!(result.is_err());
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 0d29ae3 and c000ff4.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • crates/dojo/test-utils/src/sequencer.rs (1 hunks)
  • crates/katana/cli/Cargo.toml (1 hunks)
  • crates/katana/cli/src/args.rs (2 hunks)
  • crates/katana/cli/src/options.rs (3 hunks)
  • crates/katana/cli/src/utils.rs (2 hunks)
  • crates/katana/node/src/config/rpc.rs (3 hunks)
  • crates/katana/node/src/lib.rs (5 hunks)
  • crates/katana/rpc/rpc/Cargo.toml (2 hunks)
  • crates/katana/rpc/rpc/src/cors.rs (1 hunks)
  • crates/katana/rpc/rpc/src/health.rs (1 hunks)
  • crates/katana/rpc/rpc/src/lib.rs (1 hunks)
🔇 Additional comments (7)
crates/katana/rpc/rpc/src/cors.rs (1)

1-138: Ohayo sensei! Excellent implementation of the CORS middleware.

The code is well-structured and provides flexible configuration options for CORS policies. This will greatly enhance the security and usability of the RPC server.

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

13-13: Ohayo! LGTM - Clean workspace dependency addition

The addition of katana-rpc as a workspace dependency aligns perfectly with the RPC server builder feature, sensei!

crates/katana/node/src/config/rpc.rs (2)

4-4: Ohayo! New import looks good

Clean import of HeaderValue for enhanced CORS handling.


33-33: Verify breaking changes in CORS configuration

The change from Option<Vec<String>> to Vec<HeaderValue> for cors_origins is a breaking change that might affect existing configurations and code.

Also applies to: 46-46

crates/dojo/test-utils/src/sequencer.rs (1)

121-121: LGTM! The CORS origins initialization is correct.

The change aligns well with the new CORS handling approach across the codebase.

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

92-97: The CORS configuration changes look great!

The switch to Vec<HeaderValue> with proper serialization/deserialization handling improves type safety and robustness. The default implementation with an empty vector is also appropriate.

Also applies to: 119-119

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

400-400: Ohayo! LGTM on the HeaderValue import, sensei!

The addition of HeaderValue from katana_rpc::cors enhances type safety for CORS origin handling.


let builder = ServerBuilder::new()
.set_middleware(middleware)
.set_host_filtering(AllowHosts::Any)
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! Please verify the use of AllowHosts::Any in host filtering.

Using AllowHosts::Any allows requests from any host, which may pose security risks in production environments. Consider restricting allowed hosts or making this configurable to enhance security.

Comment on lines +268 to +269
.allow_methods([Method::POST, Method::GET])
.allow_headers([hyper::header::CONTENT_TYPE, "argent-client".parse().unwrap(), "argent-version".parse().unwrap()]);
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! Avoid using .unwrap() when parsing header values.

Using .unwrap() may cause the application to panic if the parsing fails. Consider handling the potential error or using .expect() with a meaningful message.

Apply this diff to handle the parsing result:

 let cors = Cors::new()
     .allow_origins(config.cors_origins.clone())
     // Allow `POST` and `GET` methods when accessing the resource
     .allow_methods([Method::POST, Method::GET])
     .allow_headers([
         hyper::header::CONTENT_TYPE,
-        "argent-client".parse().unwrap(),
-        "argent-version".parse().unwrap(),
+        HeaderValue::from_static("argent-client"),
+        HeaderValue::from_static("argent-version"),
     ]);
📝 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
.allow_methods([Method::POST, Method::GET])
.allow_headers([hyper::header::CONTENT_TYPE, "argent-client".parse().unwrap(), "argent-version".parse().unwrap()]);
.allow_methods([Method::POST, Method::GET])
.allow_headers([hyper::header::CONTENT_TYPE, HeaderValue::from_static("argent-client"), HeaderValue::from_static("argent-version")]);

impl From<HealthCheck> for Methods {
fn from(_: HealthCheck) -> Self {
let mut module = RpcModule::new(());
module.register_method(HealthCheck::METHOD, |_, _| Ok(json!({ "health": true }))).unwrap();
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! Handle potential errors when registering methods.

Using .unwrap() may cause the server to panic if the method registration fails. Consider handling the error gracefully or propagating it appropriately.

Apply this diff to handle the error:

 module.register_method(HealthCheck::METHOD, |_, _| Ok(json!({ "health": true })))?;
📝 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
module.register_method(HealthCheck::METHOD, |_, _| Ok(json!({ "health": true }))).unwrap();
module.register_method(HealthCheck::METHOD, |_, _| Ok(json!({ "health": true })))?;

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 (1)
crates/katana/rpc/rpc/src/cors.rs (1)

13-59: Consider adding validation and more configuration options, sensei!

While the implementation is solid, consider these enhancements:

  1. Add validation for malformed origins in the builder methods
  2. Consider adding methods for other CORS headers like max-age and expose-headers
  3. Add a method to configure allow_credentials

Example enhancement:

pub fn allow_credentials(self, allow: bool) -> Self {
    Self(self.0.allow_credentials(allow))
}

pub fn max_age(self, max_age: Duration) -> Self {
    Self(self.0.max_age(max_age))
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c000ff4 and e69db8f.

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

1-11: Ohayo sensei! Clean and well-structured imports and struct definition.

The imports are appropriate, and the documentation follows Rust conventions. The wrapper pattern for Cors struct is a good choice for encapsulating the CorsLayer functionality.


61-138: Consider additional origin validation and security measures.

The wildcard handling is clever, but consider these security enhancements:

  1. Add validation for malformed origin values
  2. Consider logging when converting to wildcard mode
  3. Add documentation about security implications of using wildcards

Also, verify that the origin parsing aligns with the RFC 6454 specification.

✅ Verification successful

Let me analyze the actual implementation and validation patterns before making security recommendations.


Let me check how CORS is actually implemented and configured before making any security recommendations, sensei!


The CORS implementation is secure and well-designed

Ohayo sensei! After reviewing the implementation, I can confirm that the CORS handling is actually quite robust and secure:

  1. The code properly delegates to the battle-tested tower-http CORS implementation
  2. The wildcard handling in AllowOrigins::list is intentional and follows best practices by converting any wildcard presence into AllowOrigin::any()
  3. The implementation provides multiple secure configuration options:
    • exact() for strict single-origin policies
    • mirror_request() for dynamic origin validation
    • list() with proper wildcard detection
    • Clear documentation about security implications of permissive modes

The original review concerns about additional validation were unnecessary as the implementation correctly relies on the underlying tower-http crate's validation mechanisms.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for origin validation patterns in the codebase
rg -A 3 'origin.*validate|validate.*origin'

# Look for any security-related comments about CORS
rg -A 3 'SECURITY:.*CORS|TODO:.*CORS|FIXME:.*CORS'

Length of output: 98


Script:

#!/bin/bash
# Let's check how HeaderValue is used and validated in the codebase
ast-grep --pattern 'HeaderValue::from_str($$$)'

# Check for any CORS-related tests or validation
rg -l 'cors|CORS' --type rust

# Look for any origin-related code in test files
rg 'origin' --type rust -g '*test*.rs' -A 3

# Check if there's any validation in the tower-http cors module being used
ast-grep --pattern 'impl $_ for AllowOrigin'

Length of output: 729


Script:

#!/bin/bash
# Let's examine the tower-http cors module usage
rg -A 5 "use tower_http::cors" --type rust

# Check how CORS is configured in the actual server setup
rg -A 10 "cors::" --type rust

# Look for any CORS-related tests
rg -A 5 "test.*cors|cors.*test" --type rust -i

Length of output: 15047

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

#[test]
fn wildcard_in_list() {
let origins = vec![
HeaderValue::from_static("http://example.com"),
HeaderValue::from_static("*"),
HeaderValue::from_static("http://other.com"),
];

let _ = AllowOrigins::list(origins);
}
}
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! Let's enhance the test coverage, sensei!

The current test suite only covers the basic wildcard scenario. Consider adding tests for:

  1. Invalid origin formats
  2. Multiple wildcards in the list
  3. Empty origin list
  4. Various From implementations
  5. Builder pattern methods

Example test additions:

#[test]
fn test_invalid_origin_format() {
    let origins = vec![
        HeaderValue::from_static("invalid-origin"),
        HeaderValue::from_static("http://valid.com"),
    ];
    let cors = AllowOrigins::list(origins);
    // Assert expected behavior
}

#[test]
fn test_builder_pattern() {
    let cors = Cors::new()
        .allow_origins(vec![HeaderValue::from_static("http://example.com")])
        .allow_methods(vec![http::Method::GET]);
    // Assert configuration
}

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 (4)
crates/katana/rpc/rpc/src/cors.rs (1)

61-102: Consider adding origin validation, sensei!

While the wildcard handling is solid, consider adding validation for origin format in the list method. Invalid origin formats could cause issues at runtime.

 pub fn list<I>(origins: I) -> Self
 where
     I: IntoIterator<Item = HeaderValue>,
 {
     let origins = origins.into_iter().collect::<Vec<_>>();
+    // Validate origin format
+    for origin in &origins {
+        if let Ok(s) = origin.to_str() {
+            if origin != &WILDCARD && !s.starts_with("http://") && !s.starts_with("https://") {
+                // Use proper error handling in production
+                debug_assert!(false, "Invalid origin format: {}", s);
+            }
+        }
+    }
     if origins.iter().any(|o| o == WILDCARD) {
         Self(cors::AllowOrigin::any())
     } else {
         Self(cors::AllowOrigin::list(origins))
     }
 }
crates/katana/cli/src/utils.rs (1)

195-220: Consider validating origins during deserialization, sensei!

While the implementation handles empty strings well, consider validating the origin format during deserialization to catch invalid origins early.

 pub fn deserialize_cors_origins<'de, D>(deserializer: D) -> Result<Vec<HeaderValue>, D::Error>
 where
     D: Deserializer<'de>,
 {
-    String::deserialize(deserializer)?
+    let origins = String::deserialize(deserializer)?
         .split(',')
         .map(|s| s.trim())
-        .filter(|s| !s.is_empty())
+        .filter(|s| {
+            if s.is_empty() {
+                return false;
+            }
+            // Allow wildcard or validate URL format
+            s == "*" || s.starts_with("http://") || s.starts_with("https://")
+        })
         .map(HeaderValue::from_str)
         .collect::<Result<Vec<HeaderValue>, _>>()
-        .map_err(serde::de::Error::custom)
+        .map_err(serde::de::Error::custom)?;
+
+    if origins.is_empty() {
+        Ok(vec![])
+    } else {
+        Ok(origins)
+    }
 }
crates/katana/rpc/rpc/src/lib.rs (2)

27-34: Ohayo sensei! Consider expanding error handling for specific scenarios.

The error enum could benefit from additional variants to handle specific failure cases such as:

  • Connection/binding errors
  • Configuration validation errors
  • Middleware initialization errors
 pub enum Error {
     #[error(transparent)]
     Jsonrpsee(#[from] jsonrpsee::core::Error),
 
     #[error("RPC server has already been stopped")]
     AlreadyStopped,
+
+    #[error("Failed to bind to address: {0}")]
+    BindError(std::io::Error),
+
+    #[error("Invalid configuration: {0}")]
+    ConfigError(String),
+
+    #[error("Middleware initialization failed: {0}")]
+    MiddlewareError(String),
 }

36-51: Ohayo sensei! Consider adding utility methods to RpcServerHandle.

The handle implementation could be enhanced with methods for:

  • Checking if the server is running
  • Getting current connection count
  • Graceful shutdown with timeout
 impl RpcServerHandle {
+    /// Returns true if the server is currently running
+    pub fn is_running(&self) -> bool {
+        !self.handle.is_stopped()
+    }
+
+    /// Attempts to stop the server with a timeout
+    pub async fn stop_with_timeout(&self, timeout: Duration) -> Result<(), Error> {
+        tokio::time::timeout(timeout, self.stopped())
+            .await
+            .map_err(|_| Error::AlreadyStopped)?;
+        Ok(())
+    }
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e69db8f and e0ca640.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • crates/dojo/test-utils/src/sequencer.rs (1 hunks)
  • crates/katana/cli/Cargo.toml (1 hunks)
  • crates/katana/cli/src/args.rs (2 hunks)
  • crates/katana/cli/src/options.rs (3 hunks)
  • crates/katana/cli/src/utils.rs (2 hunks)
  • crates/katana/node/src/config/rpc.rs (3 hunks)
  • crates/katana/node/src/lib.rs (5 hunks)
  • crates/katana/rpc/rpc/Cargo.toml (2 hunks)
  • crates/katana/rpc/rpc/src/cors.rs (1 hunks)
  • crates/katana/rpc/rpc/src/health.rs (1 hunks)
  • crates/katana/rpc/rpc/src/lib.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • crates/katana/cli/Cargo.toml
  • crates/dojo/test-utils/src/sequencer.rs
  • crates/katana/cli/src/args.rs
  • crates/katana/cli/src/options.rs
  • crates/katana/node/src/config/rpc.rs
  • crates/katana/rpc/rpc/Cargo.toml
  • crates/katana/rpc/rpc/src/health.rs
🔇 Additional comments (5)
crates/katana/rpc/rpc/src/cors.rs (3)

1-61: Ohayo! The CORS implementation looks solid, sensei!

The implementation follows the builder pattern nicely, with clear documentation and type-safe methods. The Layer trait implementation enables seamless integration as middleware.


104-138: Clean and comprehensive type conversions, sensei!

The From implementations provide a complete set of type conversions, making the API flexible and ergonomic to use.


140-154: Enhance test coverage for robust validation, sensei!

The current test suite only covers the basic wildcard scenario. Consider adding more test cases.

crates/katana/rpc/rpc/src/lib.rs (1)

112-115: ⚠️ Potential issue

Ohayo sensei! Security concern with host filtering configuration.

Using AllowHosts::Any allows requests from any host, which could expose the RPC server to unauthorized access.

Consider:

  1. Using AllowHosts::Localhost for development
  2. Making host filtering configurable
  3. Implementing a whitelist of allowed hosts
-            .set_host_filtering(AllowHosts::Any)
+            .set_host_filtering(config.allowed_hosts.unwrap_or(AllowHosts::Localhost))

Likely invalid or redundant comment.

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

265-269: ⚠️ Potential issue

Ohayo sensei! Unsafe CORS header parsing.

The current implementation uses unwrap() on header parsing which could cause panics.

Apply this diff to handle the parsing safely:

 let cors = Cors::new()
     .allow_origins(config.cors_origins.clone())
     .allow_methods([Method::POST, Method::GET])
     .allow_headers([
         hyper::header::CONTENT_TYPE,
-        "argent-client".parse().unwrap(),
-        "argent-version".parse().unwrap(),
+        HeaderValue::from_static("argent-client"),
+        HeaderValue::from_static("argent-version"),
     ]);

Comment on lines +286 to +288
modules.merge(StarknetApiServer::into_rpc(api.clone()))?;
modules.merge(StarknetWriteApiServer::into_rpc(api.clone()))?;
modules.merge(StarknetTraceApiServer::into_rpc(api))?;
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 error handling for module merging.

The current implementation might not provide clear error context when module merging fails.

Consider wrapping the merge operations with additional context:

-        modules.merge(StarknetApiServer::into_rpc(api.clone()))?;
-        modules.merge(StarknetWriteApiServer::into_rpc(api.clone()))?;
-        modules.merge(StarknetTraceApiServer::into_rpc(api))?;
+        modules
+            .merge(StarknetApiServer::into_rpc(api.clone()))
+            .map_err(|e| anyhow::anyhow!("Failed to merge Starknet API: {}", e))?;
+        modules
+            .merge(StarknetWriteApiServer::into_rpc(api.clone()))
+            .map_err(|e| anyhow::anyhow!("Failed to merge Starknet Write API: {}", e))?;
+        modules
+            .merge(StarknetTraceApiServer::into_rpc(api))
+            .map_err(|e| anyhow::anyhow!("Failed to merge Starknet Trace API: {}", e))?;
📝 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
modules.merge(StarknetApiServer::into_rpc(api.clone()))?;
modules.merge(StarknetWriteApiServer::into_rpc(api.clone()))?;
modules.merge(StarknetTraceApiServer::into_rpc(api))?;
modules
.merge(StarknetApiServer::into_rpc(api.clone()))
.map_err(|e| anyhow::anyhow!("Failed to merge Starknet API: {}", e))?;
modules
.merge(StarknetWriteApiServer::into_rpc(api.clone()))
.map_err(|e| anyhow::anyhow!("Failed to merge Starknet Write API: {}", e))?;
modules
.merge(StarknetTraceApiServer::into_rpc(api))
.map_err(|e| anyhow::anyhow!("Failed to merge Starknet Trace API: {}", e))?;

Copy link

codecov bot commented Dec 10, 2024

Codecov Report

Attention: Patch coverage is 67.47573% with 67 lines in your changes missing coverage. Please review.

Project coverage is 55.61%. Comparing base (2738f67) to head (e0ca640).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
crates/katana/rpc/rpc/src/cors.rs 59.09% 27 Missing ⚠️
crates/katana/cli/src/utils.rs 0.00% 25 Missing ⚠️
crates/katana/rpc/rpc/src/lib.rs 76.19% 15 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2788      +/-   ##
==========================================
+ Coverage   55.58%   55.61%   +0.02%     
==========================================
  Files         436      439       +3     
  Lines       55521    55678     +157     
==========================================
+ Hits        30862    30965     +103     
- Misses      24659    24713      +54     

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

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.

1 participant