Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1d1e378
Move FinalizeProposalError to error mod
DanGould Aug 26, 2025
34e6ab1
Move v1-exclusive code to appropriate module
DanGould Aug 26, 2025
3a1fa44
Move receive::v1 to receive::common
DanGould Aug 26, 2025
9ac5afc
Move receive::common::exclusive to receive::common::v1
DanGould Aug 26, 2025
993258a
Move receive::common test fn to receive module
DanGould Aug 26, 2025
ff70bef
Remove unnecessary PayjoinProposal field
DanGould Aug 26, 2025
68987d0
Simplify visibility of core receive structs
DanGould Aug 26, 2025
66302af
Abstract v1-exclusive ProvisionalProposal onward
DanGould Aug 26, 2025
430db08
Use v2 logic in v2 tests
DanGould Aug 26, 2025
f619017
Make receive::common::v1::test private
DanGould Aug 26, 2025
4e307d8
Move receive::common::v1 to receive::v1
DanGould Aug 26, 2025
aa5fa74
Refactor WantsOutputs::from_proposal to ::new
DanGould Aug 27, 2025
f6a835a
Move WantsOutputs::new to the top of impl
DanGould Aug 27, 2025
efdd88b
Move interleave_shuffle to reduce visibility
DanGould Aug 27, 2025
9aa635a
Move test_pjos_disabled to common
DanGould Aug 27, 2025
51b31d1
Move test_avoid_uih_one_output to WantsOutputs containing mod
DanGould Aug 27, 2025
668377a
Move empty_candidate_inputs to common
DanGould Aug 27, 2025
19b2491
Add test_multiple_contribute_inputs() to common
DanGould Aug 27, 2025
6d75a4b
Move rest of tests into common
DanGould Aug 27, 2025
91b5316
Move tests to reduce common struct/field/fn scopes
DanGould Aug 27, 2025
eac5e77
Reduce PsbtContext method visibility
DanGould Aug 27, 2025
de883a6
Make .save(&persister).unwrap()s .expect()s
DanGould Aug 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
905 changes: 905 additions & 0 deletions payjoin/src/core/receive/common/mod.rs

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions payjoin/src/core/receive/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::{error, fmt};

use bitcoin::hashes::sha256d::Hash;

use crate::error_codes::ErrorCode::{
self, NotEnoughMoney, OriginalPsbtRejected, Unavailable, VersionUnsupported,
};
use crate::ImplementationError;

/// The top-level error type for the payjoin receiver
#[derive(Debug)]
Expand Down Expand Up @@ -399,6 +402,27 @@ impl From<InternalInputContributionError> for InputContributionError {
fn from(value: InternalInputContributionError) -> Self { InputContributionError(value) }
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum FinalizeProposalError {
/// The ntxid of the original PSBT does not match the ntxid of the finalized PSBT.
NtxidMismatch(Hash, Hash),
/// The implementation of the `wallet_process_psbt` function returned an error.
Implementation(ImplementationError),
}

impl std::fmt::Display for FinalizeProposalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NtxidMismatch(expected, actual) => {
write!(f, "Ntxid mismatch: expected {expected}, got {actual}")
}
Self::Implementation(e) => write!(f, "Implementation error: {e}"),
}
}
}

impl std::error::Error for FinalizeProposalError {}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
48 changes: 16 additions & 32 deletions payjoin/src/core/receive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@
use std::collections::BTreeMap;
use std::str::FromStr;

use bitcoin::hashes::sha256d::Hash;
use bitcoin::{
psbt, AddressType, FeeRate, OutPoint, Psbt, Script, ScriptBuf, Sequence, Transaction, TxIn,
TxOut, Weight,
};
pub(crate) use error::InternalPayloadError;
pub use error::{
Error, InputContributionError, JsonReply, OutputSubstitutionError, PayloadError,
ReplyableError, SelectionError,
};
pub(crate) use error::{FinalizeProposalError, InternalPayloadError};
use optional_parameters::Params;
use serde::{Deserialize, Serialize};

Expand All @@ -31,14 +30,13 @@ use crate::psbt::{
};
use crate::{ImplementationError, Version};

pub(crate) mod common;
mod error;
pub(crate) mod optional_parameters;

#[cfg(feature = "v1")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1")))]
pub mod v1;
#[cfg(not(feature = "v1"))]
pub(crate) mod v1;

#[cfg(feature = "v2")]
#[cfg_attr(docsrs, doc(cfg(feature = "v2")))]
Expand Down Expand Up @@ -242,9 +240,9 @@ pub(crate) fn parse_payload(
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct PsbtContext {
pub struct PsbtContext {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The receive::v2::SessionEvent::ProvisionalProposal(PsbtContext) requires this visibility. It's possible to wrap this struct if desired, but PsbtContext is the actual event diff that we're using. Perhaps it could be pruned further, just to the bitcoin::Psbt that's the payjoin_psbt since we already have the original psbt at the UncheckedProposal stage.

IMO UncheckedProposal((Original, Optioncrate::HpkePublicKey)) deserves its own type as well instead of a tuple but that can come after. The UncheckedProposal tuple should probably at least be deconstructed out of the nested tuple to UncheckedProposal(Original, Option<crate::HpkePublicKey>)

original_psbt: Psbt,
pub(crate) payjoin_psbt: Psbt,
payjoin_psbt: Psbt,
}

impl PsbtContext {
Expand Down Expand Up @@ -313,7 +311,7 @@ impl PsbtContext {
/// Finalization consists of two steps:
/// 1. Remove all sender signatures which were received with the original PSBT as these signatures are now invalid.
/// 2. Sign and finalize the resulting PSBT using the passed `wallet_process_psbt` signing function.
pub(crate) fn finalize_proposal(
fn finalize_proposal(
self,
wallet_process_psbt: impl Fn(&Psbt) -> Result<Psbt, ImplementationError>,
) -> Result<Psbt, FinalizeProposalError> {
Expand All @@ -337,31 +335,10 @@ impl PsbtContext {
}
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum FinalizeProposalError {
/// The ntxid of the original PSBT does not match the ntxid of the finalized PSBT.
NtxidMismatch(Hash, Hash),
/// The implementation of the `wallet_process_psbt` function returned an error.
Implementation(ImplementationError),
}

impl std::fmt::Display for FinalizeProposalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NtxidMismatch(expected, actual) => {
write!(f, "Ntxid mismatch: expected {expected}, got {actual}")
}
Self::Implementation(e) => write!(f, "Implementation error: {e}"),
}
}
}

impl std::error::Error for FinalizeProposalError {}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Original {
pub(crate) psbt: Psbt,
pub(crate) params: Params,
psbt: Psbt,
params: Params,
}

impl Original {
Expand Down Expand Up @@ -480,7 +457,7 @@ impl Original {
}

#[cfg(test)]
mod tests {
pub(crate) mod tests {
use bitcoin::absolute::{LockTime, Time};
use bitcoin::hashes::Hash;
use bitcoin::key::{PublicKey, WPubkeyHash};
Expand All @@ -489,7 +466,7 @@ mod tests {
use bitcoin::{
witness, Amount, PubkeyHash, ScriptBuf, ScriptHash, Txid, WScriptHash, XOnlyPublicKey,
};
use payjoin_test_utils::{DUMMY20, DUMMY32};
use payjoin_test_utils::{DUMMY20, DUMMY32, PARSED_ORIGINAL_PSBT, QUERY_PARAMS};

use super::*;
use crate::psbt::InternalPsbtInputError::InvalidScriptPubKey;
Expand All @@ -498,6 +475,13 @@ mod tests {
// We should pub(crate) it and moved to a common place.
const NON_WITNESS_DATA_WEIGHT: Weight = Weight::from_non_witness_data_size(32 + 4 + 4);

pub(crate) fn original_from_test_vector() -> Original {
let pairs = url::form_urlencoded::parse(QUERY_PARAMS.as_bytes());
let params = Params::from_query_pairs(pairs, &[Version::One])
.expect("Could not parse params from query pairs");
Original { psbt: PARSED_ORIGINAL_PSBT.clone(), params }
}

#[test]
fn input_pair_with_expected_weight() {
let p2wsh_txout = TxOut {
Expand Down
143 changes: 0 additions & 143 deletions payjoin/src/core/receive/v1/exclusive/mod.rs

This file was deleted.

Loading