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

Add ADR document on errors #513

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

thunderbiscuit
Copy link
Member

This PR is very much up for review and discussion. I figured that a good way to lay out correctly a solution would be to write it out. We can hash out the specifics directly on this PR.

Copy link

coderabbitai bot commented Apr 26, 2024

Walkthrough

This update introduces a new document, 03-errors.md, which addresses the handling of errors in Rust bitcoin libraries, particularly focusing on the integration with the uniffi tool. The document outlines the challenges and decisions related to error handling, emphasizing the importance of meaningful error messages in language bindings.

Changes

File Summary
docs/adr/03-errors.md New document discussing error handling strategies in Rust bitcoin libraries using uniffi.

Recent Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between e609b57 and c198a34.
Files selected for processing (1)
  • docs/adr/03-errrors.md (1 hunks)
Additional Context Used
LanguageTool (14)
docs/adr/03-errrors.md (14)

Near line 7: Possible spelling mistake found.
Context: ...we use to produce language bindings for bdk-ffi libraries is [uniffi]. While the librar...


Near line 7: Possible spelling mistake found.
Context: ...uage bindings for bdk-ffi libraries is [uniffi]. While the library is powerful, it als...


Near line 7: Possible spelling mistake found.
Context: ...t errors; we must choose between simple enums that have variants but not data associa...


Near line 7: Possible spelling mistake found.
Context: ...ata associated with them (for example a TxidError would not be able to return the specif...


Near line 7: Possible spelling mistake found.
Context: ...ould not be able to return the specific txid that triggered the error), or more comp...


Near line 7: Possible spelling mistake found.
Context: ...g if the object has no data, and just a strignified version of the fields if it does have a...


Near line 11: The singular determiner ‘this’ may not agree with the plural noun ‘decisions’. Did you mean “these”?
Context: ...detail in [issue #509]. Some aspects of this decisions include: - Expectations from ...


Near line 12: A comma might be missing here.
Context: ...e libraries in different languages (for example Kotlin users expect a message field o...


Near line 13: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...of maintaining the errors as they evolve and we expose more and more of the Rust BDK...


Near line 14: Possible spelling mistake found.
Context: ...ce-to-have features (some fields can be stringified without loss of information, some canno...


Near line 18: Possible spelling mistake found.
Context: ... leverage two different approaches that uniffi offers for exposing errors, and using t...


Near line 20: Possible missing article found.
Context: ...pler to maintain option, which provides better, costumized error message with a `messa...


Near line 20: Possible spelling mistake found.
Context: ...maintain option, which provides better, costumized error message with a message field pr...


Near line 20: Possible spelling mistake found.
Context: ... with a message field provided by the thiserror library. Those errors cannot have fiel...


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:

Note: Auto-reply has been disabled for this repository by the repository owner. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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.

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

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration 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.

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: 14


## Context and Problem Statement

The tool we use to produce language bindings for bdk-ffi libraries is [uniffi]. While the library is powerful, it also comes with some caveats. Those come into play when attempting to expose Rust errors; we must choose between simple enums that have variants but not data associated with them (for example a `TxidError` would not be able to return the specific txid that triggered the error), or more complex objects that do have data fields, but no ability to control the error message returned to the user. What's more, while Kotlin and Java users expect a `message` field on an `Exception` type, this field becomes an empty string if the object has no data, and just a strignified version of the fields if it does have any.
Copy link

Choose a reason for hiding this comment

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

Correct the spelling mistake in "strignified" to "stringified".

- just a strignified version of the fields if it does have any.
+ just a stringified version of the fields if it does have any.

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.

Suggested change
The tool we use to produce language bindings for bdk-ffi libraries is [uniffi]. While the library is powerful, it also comes with some caveats. Those come into play when attempting to expose Rust errors; we must choose between simple enums that have variants but not data associated with them (for example a `TxidError` would not be able to return the specific txid that triggered the error), or more complex objects that do have data fields, but no ability to control the error message returned to the user. What's more, while Kotlin and Java users expect a `message` field on an `Exception` type, this field becomes an empty string if the object has no data, and just a strignified version of the fields if it does have any.
The tool we use to produce language bindings for bdk-ffi libraries is [uniffi]. While the library is powerful, it also comes with some caveats. Those come into play when attempting to expose Rust errors; we must choose between simple enums that have variants but not data associated with them (for example a `TxidError` would not be able to return the specific txid that triggered the error), or more complex objects that do have data fields, but no ability to control the error message returned to the user. What's more, while Kotlin and Java users expect a `message` field on an `Exception` type, this field becomes an empty string if the object has no data, and just a stringified version of the fields if it does have any.


## Decision Drivers

Some options were considered and explored in detail in [issue #509]. Some aspects of this decisions include:
Copy link

Choose a reason for hiding this comment

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

Replace "this decisions" with "these decisions" to correct grammatical agreement.

- Some aspects of this decisions include:
+ Some aspects of these decisions include:

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.

Suggested change
Some options were considered and explored in detail in [issue #509]. Some aspects of this decisions include:
Some options were considered and explored in detail in [issue #509]. Some aspects of these decisions include:

## Decision Drivers

Some options were considered and explored in detail in [issue #509]. Some aspects of this decisions include:
- Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)
Copy link

Choose a reason for hiding this comment

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

Consider adding a comma after "for example" for better readability.

- (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)
+ (for example, Kotlin users expect a `message` field on the exception, whereas Swift users do not)

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.

Suggested change
- Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)
- Expectations from devs using the libraries in different languages (for example, Kotlin users expect a `message` field on the exception, whereas Swift users do not)

Ensure lists are surrounded by blank lines.

- - Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)
+ 
+ - Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)

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.

Suggested change
- Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)
- Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)


Some options were considered and explored in detail in [issue #509]. Some aspects of this decisions include:
- Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)
- Ease of maintaining the errors as they evolve and we expose more and more of the Rust BDK ecosystem
Copy link

Choose a reason for hiding this comment

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

Consider adding a comma before "and" to connect two independent clauses.

- as they evolve and we expose more and more of the Rust BDK ecosystem
+ as they evolve, and we expose more and more of the Rust BDK ecosystem

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.

Suggested change
- Ease of maintaining the errors as they evolve and we expose more and more of the Rust BDK ecosystem
- Ease of maintaining the errors as they evolve, and we expose more and more of the Rust BDK ecosystem


We have decided to leverage two different approaches that uniffi offers for exposing errors, and using the most appropriate one for each situation.

In the case where errors do not require passing back data, we opt for the simpler to maintain option, which provides better, costumized error message with a `message` field provided by the `thiserror` library. Those errors cannot have fields. For example:
Copy link

Choose a reason for hiding this comment

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

Correct the spelling mistake in "costumized" to "customized".

- which provides better, costumized error message with a `message` field provided by the `thiserror` library.
+ which provides better, customized error message with a `message` field provided by the `thiserror` library.

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.

Suggested change
In the case where errors do not require passing back data, we opt for the simpler to maintain option, which provides better, costumized error message with a `message` field provided by the `thiserror` library. Those errors cannot have fields. For example:
In the case where errors do not require passing back data, we opt for the simpler to maintain option, which provides better, customized error message with a `message` field provided by the `thiserror` library. Those errors cannot have fields. For example:

};
```

### Rust
Copy link

Choose a reason for hiding this comment

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

Ensure headings are surrounded by blank lines.

- ### Rust
+ ### Rust

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.

Suggested change
### Rust
### Rust

In the case where errors do not require passing back data, we opt for the simpler to maintain option, which provides better, costumized error message with a `message` field provided by the `thiserror` library. Those errors cannot have fields. For example:
#### UDL

```txt
Copy link

Choose a reason for hiding this comment

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

Ensure fenced code blocks are surrounded by blank lines.

- ```txt
+ 
+ ```txt

```

#### Rust
```rust
Copy link

Choose a reason for hiding this comment

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

Ensure fenced code blocks are surrounded by blank lines.

- ```rust
+ 
+ ```rust

In the case where complex types should be returned as part of the error, we use the more complex interface UDL type and return the data, at the cost of more explicit messages. For example:

### UDL
```txt
Copy link

Choose a reason for hiding this comment

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

Ensure fenced code blocks are surrounded by blank lines.

- ```txt
+ 
+ ```txt

```

### Rust
```rust
Copy link

Choose a reason for hiding this comment

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

Ensure fenced code blocks are surrounded by blank lines.

- ```rust
+ 
+ ```rust

@reez
Copy link
Collaborator

reez commented Apr 26, 2024

Great idea. I'm going to ruminate on this a bit over the next week (and add comments/thoughts as needed)


## Context and Problem Statement

The tool we use to produce language bindings for bdk-ffi libraries is [uniffi]. While the library is powerful, it also comes with some caveats. Those come into play when attempting to expose Rust errors; we must choose between simple enums that have variants but not data associated with them (for example a `TxidError` would not be able to return the specific txid that triggered the error), or more complex objects that do have data fields, but no ability to control the error message returned to the user. What's more, while Kotlin and Java users expect a `message` field on an `Exception` type, this field becomes an empty string if the object has no data, and just a strignified version of the fields if it does have any.
Copy link
Collaborator

Choose a reason for hiding this comment

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

if you want to touch on swift real quick here we can add something like this at the end of the Context and Problem Statement section:

"Swift, in contrast, can optionally leverage something like the LocalizedError protocol to provide custom and localized descriptions."

## Decision Drivers

Some options were considered and explored in detail in [issue #509]. Some aspects of this decisions include:
- Expectations from devs using the libraries in different languages (for example Kotlin users expect a `message` field on the exception, whereas Swift users do not)
Copy link
Collaborator

Choose a reason for hiding this comment

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

"whereas Swift users do not" could be "whereas Swift users do not expect message but might expect localizedDescription"

Copy link
Collaborator

Choose a reason for hiding this comment

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

verbiage on this suggestion might change now with mozilla/uniffi-rs#2116

Copy link
Collaborator

@reez reez left a comment

Choose a reason for hiding this comment

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

ACK c198a34

Added 2 comments you can optionally include, and then coderabbitai added some good grammatical suggestions I think should be included.

@@ -0,0 +1,59 @@
# Errors

Returning meaningful errors is important for users of our libraries. The Rust bitcoin ecosystem uses descriptive and data-driven errors, and we would like to stay as close to them as possible when building language bindings for these libraries.
Copy link
Collaborator

Choose a reason for hiding this comment

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

what do you think of something like this for this section, it includes what you already have but just sandwiches some extra "error handling philosophy" in between:

Returning meaningful errors is important for users of our libraries. Libraries return errors and applications decide if and how those errors are formatted and displayed to users. Our goal as a library is to produce meaningful and structured error types which allows applications to easily differentiate various error cases. The Rust bitcoin ecosystem uses descriptive and data-driven errors, and we would like to stay as close to them as possible when building language bindings for these libraries.

@reez reez mentioned this pull request May 30, 2024
@reez
Copy link
Collaborator

reez commented Nov 21, 2024

Still interested in adding this as an ADR? I think we are solidified enough per #509 that the way we do it now is the "standard", so I'm cool with getting this merged if you are good with that (obviously after rebase, maybe fixing small nits/comments, etc).

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.

2 participants