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

payjoin / rust-payjoin / 15221119596

23 May 2025 11:50PM UTC coverage: 83.277% (-0.2%) from 83.467%
15221119596

Pull #705

github

web-flow
Merge 21ededced into a9cef3fe3
Pull Request #705: Transition away from using _danger-local-https

26 of 36 new or added lines in 4 files covered. (72.22%)

45 existing lines in 1 file now uncovered.

5966 of 7164 relevant lines covered (83.28%)

646.38 hits per line

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

42.55
/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(crate) 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

16
    pub fn set_selected_relay(&mut self, relay: payjoin::Url) { self.selected_relay = Some(relay); }
4✔
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

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

25
pub(crate) async fn unwrap_ohttp_keys_or_else_fetch(
1✔
26
    config: &Config,
1✔
27
    relay_state: 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

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

NEW
41
pub(crate) async fn fetch_keys(
×
UNCOV
42
    config: &Config,
×
NEW
43
    relay_state: 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 =
×
UNCOV
51
            relay_state.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

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

UNCOV
71
        let ohttp_keys = {
×
NEW
72
            payjoin::io::fetch_ohttp_keys(selected_relay.clone(), payjoin_directory.clone(), None)
×
NEW
73
                .await
×
74
        };
75

UNCOV
76
        match ohttp_keys {
×
UNCOV
77
            Ok(keys) => return Ok(Some(keys)),
×
UNCOV
78
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
UNCOV
79
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
80
            }
UNCOV
81
            Err(e) => {
×
UNCOV
82
                log::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
UNCOV
83
                relay_state
×
UNCOV
84
                    .lock()
×
UNCOV
85
                    .expect("Lock should not be poisoned")
×
UNCOV
86
                    .add_failed_relay(selected_relay);
×
87
            }
88
        }
89
    }
UNCOV
90
}
×
91

92
pub(crate) async fn validate_relay(
4✔
93
    config: &Config,
4✔
94
    relay_state: Arc<Mutex<RelayManager>>,
4✔
95
) -> Result<payjoin::Url> {
4✔
96
    use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
97
    let payjoin_directory = config.v2()?.pj_directory.clone();
4✔
98
    let relays = config.v2()?.ohttp_relays.clone();
4✔
99

100
    loop {
4✔
101
        let failed_relays =
4✔
102
            relay_state.lock().expect("Lock should not be poisoned").get_failed_relays();
4✔
103

4✔
104
        let remaining_relays: Vec<_> =
4✔
105
            relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
4✔
106

4✔
107
        if remaining_relays.is_empty() {
4✔
UNCOV
108
            return Err(anyhow!("No valid relays available"));
×
109
        }
4✔
110

111
        let selected_relay =
4✔
112
            match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
4✔
113
                Some(relay) => relay.clone(),
4✔
UNCOV
114
                None => return Err(anyhow!("Failed to select from remaining relays")),
×
115
            };
116

117
        relay_state
4✔
118
            .lock()
4✔
119
            .expect("Lock should not be poisoned")
4✔
120
            .set_selected_relay(selected_relay.clone());
4✔
121

122
        let ohttp_keys = {
4✔
123
            payjoin::io::fetch_ohttp_keys(selected_relay.clone(), payjoin_directory.clone(), None)
4✔
124
                .await
4✔
125
        };
126

127
        match Ok(ohttp_keys) {
4✔
128
            Ok(_) => return Ok(selected_relay),
4✔
UNCOV
129
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
UNCOV
130
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
131
            }
UNCOV
132
            Err(e) => {
×
UNCOV
133
                log::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
UNCOV
134
                relay_state
×
UNCOV
135
                    .lock()
×
UNCOV
136
                    .expect("Lock should not be poisoned")
×
UNCOV
137
                    .add_failed_relay(selected_relay);
×
138
            }
139
        }
140
    }
141
}
4✔
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