-
Notifications
You must be signed in to change notification settings - Fork 14
Error bindings #58
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
Error bindings #58
Conversation
93d07af
to
484afec
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left quite a few comments on the "Expose receiver error types" commit. You may see that of the conversions may be able to be simplified.
I wonder if all of the impl From
blocks are appropriate on the public API. Most of them certainly are, but some from specific variants make me wonder.
I wonder if we're complicating our life by using these #[error(message)] macros or if they're relatively self documented. Did you think they were just better documenting than comments, or something else? We don't have them on the error types upstream, and the bound errors will print different messages because of the #[error(...)] macros
Over all I think this constitutes a much more workable experience for users, though we're going to need to test it, and I can see many places where our API would benefit users to upgrade to using bitcoin_ffi types instead of the raw e.g. String or u64 types.
src/receive/error.rs
Outdated
impl From<payjoin::receive::ReplyableError> for ReplyableError { | ||
fn from(value: payjoin::receive::ReplyableError) -> Self { | ||
use payjoin::receive::ReplyableError::*; | ||
|
||
match value { | ||
Payload(_) => ReplyableError::Payload { message: value.to_string() }, | ||
V1(_) => ReplyableError::V1 { message: value.to_string() }, | ||
Implementation(_) => { | ||
ReplyableError::Implementation(ImplementationError { message: value.to_string() }) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By using value.to_string()
instead of the variant e.to_string
, isn't the thiserror annotation prefix redundant?
e.g. won't
#[error("Error while validating V1 request: {message}")]
V1 { message: String },`
double print "Error while validating V1 request" ?
I prefer using value
instead of e.g. V1(e)
's e
because we can remove this redundancy, but we do have to make sure we're not being redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm good point about the double printing. I can't get tests to run because of the ohttp changes so can't verify easily but it seems likely that it does double print. The solution may be to use #[error(transparent)]
everywhere...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OHTTP changes should work with production servers now. Which problem are you experiencing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that I need to upgrade the payjoin-directory
dev dependency, but if I upgrade it to say:
payjoin-directory = { git = "https://github.com/payjoin/rust-payjoin", branch = "bindings-0.23", features = ["_danger-local-https"] }
I get:
❯ cargo test --features=_danger-local-https
Updating git repository `https://github.com/payjoin/rust-payjoin.git`
Updating crates.io index
error: failed to select a version for `payjoin`.
... required by package `payjoin-directory v0.0.1 (https://github.com/payjoin/rust-payjoin.git?branch=bindings-0.23#0fabc7aa)`
... which satisfies git dependency `payjoin-directory` of package `payjoin_ffi v0.22.1 (/Users/spacebear/Projects/payjoin-ffi)`
versions that meet the requirements `^0.22.0` are: 0.22.0
the package `payjoin-directory` depends on `payjoin`, with features: `directory` but `payjoin` does not have these features.
impl From<payjoin::bitcoin::address::ParseError> for Error { | ||
fn from(value: payjoin::bitcoin::address::ParseError) -> Self { | ||
Error::V2 { message: value.to_string() } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be removed by accepting a bitcoin_ffi::Address
rather than String
and Network
in Receiver::new
[edit: perhaps in a follow up]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be a nice follow-up, though I couldn't get it to work in receive/uni.rs
due to:
the trait `Lift<UniFfiTag>` is not implemented for `bitcoin_ffi::Address`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe It just needs to be passed as Arc<crate::bitcoin_ffi::Address>
in the argument. follow on would work.
impl From<IntoUrlError> for Error { | ||
fn from(value: IntoUrlError) -> Self { | ||
Error::V2 { message: value.to_string() } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these From
implementations end up in the public API and I wonder if they're being used because they are indeed universal or because they make implementation less noisy.
src/receive/error.rs
Outdated
@@ -0,0 +1,135 @@ | |||
use payjoin::IntoUrlError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use payjoin::receive
would prevent some payjoin::receive::<errortype>
redundancy quite a few times in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opted for mimicking the bdk-ffi approach of aliasing e.g. use payjoin::receive::Error as PdkError
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just payjoin::receive as pdk
? The bdk case is a bit different because the errors cross so many modules. I don't even really like aliasing the module, but I like it better than aliasing every single type.
I realize now that we're using fully qualified names elsewhere, e.g. payjoin::receive::v2::PayjoinProposal in receiver/mod.rs, but I should just let this in to progress since it's internal.
6fa3073
to
f1ffa2f
Compare
Great point, I mostly used this pattern because it was used previously and looked less noisy. At first glance some of them seem appropriate (e.g.
I added them because the uniffi proc-macros were causing the compiler to complain otherwise:
I wasn't aware of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The one major concern was addressed
Everything else mostly relates to form rather than function, and given our time constraints, I'm inclined to move forward.
I do think an audit of thiserror macro usage to impl Display is in order, but that's secondary to getting the semantic error handling correct. And this gets a whole lot closer.
ACK f1ffa2f
src/receive/error.rs
Outdated
@@ -0,0 +1,135 @@ | |||
use payjoin::IntoUrlError; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just payjoin::receive as pdk
? The bdk case is a bit different because the errors cross so many modules. I don't even really like aliasing the module, but I like it better than aliasing every single type.
I realize now that we're using fully qualified names elsewhere, e.g. payjoin::receive::v2::PayjoinProposal in receiver/mod.rs, but I should just let this in to progress since it's internal.
impl From<payjoin::bitcoin::address::ParseError> for Error { | ||
fn from(value: payjoin::bitcoin::address::ParseError) -> Self { | ||
Error::V2 { message: value.to_string() } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe It just needs to be passed as Arc<crate::bitcoin_ffi::Address>
in the argument. follow on would work.
// use super::*; | ||
|
||
// fn get_proposal_from_test_vector() -> Result<UncheckedProposal, PayjoinError> { | ||
// fn get_proposal_from_test_vector() -> Result<UncheckedProposal, Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
he thorough
src/receive/error.rs
Outdated
impl From<payjoin::receive::ReplyableError> for ReplyableError { | ||
fn from(value: payjoin::receive::ReplyableError) -> Self { | ||
use payjoin::receive::ReplyableError::*; | ||
|
||
match value { | ||
Payload(_) => ReplyableError::Payload { message: value.to_string() }, | ||
V1(_) => ReplyableError::V1 { message: value.to_string() }, | ||
Implementation(_) => { | ||
ReplyableError::Implementation(ImplementationError { message: value.to_string() }) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OHTTP changes should work with production servers now. Which problem are you experiencing?
something was merged that requires this to be rebased before merge |
Sounds also like see: #64 |
Point to the bindings-0.23 rust-payjoin branch until payjoin 0.23 is released, then we can pin it back to an official version.
f1ffa2f
to
e6aaf28
Compare
Resolved conflicts, renamed Follow-up todos:
|
This exposes the top-level receiver error categories while keeping the internal variants opaque (stringified). The receiver functions are updated to return the corresponding error types.
It was renamed to `new` in rust-payjoin so ensure the bindings stay in sync.
The inner error types are complex so they are first converted to strings and the wrapper types implement From<String>.
Handle error conversions for `to_json` and `from_json` helpers.
Now that there are bindings available for all error types, we can get rid of the catch-all PayjoinError.
e6aaf28
to
84436d3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGMT. Huge progress to have contextual bindings. Can't wait to see the implementations improve because of these.
I hope to see the conversion audit sooner than later. Letting it through is known tech debt.
impl From<receive::Error> for Error { | ||
fn from(value: receive::Error) -> Self { | ||
match value { | ||
receive::Error::ReplyToSender(e) => Error::ReplyToSender(e.into()), | ||
receive::Error::V2(_) => Error::V2 { msg: value.to_string() }, | ||
_ => Error::Unexpected, | ||
} | ||
} | ||
} | ||
|
||
impl From<receive::ReplyableError> for ReplyableError { | ||
fn from(value: receive::ReplyableError) -> Self { | ||
match value { | ||
receive::ReplyableError::Payload(_) => { | ||
ReplyableError::Payload { msg: value.to_string() } | ||
} | ||
receive::ReplyableError::V1(_) => ReplyableError::V1 { msg: value.to_string() }, | ||
receive::ReplyableError::Implementation(_) => { | ||
ReplyableError::Implementation(Arc::new(ImplementationError { | ||
msg: value.to_string(), | ||
})) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl From<payjoin::bitcoin::address::ParseError> for Error { | ||
fn from(value: payjoin::bitcoin::address::ParseError) -> Self { | ||
Error::V2 { msg: value.to_string() } | ||
} | ||
} | ||
|
||
impl From<IntoUrlError> for Error { | ||
fn from(value: IntoUrlError) -> Self { | ||
Error::V2 { msg: value.to_string() } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These impls definitely spook me and must be audited.
impl From<String> for PjParseError { | ||
fn from(msg: String) -> Self { | ||
PjParseError { msg } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very smelly, address it in the audit. If we need this because we depend on bitcoin_uri errors in the public API, maybe we should reconsider those rather than making arbitrary string conversions part of the API.
Manual map_err seems a lot more appropriate in this circumstance.
Addresses #48
This exposes new top-level error types, and in cases where inner types are transparent also exposes those. Opaque inner types are kept as simple String representations.
PayjoinError is obsoleted by the new error types and removed in the last commit.