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

payjoin / rust-payjoin / 24360962678

13 Apr 2026 06:50PM UTC coverage: 84.343% (+0.003%) from 84.34%
24360962678

Pull #1399

github

web-flow
Merge 9fa0ec8cd into f7b415a7e
Pull Request #1399: Split resume session relays

11 of 13 new or added lines in 3 files covered. (84.62%)

1 existing line in 1 file now uncovered.

10795 of 12799 relevant lines covered (84.34%)

412.57 hits per line

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

75.81
/payjoin-cli/src/app/v2/ohttp.rs
1
use anyhow::{anyhow, Result};
2

3
use super::Config;
4

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

11
impl RelayManager {
12
    pub fn new() -> Self { RelayManager { selected_relay: None, failed_relays: Vec::new() } }
7✔
13

14
    pub fn set_selected_relay(&mut self, relay: url::Url) { self.selected_relay = Some(relay); }
7✔
15

16
    pub fn get_selected_relay(&self) -> Option<url::Url> { self.selected_relay.clone() }
6✔
17

18
    pub fn add_failed_relay(&mut self, relay: url::Url) { self.failed_relays.push(relay); }
×
19

20
    pub fn get_failed_relays(&self) -> Vec<url::Url> { self.failed_relays.clone() }
7✔
21
}
22

23
pub(crate) struct ValidatedOhttpKeys {
24
    pub(crate) ohttp_keys: payjoin::OhttpKeys,
25
    pub(crate) relay_url: url::Url,
26
}
27

28
pub(crate) async fn unwrap_ohttp_keys_or_else_fetch(
7✔
29
    config: &Config,
7✔
30
    directory: Option<url::Url>,
7✔
31
    relay_manager: &mut RelayManager,
7✔
32
) -> Result<ValidatedOhttpKeys> {
7✔
33
    if let Some(ohttp_keys) = config.v2()?.ohttp_keys.clone() {
7✔
34
        println!("Using OHTTP Keys from config");
6✔
35
        let validated = fetch_ohttp_keys(config, directory, relay_manager).await?;
6✔
36
        Ok(ValidatedOhttpKeys { ohttp_keys, relay_url: validated.relay_url })
5✔
37
    } else {
38
        println!("Bootstrapping private network transport over Oblivious HTTP");
1✔
39
        let fetched_keys = fetch_ohttp_keys(config, directory, relay_manager).await?;
1✔
40

41
        Ok(fetched_keys)
1✔
42
    }
43
}
6✔
44

45
async fn fetch_ohttp_keys(
7✔
46
    config: &Config,
7✔
47
    directory: Option<url::Url>,
7✔
48
    relay_manager: &mut RelayManager,
7✔
49
) -> Result<ValidatedOhttpKeys> {
7✔
50
    use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
51
    let payjoin_directory = directory.unwrap_or(config.v2()?.pj_directory.clone());
7✔
52
    let relays = config.v2()?.ohttp_relays.clone();
7✔
53

54
    if relays.len() < 2 {
7✔
55
        tracing::warn!(
7✔
56
            "Only one OHTTP relay configured. Add more ohttp_relays to improve privacy."
57
        );
NEW
58
    }
×
59

60
    loop {
61
        let failed_relays = relay_manager.get_failed_relays();
7✔
62

63
        let remaining_relays: Vec<_> =
7✔
64
            relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
7✔
65

66
        if remaining_relays.is_empty() {
7✔
67
            return Err(anyhow!("No valid relays available"));
×
68
        }
7✔
69

70
        let selected_relay =
7✔
71
            match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
7✔
72
                Some(relay) => relay.clone(),
7✔
73
                None => return Err(anyhow!("Failed to select from remaining relays")),
×
74
            };
75

76
        relay_manager.set_selected_relay(selected_relay.clone());
7✔
77

78
        let ohttp_keys = {
6✔
79
            #[cfg(feature = "_manual-tls")]
80
            {
81
                if let Some(cert_path) = config.root_certificate.as_ref() {
7✔
82
                    let cert_der = std::fs::read(cert_path)?;
7✔
83
                    payjoin::io::fetch_ohttp_keys_with_cert(
7✔
84
                        selected_relay.as_str(),
7✔
85
                        payjoin_directory.as_str(),
7✔
86
                        &cert_der,
7✔
87
                    )
7✔
88
                    .await
7✔
89
                } else {
90
                    payjoin::io::fetch_ohttp_keys(
×
91
                        selected_relay.as_str(),
×
92
                        payjoin_directory.as_str(),
×
93
                    )
×
94
                    .await
×
95
                }
96
            }
97
            #[cfg(not(feature = "_manual-tls"))]
98
            payjoin::io::fetch_ohttp_keys(selected_relay.as_str(), payjoin_directory.as_str()).await
99
        };
100

101
        match ohttp_keys {
×
102
            Ok(keys) =>
6✔
103
                return Ok(ValidatedOhttpKeys { ohttp_keys: keys, relay_url: selected_relay }),
6✔
104
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
105
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
106
            }
107
            Err(e) => {
×
108
                tracing::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
NEW
109
                relay_manager.add_failed_relay(selected_relay);
×
110
            }
111
        }
112
    }
113
}
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