• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

payjoin / rust-payjoin / 14713397893

28 Apr 2025 04:57PM UTC coverage: 82.027% (+0.09%) from 81.936%
14713397893

push

github

web-flow
Duplicate proposals catch in ns1r (#642)

When building a multiparty proposal we did not have a catch to make sure
that the proposals were all unique and as such a multiparty could be
built by just adding the same proposal over and over. This creates a new
error IdenticalProposals that checks to make sure the contexts are not
matching when adding to a multiparty.

Closes #640

116 of 136 new or added lines in 3 files covered. (85.29%)

2 existing lines in 1 file now uncovered.

5431 of 6621 relevant lines covered (82.03%)

698.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/payjoin/src/receive/multiparty/error.rs
1
use core::fmt;
2
use std::error;
3

4
use crate::uri::ShortId;
5

6
#[derive(Debug)]
7
pub struct MultipartyError(InternalMultipartyError);
8

9
#[derive(Debug)]
10
pub(crate) enum InternalMultipartyError {
11
    /// Not enough proposals
12
    NotEnoughProposals,
13
    /// Duplicate proposals
14
    IdenticalProposals(IdenticalProposalError),
15
    /// Proposal version not supported
16
    ProposalVersionNotSupported(usize),
17
    /// Optimistic merge not supported
18
    OptimisticMergeNotSupported,
19
    /// Bitcoin Internal Error
20
    BitcoinExtractTxError(Box<bitcoin::psbt::ExtractTxError>),
21
    /// Input in Finalized Proposal is missing witness or script_sig
22
    InputMissingWitnessOrScriptSig,
23
    /// Failed to combine psbts
24
    FailedToCombinePsbts(bitcoin::psbt::Error),
25
}
26

27
#[derive(Debug)]
28
pub enum IdenticalProposalError {
29
    IdenticalPsbts(Box<bitcoin::Psbt>, Box<bitcoin::Psbt>),
30
    IdenticalContexts(Box<ShortId>, Box<ShortId>),
31
}
32

33
impl std::fmt::Display for IdenticalProposalError {
34
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4✔
35
        match self {
4✔
36
            IdenticalProposalError::IdenticalPsbts(current_psbt, incoming_psbt) => write!(
2✔
37
                f,
2✔
38
                "Two sender psbts are identical\n left psbt: {current_psbt}\n right psbt: {incoming_psbt}"
2✔
39
            ),
2✔
40
            IdenticalProposalError::IdenticalContexts(current_context, incoming_context) => write!(
2✔
41
                f,
2✔
42
                "Two sender contexts are identical\n left id: {current_context}\n right id: {incoming_context}"
2✔
43
            ),
2✔
44
        }
45
    }
4✔
46
}
47

48
impl From<InternalMultipartyError> for MultipartyError {
49
    fn from(e: InternalMultipartyError) -> Self { MultipartyError(e) }
6✔
50
}
51

52
impl fmt::Display for MultipartyError {
53
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6✔
54
        match &self.0 {
6✔
55
            InternalMultipartyError::NotEnoughProposals => write!(f, "Not enough proposals"),
2✔
56
            InternalMultipartyError::IdenticalProposals(e) =>
4✔
57
                write!(f, "More than one identical participant: {e}"),
4✔
58
            InternalMultipartyError::ProposalVersionNotSupported(v) =>
×
59
                write!(f, "Proposal version not supported: {v}"),
×
60
            InternalMultipartyError::OptimisticMergeNotSupported =>
61
                write!(f, "Optimistic merge not supported"),
×
62
            InternalMultipartyError::BitcoinExtractTxError(e) =>
×
63
                write!(f, "Bitcoin extract tx error: {e:?}"),
×
64
            InternalMultipartyError::InputMissingWitnessOrScriptSig =>
65
                write!(f, "Input in Finalized Proposal is missing witness or script_sig"),
×
66
            InternalMultipartyError::FailedToCombinePsbts(e) =>
×
67
                write!(f, "Failed to combine psbts: {e:?}"),
×
68
        }
69
    }
6✔
70
}
71

72
impl error::Error for MultipartyError {
73
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
×
74
        match &self.0 {
×
75
            InternalMultipartyError::NotEnoughProposals => None,
×
NEW
76
            InternalMultipartyError::IdenticalProposals(_) => None,
×
77
            InternalMultipartyError::ProposalVersionNotSupported(_) => None,
×
78
            InternalMultipartyError::OptimisticMergeNotSupported => None,
×
79
            InternalMultipartyError::BitcoinExtractTxError(e) => Some(e),
×
80
            InternalMultipartyError::InputMissingWitnessOrScriptSig => None,
×
81
            InternalMultipartyError::FailedToCombinePsbts(e) => Some(e),
×
82
        }
83
    }
×
84
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc