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

Chain service error #989

Merged
merged 9 commits into from
May 27, 2024
Merged

Chain service error #989

merged 9 commits into from
May 27, 2024

Conversation

roeierez
Copy link
Member

fixed #983

This PR address two issues:

  1. Ensures we only parse the json in case of success status code (2xx)
  2. log any chain service errors with the corresponding url and associated error returned.
  3. When attempting to lookup for closing tx onchain don't fail the sync process if the tx was not found (which technically could happen in case of zero conf).

@roeierez roeierez requested review from dangeross and ok300 May 26, 2024 16:49
url,
response.status()
);
error!("{err}");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it worth logging the response body in unsuccessful requests or is the http code enough to diagnose potential issues?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it worth since it shouldn't happen too much and when it happens like in the associated issue it helps identify the problem.

.text()
.await
.map_err(|e| SdkError::ServiceConnectivity { err: e.to_string() }),
false => {
Copy link
Contributor

@ok300 ok300 May 27, 2024

Choose a reason for hiding this comment

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

Unfortunately this would break error handling for LNURL.

Some specs (like LNURL but maybe others too) define errors in terms of how the response payload looks like, regardless of HTTP status.

If we now throw Err here in the GET response handling in case of HTTP error code, this means we will not return anymore the LNURL error JSON payload

{"status": "ERROR", "reason": "error details..."}

which means we lose the info on the error cause indicated by the server (not enough funds, etc).

IMO we need to return both the HTTP status and the raw payload, then let the caller decide. For mempool API calls, HTTP error code means error. For LNURL, the HTTP error code is only one mode of failure, the other is the error payload (can be returned with HTTP 200 or HTTP error).

Copy link
Contributor

Choose a reason for hiding this comment

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

I tested it and indeed:

with the PR, trying to LNURL-withdraw from a wallet with no funds returns

Error: Service connectivity: Service connectivity: GET request https://stacker.news/api/lnwith?k1=ce529c69344c7ae... failed with status: 400 Bad Request

whereas on main the same LNURL call returns

{
  "ErrorStatus": {
    "data": {
      "reason": "insufficient funds"
    }
  }
}

These LNURL error objects are useful to apps integrating with us, as they can surface the error reason to the end-user.

Copy link
Contributor

Choose a reason for hiding this comment

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

How about #990? IMO it covers both cases.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it would be good to add test cases for the two ways a response is handled

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

@dangeross added test. Now both cases are tested.

@ok300
Copy link
Contributor

ok300 commented May 27, 2024

Resolved conflicts with main.

@roeierez roeierez requested a review from dangeross May 27, 2024 12:48
Comment on lines 1078 to 1089
let response_body = match &return_lnurl_error {
None => expected_lnurl_withdraw_data,
Some(err_reason) => {
["{\"status\": \"ERROR\", \"reason\": \"", &err_reason, "\"}"].join("")
}
};

let status = match &return_lnurl_error {
None => 200,
Some(_) => 400,
};

Copy link
Contributor

@erdemyerebasmaz erdemyerebasmaz May 27, 2024

Choose a reason for hiding this comment

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

I think we can match once and return the result as tuple here:

let (response_body, status) = match &return_lnurl_error {
    None => (expected_lnurl_withdraw_data, 200),
    Some(err_reason) => (
        ["{\"status\": \"ERROR\", \"reason\": \"", &err_reason, "\"}"].join(""),
        400,
    ),
};

or we can use response_body to set status to avoid matching twice:

let status = if return_lnurl_error.is_none() {
    200
} else {
    400
};

Copy link
Contributor

Choose a reason for hiding this comment

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

@roeierez cargo clippy has this warning:

error: this expression creates a reference which is immediately dereferenced by the compiler
    --> sdk-core/src/input_parser.rs:1081:60
     |
1081 |                 ["{\"status\": \"ERROR\", \"reason\": \"", &err_reason, "\"}"].join(""),
     |                                                            ^^^^^^^^^^^ help: change this to: `err_reason`
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
     = note: `-D clippy::needless-borrow` implied by `-D warnings`
     = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`

Copy link
Contributor

@erdemyerebasmaz erdemyerebasmaz left a comment

Choose a reason for hiding this comment

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

Changes look good
Have a recommendation regarding redundant match on &return_lnurl_error

/// parse the payload. In this case, an HTTP error code will automatically cause this function to
/// return `Err`, regardless of the payload. If false, the result type will be determined only
/// by the result of parsing the payload into the desired target type.
pub(crate) async fn get_parse_and_log_response<T>(
Copy link
Contributor

@erdemyerebasmaz erdemyerebasmaz May 27, 2024

Choose a reason for hiding this comment

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

According to documentation, I think it makes much more sense to rename this parse_get_and_log_response

Copy link
Collaborator

@dangeross dangeross 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, except the clippy error

@roeierez roeierez merged commit ff5b055 into main May 27, 2024
7 checks passed
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.

Generic: All chain service instances failed
5 participants