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

Separate receive::{v1,v2} error modules #482

Merged
merged 8 commits into from
Jan 16, 2025

Conversation

DanGould
Copy link
Contributor

@DanGould DanGould commented Jan 14, 2025

This big move isolates v1/v2 module-specific error variants into clean module v1/v2 error modules.

  • First commit renames the crate::receive::Error variants to be module agnostic. Before they were v1, http response-specific. Reviewers: What do you think about the Validation and External variant names? (part of Review usage of crate::receive::Error #312)
  • Second commit roughly separates the modules
  • Third commit unifies some variants that lived in module-specific error types but were actually shared
  • Fourth commit recognizes unifies v2-module-specific error variant from the remaining RequestError stub
  • Fifth commit properly scopes the crate::receive::Error variant to its own module, and I think that may resolve Review usage of crate::receive::Error #312

There are probably too many impl<From> for error variants, but I think the straight path forward is addressing the structure first with this PR and then taking a magnifying glass to the way specific variants are handled.

This still also leaves OutputSubstitutionError, SelectionError and InputContributionError from producing JSON error responses to cancel a session with a v2 receiver. We're going to need to address that as part of #403. v2 Error variants also improperly produce JSON errors, but I think the way this was done by abusing fmt::Display is also an antipattern to fix at the same time that's addressed. I'd like to leave the JSON receiver error fixes to a follow up since what gets revealed is potentially sensitive and we should be reviewing that change with extra scrutiny.

See: #312, #392, #403

@coveralls
Copy link
Collaborator

coveralls commented Jan 14, 2025

Pull Request Test Coverage Report for Build 12814297177

Details

  • 48 of 188 (25.53%) changed or added relevant lines in 7 files are covered.
  • 2 unchanged lines in 2 files lost coverage.
  • Overall coverage decreased (-0.3%) to 60.489%

Changes Missing Coverage Covered Lines Changed/Added Lines %
payjoin/src/receive/v2/error.rs 2 9 22.22%
payjoin/src/receive/v1/mod.rs 16 25 64.0%
payjoin/src/receive/v2/mod.rs 13 22 59.09%
payjoin-cli/src/app/v2.rs 0 16 0.0%
payjoin-cli/src/app/v1.rs 0 27 0.0%
payjoin/src/receive/error.rs 17 53 32.08%
payjoin/src/receive/v1/error.rs 0 36 0.0%
Files with Coverage Reduction New Missed Lines %
payjoin/src/receive/error.rs 1 21.28%
payjoin-cli/src/app/v1.rs 1 0.0%
Totals Coverage Status
Change from base Build 12795849419: -0.3%
Covered Lines: 2947
Relevant Lines: 4872

💛 - Coveralls

@DanGould DanGould force-pushed the sep-receive-errors branch 4 times, most recently from d28133e to e002ea2 Compare January 15, 2025 00:02
@DanGould DanGould requested a review from spacebear21 January 15, 2025 00:08
@DanGould DanGould changed the title Initate receive v1,v2 error separation Separate receive::{v1,v2} error modules Jan 15, 2025
@DanGould DanGould marked this pull request as ready for review January 15, 2025 00:10
Copy link
Collaborator

@spacebear21 spacebear21 left a comment

Choose a reason for hiding this comment

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

This all seems very well thought-out. The only thing I'd add to this PR is docstrings for all touched Error types and their variants, so that your thought process is at least partially captured in source (e.g. what distinguishes a PayloadError from a RequestError).

Comment on lines 55 to 79
pub enum ValidationError {
Payload(PayloadError),
V1(v1::RequestError),
#[cfg(feature = "v2")]
V2(v2::SessionError),
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you add docstring descriptions for each variant here and in other error enums where they're missing (e.g. v1::InternalRequestError)? It would also be good to document the enums themselves.

Even if things might change in follow-up PRs, I think adding descriptions now forces us to think thoroughly about naming, where each type belongs, etc.

Describe the variants based on their source, not the response they're
supposed to produce in the v1 protocol, which is what they were set to
do before this change.
This is the big move, but it doesn't completely clean up the variants
into clean module fault lines. It chunks the work into submodules
but still has some leaky abstractions. The next commits will try to
draw cleaner lines.
Unify error variants produced by both v1 and v2 state machines
but handled in different paths. Deduplicate the code to handle them
together.
The v2-specific error types in the receive module deserve their own
type refleting those types in v1. I do not believe they are yet fully
handled in payjoin-cli so its error handling will need to be audited.
It is not a generic payjoin error. It's receive-specific.
A `_ => None` catchall could cause new error variants to be overlooked.
Functions should return the least abstract appropriate error which is
InternalRequestError in this case.
@DanGould
Copy link
Contributor Author

I added docstrings for all touched Error types and their variants, which was a great idea and made me reconsider names in some places.

receive::Error::External became receive::Error::Implementation because it didn't make sense to refer to it as External when working on an implementation. When your point of reference is external to the payjoin crate, the payjoin crate is external to you.

it also uncovered that some of the PayloadError types is not like the others: InternalPayloadError::FeeTooHigh only arises from receiver preferences, not from the Original PSBT Payload being invalid afaict. InternalPayloadError::PsbtBelowFeeRate is similar, in that it's a before-unexpressed preference problem rather (feerate isn't in the fragment params, for example) than a pure protocol validation problem.

So is InternalPayloadError::InputWeight which I believe will only get triggered by improper receiver input, so perhaps that data should be validated in contribute_inputs and then ignored by the point we get to the apply_fee state machine.

Either way both errors should make their way into the top level receive::Error to be returned to the Sender but they might belong in their own variants. I'd like to handle these in a follow up PR which propagats JSON errors more beautifully than is done now. (Or even split it into 2 prs, because this one is getting a bit large)

I made a couple other relevant changes in this push because I couldn't resist and they seemed non-controversial

  1. Specify explicit PayloadError::source() variants, explained in the commit, might miss new error variants if it uses _ to catch them all
  2. psbt_fee_rate is internal and should thus return its most specific error.

@DanGould DanGould requested a review from spacebear21 January 16, 2025 01:34
Copy link
Collaborator

@spacebear21 spacebear21 left a comment

Choose a reason for hiding this comment

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

Amazing, glad that suggestion helped! These error modules are starting to look S-tier.

I noticed one more spot where we use a catch-all in Error::source but otherwise this looks ready for merge.

InternalRequestError::Psbt(e) => Some(e),
InternalRequestError::Io(e) => Some(e),
InternalRequestError::InvalidContentLength(e) => Some(e),
_ => None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similar to your comment in bfd6f98 we should specify explicit variants here to not overlook new variants accidentally.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

specified 🫡

A `_` catchall could cause new error variants to be overlooked.
Copy link
Collaborator

@spacebear21 spacebear21 left a comment

Choose a reason for hiding this comment

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

ACK 44cbf91

@DanGould DanGould merged commit e439b69 into payjoin:master Jan 16, 2025
6 checks passed
@DanGould DanGould deleted the sep-receive-errors branch January 16, 2025 17:36
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.

Review usage of crate::receive::Error
3 participants