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

payjoin / rust-payjoin / 14643493351

24 Apr 2025 01:57PM UTC coverage: 81.929% (+0.09%) from 81.835%
14643493351

Pull #667

github

web-flow
Merge e89f929e9 into 3b23dcaf5
Pull Request #667: Fix uninline format clippy violations

54 of 136 new or added lines in 27 files covered. (39.71%)

2 existing lines in 1 file now uncovered.

5327 of 6502 relevant lines covered (81.93%)

711.21 hits per line

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

78.31
/payjoin/src/receive/optional_parameters.rs
1
use std::borrow::Borrow;
2
use std::fmt;
3

4
use bitcoin::FeeRate;
5
use log::warn;
6

7
use crate::output_substitution::OutputSubstitution;
8

9
#[derive(Debug, Clone)]
10
pub(crate) struct Params {
11
    // version
12
    pub v: usize,
13
    // disableoutputsubstitution
14
    pub output_substitution: OutputSubstitution,
15
    // maxadditionalfeecontribution, additionalfeeoutputindex
16
    pub additional_fee_contribution: Option<(bitcoin::Amount, usize)>,
17
    // minfeerate
18
    pub min_fee_rate: FeeRate,
19
    #[cfg(feature = "_multiparty")]
20
    /// Opt in to optimistic psbt merge
21
    pub optimistic_merge: bool,
22
}
23

24
impl Default for Params {
25
    fn default() -> Self {
38✔
26
        Params {
38✔
27
            v: 1,
38✔
28
            output_substitution: OutputSubstitution::Enabled,
38✔
29
            additional_fee_contribution: None,
38✔
30
            min_fee_rate: FeeRate::BROADCAST_MIN,
38✔
31
            #[cfg(feature = "_multiparty")]
38✔
32
            optimistic_merge: false,
38✔
33
        }
38✔
34
    }
38✔
35
}
36

37
impl Params {
38
    pub fn from_query_pairs<K, V, I>(
34✔
39
        pairs: I,
34✔
40
        supported_versions: &'static [usize],
34✔
41
    ) -> Result<Self, Error>
34✔
42
    where
34✔
43
        I: Iterator<Item = (K, V)>,
34✔
44
        K: Borrow<str> + Into<String>,
34✔
45
        V: Borrow<str> + Into<String>,
34✔
46
    {
34✔
47
        let mut params = Params::default();
34✔
48

34✔
49
        let mut additional_fee_output_index = None;
34✔
50
        let mut max_additional_fee_contribution = None;
34✔
51

52
        for (key, v) in pairs {
132✔
53
            match (key.borrow(), v.borrow()) {
98✔
54
                ("v", version) =>
98✔
55
                    params.v = match version.parse::<usize>() {
24✔
56
                        Ok(version) if supported_versions.contains(&version) => version,
24✔
57
                        _ => return Err(Error::UnknownVersion { supported_versions }),
×
58
                    },
59
                ("additionalfeeoutputindex", index) =>
74✔
60
                    additional_fee_output_index = match index.parse::<usize>() {
21✔
61
                        Ok(index) => Some(index),
21✔
NEW
62
                        Err(_error) => {
×
NEW
63
                            warn!("bad `additionalfeeoutputindex` query value '{index}': {_error}");
×
NEW
64
                            None
×
65
                        }
66
                    },
67
                ("maxadditionalfeecontribution", fee) =>
53✔
68
                    max_additional_fee_contribution = match bitcoin::Amount::from_str_in(
21✔
69
                        fee,
21✔
70
                        bitcoin::Denomination::Satoshi,
21✔
71
                    ) {
21✔
72
                        Ok(contribution) => Some(contribution),
21✔
73
                        Err(_error) => {
×
74
                            warn!(
×
NEW
75
                                "bad `maxadditionalfeecontribution` query value '{fee}': {_error}"
×
76
                            );
77
                            None
×
78
                        }
79
                    },
80
                ("minfeerate", fee_rate) =>
32✔
81
                    params.min_fee_rate = match fee_rate.parse::<f32>() {
14✔
82
                        Ok(fee_rate_sat_per_vb) => {
14✔
83
                            // TODO Parse with serde when rust-bitcoin supports it
14✔
84
                            let fee_rate_sat_per_kwu = fee_rate_sat_per_vb * 250.0_f32;
14✔
85
                            // since it's a minimum, we want to round up
14✔
86
                            FeeRate::from_sat_per_kwu(fee_rate_sat_per_kwu.ceil() as u64)
14✔
87
                        }
88
                        Err(_) => return Err(Error::FeeRate),
×
89
                    },
90
                ("disableoutputsubstitution", v) =>
18✔
91
                    params.output_substitution = if v == "true" {
5✔
92
                        OutputSubstitution::Disabled
5✔
93
                    } else {
94
                        OutputSubstitution::Enabled
×
95
                    },
96
                #[cfg(feature = "_multiparty")]
97
                ("optimisticmerge", v) => params.optimistic_merge = v == "true",
13✔
98
                _ => (),
×
99
            }
100
        }
101

102
        match (max_additional_fee_contribution, additional_fee_output_index) {
34✔
103
            (Some(amount), Some(index)) =>
21✔
104
                params.additional_fee_contribution = Some((amount, index)),
21✔
105
            (Some(_), None) | (None, Some(_)) => {
NEW
106
                warn!("only one additional-fee parameter specified: {params:?}");
×
107
            }
108
            _ => (),
13✔
109
        }
110

111
        log::debug!("parsed optional parameters: {params:?}");
34✔
112
        Ok(params)
34✔
113
    }
34✔
114
}
115

116
#[derive(Debug)]
117
pub(crate) enum Error {
118
    UnknownVersion { supported_versions: &'static [usize] },
119
    FeeRate,
120
}
121

122
impl fmt::Display for Error {
123
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
×
124
        match self {
×
125
            Error::UnknownVersion { .. } => write!(f, "unknown version"),
×
126
            Error::FeeRate => write!(f, "could not parse feerate"),
×
127
        }
128
    }
×
129
}
130

131
impl std::error::Error for Error {
132
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
×
133
}
134

135
#[cfg(test)]
136
pub(crate) mod test {
137
    use bitcoin::Amount;
138

139
    use super::*;
140

141
    #[test]
142
    fn test_parse_params() {
1✔
143
        use bitcoin::FeeRate;
144

145
        let pairs = url::form_urlencoded::parse(b"maxadditionalfeecontribution=182&additionalfeeoutputindex=0&minfeerate=1&disableoutputsubstitution=true&optimisticmerge=true");
1✔
146
        let params =
1✔
147
            Params::from_query_pairs(pairs, &[1]).expect("Could not parse params from query pairs");
1✔
148
        assert_eq!(params.v, 1);
1✔
149
        assert_eq!(params.output_substitution, OutputSubstitution::Disabled);
1✔
150
        assert_eq!(params.additional_fee_contribution, Some((Amount::from_sat(182), 0)));
1✔
151
        assert_eq!(params.min_fee_rate, FeeRate::BROADCAST_MIN);
1✔
152
        #[cfg(feature = "_multiparty")]
153
        assert!(params.optimistic_merge)
1✔
154
    }
1✔
155
}
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