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

fix(sdk)!: create channel error due to empty address #2317

Merged
merged 21 commits into from
Dec 5, 2024

Conversation

shumkov
Copy link
Member

@shumkov shumkov commented Nov 8, 2024

Issue being fixed or feature implemented

New SDK 1.5.1 fails on android with:

rs_dapi_client::dapi_client: request failed error=ExecutionError { inner: Transport(Grpc(Status { code: FailedPrecondition, message: "Channel creation failed: transport error", source: None })), retries: 0, address: Some(Address { ban_count: 0, banned_until: None, uri: https://52.13.132.146:1443/ }) }

What was done?

  • Do not allow to create invalid Address
  • Return invalid argument instead of failed precondition in TransportClient::new_with_uri
  • AddressList::add_uri is deprecated

How Has This Been Tested?

Running tests

Breaking Changes

  • From<Uri> for Address replaced with TryFrom<Uri> for Address
  • From<&str> for AddressList replaced with FromStr for AddressList
  • FromIterator<Uri> for AddressList replaced with FromIterator<Address> for AddressList

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced error handling for address parsing and gRPC channel creation.
    • Transitioned from URI strings to a structured Address type for improved type safety.
  • Bug Fixes

    • Improved error reporting for address-related operations and retry mechanisms.
  • Documentation

    • Updated examples and comments to reflect the new Address type usage.
  • Tests

    • Refined test cases to align with the new address handling and error management.

@shumkov shumkov added this to the v1.6.0 milestone Nov 8, 2024
Copy link
Contributor

coderabbitai bot commented Nov 8, 2024

Walkthrough

The changes in this pull request primarily focus on enhancing the Address and AddressList structures within the rs-dapi-client module. Key modifications include transitioning from From to TryFrom for Address, updating error handling to improve clarity, and refining the conversion processes. The EvoNode struct and related test cases have also been adapted to utilize the new Address type. Additionally, adjustments in the gRPC transport layer have altered error reporting formats. Overall, these changes improve type safety and error handling across the affected components.

Changes

File Path Change Summary
packages/rs-dapi-client/src/address_list.rs - Modified FromStr implementation for Address to TryFrom<Uri> with improved error handling.
- Updated FromStr for AddressList to parse Address instead of Uri.
- Changed InvalidAddressUri to accept String.
- Updated from_iter method to accept Address.
packages/rs-dapi-client/src/transport/grpc.rs - Changed error handling in with_uri and with_uri_and_settings methods from failed_precondition to invalid_argument.
- Updated error message formatting.
packages/rs-sdk/examples/read_contract.rs - Updated import statement to include Address.
- Changed URI construction to use Address directly instead of http::Uri.
packages/rs-sdk/src/platform/types/evonode.rs - Updated example usage to instantiate EvoNode with Address instead of http::Uri.
packages/rs-sdk/src/sync.rs - Expanded AsyncError enum to include Generic(String).
- Updated logic in block_on and retry functions for improved error handling and retry mechanisms.
packages/rs-sdk/tests/fetch/config.rs - Updated import statement to include Address.
- Changed variable type from String to Address in address_list method.
packages/rs-sdk/tests/fetch/evonode.rs - Updated tests to replace http::Uri with Address.
- Modified error handling in tests to reflect the change to Address.

Possibly related PRs

Suggested labels

rs-sdk

Suggested reviewers

  • QuantumExplorer
  • lklimek

🐰 In the land of code where rabbits play,
New structures hop in, brightening the day.
From strings to addresses, we leap with delight,
Error handling's clearer, everything feels right!
With each little change, our code's a bit spry,
A hop and a skip, watch our features fly! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 02e0474 and c46fa26.

📒 Files selected for processing (3)
  • packages/rs-dapi-client/src/address_list.rs (5 hunks)
  • packages/rs-sdk/src/sync.rs (1 hunks)
  • packages/rs-sdk/tests/fetch/evonode.rs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rs-sdk/tests/fetch/evonode.rs
🧰 Additional context used
📓 Learnings (1)
packages/rs-dapi-client/src/address_list.rs (1)
Learnt from: shumkov
PR: dashpay/platform#2317
File: packages/rs-dapi-client/src/address_list.rs:175-180
Timestamp: 2024-11-28T13:49:17.301Z
Learning: In Rust code in `packages/rs-dapi-client/src/address_list.rs`, do not change the interface of deprecated methods like `add_uri`, even to fix potential panics.
🔇 Additional comments (7)
packages/rs-dapi-client/src/address_list.rs (6)

26-27: LGTM! Improved error handling in FromStr implementation.

The error handling has been enhanced by converting the URI parsing error to a string message, making it more user-friendly.


49-59: LGTM! Added validation in TryFrom implementation.

The new TryFrom<Uri> implementation adds important validation to ensure the URI contains a host, preventing invalid addresses from being created.


107-107: LGTM! Enhanced error variant.

Changed InvalidAddressUri to use String instead of http::uri::InvalidUri, allowing for more descriptive error messages.


260-269: LGTM! Improved FromStr implementation.

The implementation now correctly handles errors during address parsing and collection.


273-277: LGTM! Updated FromIterator implementation.

Changed from FromIterator<Uri> to FromIterator<Address>, improving type safety by ensuring addresses are validated before being added to the list.


205-210: Consider removing deprecated method.

The deprecated add_uri method uses expect("valid uri") which could panic. However, based on the learnings, we should not change the interface of deprecated methods.

Let's check if this method is still being used:

packages/rs-sdk/src/sync.rs (1)

358-358: LGTM! Updated address parsing in test.

The test now uses the new address parsing mechanism, maintaining consistency with the changes in the Address type.


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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

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.

@shumkov shumkov changed the title fix(sdk): create channel error due to empty address fix(sdk)!: create channel error due to empty address Nov 8, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (10)
packages/rs-sdk/tests/fetch/evonode.rs (2)

65-69: Add test coverage for invalid address creation

While this test covers the connection refusal scenario, given the PR's focus on preventing invalid Address creation, consider adding explicit test cases for:

  1. Invalid URI to Address conversion scenarios
  2. Empty address cases that were causing issues on Android

Example addition:

#[test]
fn test_invalid_address_creation() {
    // Test empty host
    let result = Address::try_from(Uri::from_static("http:///path"));
    assert!(result.is_err());

    // Test missing scheme
    let result = "localhost:3000".parse::<Address>();
    assert!(result.is_err());
}

Based on the code inspection, I can now generate the final response:

Add unit tests for breaking type conversion changes

The code shows the implementation of the breaking changes but lacks dedicated unit tests. Please add tests for:

  • TryFrom<Uri> for Address to verify:
    • Success case with valid URI containing host
    • Error case with URI missing host
  • FromStr for AddressList to verify:
    • Success case with comma-separated valid addresses
    • Error case with invalid URI strings
  • FromIterator<Address> for AddressList to verify:
    • Collection creation from iterator of valid addresses

These tests should be added in a new mod tests block in packages/rs-dapi-client/src/address_list.rs.

🔗 Analysis chain

Line range hint 14-72: Enhance test coverage for breaking changes

The PR introduces several breaking changes in type conversions that should be explicitly tested:

  1. Uri to Address: FromTryFrom
  2. &str to AddressList: FromFromStr
  3. Uri to AddressList: FromIterator<Uri>FromIterator<Address>

Let's check if these conversions are tested elsewhere:

Consider adding comprehensive test coverage for these breaking changes if not already covered elsewhere.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing tests of the breaking changes
rg -t rust "test.*(?:try_)?from.*uri|test.*address.*list.*from|test.*from.*str" ./packages/rs-dapi-client/src/

Length of output: 112


Script:

#!/bin/bash
# Let's search for test files and type conversion tests with a broader pattern
rg -t rust "(?m)^#\[test\].*\n.*(?:try_)?from|test.*address.*list|test.*uri.*address" --context 2

Length of output: 291


Script:

#!/bin/bash
# Let's also check for the actual type conversion implementations
ast-grep --pattern 'impl $_ for Address {
  $$$
}'

Length of output: 3255


Script:

#!/bin/bash
# And check for AddressList implementations
ast-grep --pattern 'impl $_ for AddressList {
  $$$
}'

Length of output: 2602


Script:

#!/bin/bash
# Let's also check all test files in the repository
fd "test.*\.rs$"

Length of output: 2278


Script:

#!/bin/bash
# Let's check for existing tests in address_list.rs
rg -U "(?s)#\[test\].*?\}" packages/rs-dapi-client/src/address_list.rs

Length of output: 72


Script:

#!/bin/bash
# Let's also check the test file where the review comment was made
rg -U "(?s)#\[test\].*?\}" packages/rs-sdk/tests/fetch/evonode.rs

Length of output: 67


Script:

#!/bin/bash
# Let's try a simpler approach to find tests
rg "#\[test\]" packages/rs-dapi-client/src/address_list.rs -A 1

Length of output: 65


Script:

#!/bin/bash
# Let's also check if there's a dedicated test module
rg "mod tests" packages/rs-dapi-client/src/address_list.rs -A 2

Length of output: 65


Script:

#!/bin/bash
# And check the actual content of address_list.rs
cat packages/rs-dapi-client/src/address_list.rs

Length of output: 6806

packages/rs-sdk/examples/read_contract.rs (2)

83-85: Consider improving error handling in this example

While the implementation correctly uses the new Address type, using expect() in an example might not demonstrate best practices for error handling.

Consider using proper error handling to make the example more educational:

-    let address = Address::from_str(&format!(
-        "https://{}:{}",
-        config.server_address, config.platform_port
-    ))
-    .expect("parse uri");
+    let address = Address::from_str(&format!(
+        "https://{}:{}",
+        config.server_address, config.platform_port
+    ))
+    .map_err(|e| format!("Failed to parse address: {}", e))?;

83-90: Add documentation about Address usage

Since this is an example file and the PR introduces breaking changes in how addresses are handled, it would be helpful to add comments explaining the new Address type usage and why it's preferred over the previous URI approach.

Add a comment block before the address creation:

+    // Create a new Address instance using HTTPS scheme
+    // Note: We use Address instead of URI for better validation and type safety
+    // The Address type ensures that only valid addresses are created
     let address = Address::from_str(&format!(
packages/rs-sdk/src/platform/types/evonode.rs (1)

Line range hint 82-86: Consider enhancing error handling specificity.

Given the PR's focus on improving error handling (changing from failed precondition to invalid argument errors), consider making the error handling in execute_transport more specific. Instead of using a generic error conversion with map_err(TransportError::Grpc), you could map specific gRPC errors to more descriptive transport errors.

Here's a suggested improvement:

             let response = client
                 .get_status(grpc_request)
-                .map_err(TransportError::Grpc)
+                .map_err(|e| match e.code() {
+                    tonic::Code::InvalidArgument => TransportError::InvalidAddress(e.message().to_string()),
+                    _ => TransportError::Grpc(e),
+                })
                 .map_ok(|response| response.into_inner())
                 .await;
packages/rs-sdk/tests/fetch/config.rs (1)

134-136: Consider more robust error handling for address parsing.

While the implementation correctly uses the new Address type and parsing mechanism, the use of expect() could make debugging harder if the configuration is invalid. Consider either:

  1. Propagating the error to provide more context about the invalid configuration, or
  2. Adding a more descriptive expect message that includes the actual address being parsed

Example improvement:

-        let address: Address = format!("{}://{}:{}", scheme, self.platform_host, self.platform_port).parse().expect("valid address");
+        let addr_str = format!("{}://{}:{}", scheme, self.platform_host, self.platform_port);
+        let address: Address = addr_str.parse().expect(&format!("Invalid address: {}", addr_str));
packages/rs-dapi-client/src/address_list.rs (3)

28-29: Consider preserving original error types for better error handling

Converting the error into a String with e.to_string() may lose valuable error information. Consider preserving the original error type to retain detailed context for debugging purposes.

You could modify the InvalidAddressUri variant to include the original error:

- InvalidAddressUri(String),
+ InvalidAddressUri(http::uri::InvalidUri),

And adjust the error mapping accordingly:

.map_err(|e| AddressListError::InvalidAddressUri(e))

55-57: Include URI in error message for better debugging

Including the problematic URI in the error message can aid in diagnosing issues by providing more context.

Apply this change:

if value.host().is_none() {
    return Err(AddressListError::InvalidAddressUri(
-       "uri must contain host".to_string()
+       format!("URI '{}' must contain host", value)
    ));
}

228-232: Rename variable uri to address for clarity

In the FromIterator<Address> implementation, the variable uri represents an Address. Renaming it to address would improve code readability and reduce confusion.

Apply this diff:

fn from_iter<T: IntoIterator<Item = Address>>(iter: T) -> Self {
    let mut address_list = Self::new();
-    for uri in iter {
-        address_list.add(uri);
+    for address in iter {
+        address_list.add(address);
    }
    address_list
}
packages/rs-sdk/src/sync.rs (1)

200-200: Fix typographical error in comment

There's a misspelling in the comment: "preceeding" should be "preceding".

Apply this diff to correct the typo:

-                    // requests sent in all preceeding attempts; user expects `settings.retries +1`
+                    // requests sent in all preceding attempts; user expects `settings.retries +1`
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 48cca1a and b8a887e.

📒 Files selected for processing (7)
  • packages/rs-dapi-client/src/address_list.rs (5 hunks)
  • packages/rs-dapi-client/src/transport/grpc.rs (1 hunks)
  • packages/rs-sdk/examples/read_contract.rs (2 hunks)
  • packages/rs-sdk/src/platform/types/evonode.rs (1 hunks)
  • packages/rs-sdk/src/sync.rs (2 hunks)
  • packages/rs-sdk/tests/fetch/config.rs (2 hunks)
  • packages/rs-sdk/tests/fetch/evonode.rs (2 hunks)
🔇 Additional comments (6)
packages/rs-sdk/tests/fetch/evonode.rs (2)

11-11: LGTM: Address import aligns with PR objectives

The addition of rs_dapi_client::Address import supports the transition from Uri to Address type as outlined in the PR objectives.


Line range hint 14-61: LGTM: Robust test implementation with proper error handling

The test case properly implements the new Address type while maintaining comprehensive error handling, timeouts, and assertions. The logging is informative and will help with debugging.

packages/rs-sdk/examples/read_contract.rs (1)

6-6: LGTM: Import statement updated correctly

The addition of Address to the import statement aligns with the PR's objective to handle addresses more safely.

packages/rs-sdk/tests/fetch/config.rs (1)

11-11: LGTM: Import aligns with new Address type usage.

The addition of the Address import is consistent with the PR's objective to prevent invalid address instances.

packages/rs-dapi-client/src/address_list.rs (1)

104-104: Ensure error messages provide sufficient context

By changing InvalidAddressUri to accept a String, ensure that error messages contain enough detail to help debug issues, especially if original error types are not preserved.

Consider reviewing all error messages to confirm they provide adequate information.

packages/rs-sdk/src/sync.rs (1)

344-344: LGTM!

The code change in the test function looks good.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
packages/rs-dapi-client/src/address_list.rs (1)

223-232: Consider handling whitespace in address parsing

The implementation is correct, but consider trimming whitespace for better usability:

     fn from_str(s: &str) -> Result<Self, Self::Err> {
         let uri_list: Vec<Address> = s
             .split(',')
+            .map(str::trim)
+            .filter(|s| !s.is_empty())
             .map(Address::from_str)
             .collect::<Result<_, _>>()?;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b8a887e and cea6ca9.

📒 Files selected for processing (1)
  • packages/rs-dapi-client/src/address_list.rs (6 hunks)
🔇 Additional comments (4)
packages/rs-dapi-client/src/address_list.rs (4)

28-29: LGTM: Improved error handling in FromStr implementation

The change improves error handling by providing more descriptive error messages and properly chaining the conversions through try_from.


104-104: LGTM: Simplified error variant

The change to use String for InvalidAddressUri makes the error handling more flexible and readable.


236-243: LGTM: Safe FromIterator implementation

The change from FromIterator<Uri> to FromIterator<Address> properly aligns with the new validation approach, ensuring all addresses are valid.


51-63: LGTM: Essential validation in TryFrom implementation

The change from From to TryFrom with host validation is crucial for preventing invalid Address instances. This directly addresses the root cause of the channel creation errors.

Let's verify that there are no direct From<Uri> usages that need to be updated:

✅ Verification successful

LGTM: No direct From usages found

The codebase only contains a TryFrom<Uri> implementation for Address, with no direct From<Uri> usages. The change from From to TryFrom is safe since there are no direct .into() calls or From trait implementations that need to be updated.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining From<Uri> implementations or direct .into() calls
rg -l "impl\s+From<Uri>" 
rg "\.into\(\)\s*//.*Uri.*Address"

Length of output: 63


Script:

#!/bin/bash
# Let's search more broadly for potential .into() calls and Uri to Address conversions
rg -A 2 "Uri.*into.*Address|Address.*from.*Uri"

# Also search for any direct Uri to Address conversions in tests
rg -A 2 "Uri.*Address" "**/*test*.rs"

# Search for any From trait usage with Uri
ast-grep --pattern 'impl From<$_> for $_'

Length of output: 486521


Script:

#!/bin/bash
# Search for any direct Uri to Address conversions or .into() calls
rg -A 2 "Uri.*into.*Address|Address.*from.*Uri|impl From<Uri> for Address"

# Search for any Uri type usage in the codebase
rg -A 2 "Uri.*Address"

Length of output: 537

packages/rs-dapi-client/src/address_list.rs Outdated Show resolved Hide resolved
@shumkov shumkov changed the base branch from v1.6-dev-ugly to v1.6-dev November 28, 2024 06:30
Copy link
Contributor

@lklimek lklimek left a comment

Choose a reason for hiding this comment

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

It should be done on top of #2351 which changes the Address struct

@shumkov shumkov deleted the branch v1.7-dev November 29, 2024 10:09
@shumkov shumkov closed this Nov 29, 2024
@shumkov shumkov reopened this Nov 29, 2024
@shumkov shumkov changed the base branch from v1.6-dev to v1.7-dev November 29, 2024 10:30
@shumkov shumkov self-assigned this Dec 3, 2024
# Conflicts:
#	packages/rs-dapi-client/src/address_list.rs
#	packages/rs-sdk/src/sync.rs
@shumkov shumkov modified the milestones: v1.6.0, v1.7.0 Dec 4, 2024
// TODO: this is the most simple way to add an address
// however we need to support bulk loading (e.g. providing a network name)
// and also fetch updated from SML.
#[deprecated]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
#[deprecated]
#[deprecated(since = "1.7.0", note = "deprecated in favor of add()")]

please use full syntax instead of comment below

@shumkov shumkov merged commit 6270ef0 into v1.7-dev Dec 5, 2024
30 checks passed
@shumkov shumkov deleted the fix/sdk/empty_address_uri branch December 5, 2024 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants