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

payjoin / rust-payjoin / 15303198513

28 May 2025 02:44PM UTC coverage: 83.805% (-0.7%) from 84.553%
15303198513

Pull #705

github

web-flow
Merge f04cc7510 into 87042266d
Pull Request #705: Adjust _danger-local-https to be the default to prevent dangerous cert vulnerability when building with --all-features

11 of 28 new or added lines in 3 files covered. (39.29%)

64 existing lines in 3 files now uncovered.

6520 of 7780 relevant lines covered (83.8%)

595.35 hits per line

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

18.81
/payjoin-cli/src/app/v2/ohttp.rs
1
use std::sync::{Arc, Mutex};
2

3
use anyhow::{anyhow, Result};
4

5
use super::Config;
6

7
#[derive(Debug, Clone)]
8
pub struct RelayManager {
9
    selected_relay: Option<payjoin::Url>,
10
    failed_relays: Vec<payjoin::Url>,
11
}
12

13
impl RelayManager {
14
    pub fn new() -> Self { RelayManager { selected_relay: None, failed_relays: Vec::new() } }
4✔
15

UNCOV
16
    pub fn set_selected_relay(&mut self, relay: payjoin::Url) { self.selected_relay = Some(relay); }
×
17

18
    pub fn get_selected_relay(&self) -> Option<payjoin::Url> { self.selected_relay.clone() }
6✔
19

UNCOV
20
    pub fn add_failed_relay(&mut self, relay: payjoin::Url) { self.failed_relays.push(relay); }
×
21

UNCOV
22
    pub fn get_failed_relays(&self) -> Vec<payjoin::Url> { self.failed_relays.clone() }
×
23
}
24

25
pub(crate) async fn unwrap_ohttp_keys_or_else_fetch(
1✔
26
    config: &Config,
1✔
27
    relay_manager: Arc<Mutex<RelayManager>>,
1✔
28
) -> Result<payjoin::OhttpKeys> {
1✔
29
    if let Some(keys) = config.v2()?.ohttp_keys.clone() {
1✔
30
        println!("Using OHTTP Keys from config");
1✔
31
        Ok(keys)
1✔
32
    } else {
33
        println!("Bootstrapping private network transport over Oblivious HTTP");
×
34

×
NEW
35
        fetch_keys(config, relay_manager.clone())
×
36
            .await
×
37
            .and_then(|keys| keys.ok_or_else(|| anyhow::anyhow!("No OHTTP keys found")))
×
38
    }
39
}
1✔
40

UNCOV
41
async fn fetch_keys(
×
UNCOV
42
    config: &Config,
×
NEW
43
    relay_manager: Arc<Mutex<RelayManager>>,
×
UNCOV
44
) -> Result<Option<payjoin::OhttpKeys>> {
×
45
    use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
UNCOV
46
    let payjoin_directory = config.v2()?.pj_directory.clone();
×
UNCOV
47
    let relays = config.v2()?.ohttp_relays.clone();
×
48

UNCOV
49
    loop {
×
UNCOV
50
        let failed_relays =
×
NEW
51
            relay_manager.lock().expect("Lock should not be poisoned").get_failed_relays();
×
UNCOV
52

×
UNCOV
53
        let remaining_relays: Vec<_> =
×
UNCOV
54
            relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
×
UNCOV
55

×
UNCOV
56
        if remaining_relays.is_empty() {
×
UNCOV
57
            return Err(anyhow!("No valid relays available"));
×
UNCOV
58
        }
×
59

UNCOV
60
        let selected_relay =
×
UNCOV
61
            match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
×
UNCOV
62
                Some(relay) => relay.clone(),
×
UNCOV
63
                None => return Err(anyhow!("Failed to select from remaining relays")),
×
64
            };
65

NEW
66
        relay_manager
×
UNCOV
67
            .lock()
×
UNCOV
68
            .expect("Lock should not be poisoned")
×
UNCOV
69
            .set_selected_relay(selected_relay.clone());
×
70

71
        #[cfg(not(feature = "pki-https"))]
NEW
72
        let ohttp_keys = {
×
NEW
73
            let cert_der = crate::app::read_local_cert()?;
×
NEW
74
            payjoin::io::fetch_ohttp_keys_with_cert(
×
NEW
75
                selected_relay.clone(),
×
NEW
76
                payjoin_directory.clone(),
×
NEW
77
                cert_der,
×
NEW
78
            )
×
NEW
79
            .await
×
80
        };
81

82
        #[cfg(feature = "pki-https")]
83
        let ohttp_keys = {
84
            payjoin::io::fetch_ohttp_keys(selected_relay.clone(), payjoin_directory.clone()).await
85
        };
86

UNCOV
87
        match ohttp_keys {
×
UNCOV
88
            Ok(keys) => return Ok(Some(keys)),
×
UNCOV
89
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
UNCOV
90
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
91
            }
UNCOV
92
            Err(e) => {
×
UNCOV
93
                log::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
NEW
94
                relay_manager
×
UNCOV
95
                    .lock()
×
UNCOV
96
                    .expect("Lock should not be poisoned")
×
UNCOV
97
                    .add_failed_relay(selected_relay);
×
98
            }
99
        }
100
    }
UNCOV
101
}
×
102

103
//#[cfg(feature = "pki-https")]
104
pub(crate) async fn validate_relay(
6✔
105
    config: &Config,
6✔
106
    relay_manager: Arc<Mutex<RelayManager>>,
6✔
107
) -> Result<payjoin::Url> {
6✔
108
    use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
109
    let payjoin_directory = config.v2()?.pj_directory.clone();
6✔
110
    let relays = config.v2()?.ohttp_relays.clone();
6✔
111

112
    if let Some(relay) = config.v2()?.ohttp_relays.first().cloned() {
6✔
113
        return Ok(relay);
6✔
NEW
114
    }
×
115

UNCOV
116
    loop {
×
UNCOV
117
        let failed_relays =
×
NEW
118
            relay_manager.lock().expect("Lock should not be poisoned").get_failed_relays();
×
UNCOV
119

×
UNCOV
120
        let remaining_relays: Vec<_> =
×
UNCOV
121
            relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
×
UNCOV
122

×
UNCOV
123
        if remaining_relays.is_empty() {
×
UNCOV
124
            return Err(anyhow!("No valid relays available"));
×
UNCOV
125
        }
×
126

UNCOV
127
        let selected_relay =
×
UNCOV
128
            match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
×
UNCOV
129
                Some(relay) => relay.clone(),
×
UNCOV
130
                None => return Err(anyhow!("Failed to select from remaining relays")),
×
131
            };
132

NEW
133
        relay_manager
×
UNCOV
134
            .lock()
×
UNCOV
135
            .expect("Lock should not be poisoned")
×
UNCOV
136
            .set_selected_relay(selected_relay.clone());
×
137

UNCOV
138
        let ohttp_keys =
×
UNCOV
139
            payjoin::io::fetch_ohttp_keys(selected_relay.clone(), payjoin_directory.clone()).await;
×
140

UNCOV
141
        match ohttp_keys {
×
UNCOV
142
            Ok(_) => return Ok(selected_relay),
×
UNCOV
143
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
UNCOV
144
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
145
            }
UNCOV
146
            Err(e) => {
×
UNCOV
147
                log::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
NEW
148
                relay_manager
×
UNCOV
149
                    .lock()
×
UNCOV
150
                    .expect("Lock should not be poisoned")
×
UNCOV
151
                    .add_failed_relay(selected_relay);
×
152
            }
153
        }
154
    }
155
}
6✔
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