switchgear_testing/credentials/
lightning.rs1use crate::credentials::download_credentials;
2use crate::services::{IntegrationTestServices, LightningIntegrationTestServices};
3use anyhow::{anyhow, Context};
4use secp256k1::PublicKey;
5use std::fs;
6use std::path::{Path, PathBuf};
7use tempfile::TempDir;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct ClnRegTestLnNode {
11 pub public_key: PublicKey,
12 pub address: String,
13 pub ca_cert_path: PathBuf,
14 pub client_cert_path: PathBuf,
15 pub client_key_path: PathBuf,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct LndRegTestLnNode {
20 pub public_key: PublicKey,
21 pub address: String,
22 pub tls_cert_path: PathBuf,
23 pub macaroon_path: PathBuf,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub struct RegTestLnNodes {
28 pub cln: ClnRegTestLnNode,
29 pub lnd: LndRegTestLnNode,
30}
31
32#[derive(Copy, Clone, Debug)]
33enum RegTestLnNodeType {
34 Cln,
35 Lnd,
36}
37
38pub struct LnCredentials {
39 credentials_dir: TempDir,
40 lightning: LightningIntegrationTestServices,
41}
42
43impl LnCredentials {
44 pub fn create() -> anyhow::Result<Self> {
45 let services = IntegrationTestServices::new();
46 let credentials_dir = TempDir::new()?;
47 download_credentials(credentials_dir.path(), services.credentials())?;
48 Ok(Self {
49 credentials_dir,
50 lightning: services.lightning().clone(),
51 })
52 }
53
54 pub fn get_backends(&self) -> anyhow::Result<RegTestLnNodes> {
55 let credentials = self.credentials_dir.path().join("credentials");
56 let base_path = credentials.as_path();
57
58 let entries = fs::read_dir(base_path)
59 .with_context(|| format!("reading directory {}", base_path.display()))?;
60
61 let mut cln = None;
62 let mut lnd = None;
63 for entry in entries {
64 let entry = entry
65 .with_context(|| format!("reading directory entry in {}", base_path.display(),))?;
66
67 let path = entry.path();
68
69 if !path.is_dir() {
70 continue;
71 }
72
73 let dir_name = match path.file_name() {
74 Some(name) => match name.to_str() {
75 Some(s) => s,
76 None => continue,
77 },
78 None => continue,
79 };
80
81 let node_type = if dir_name.starts_with("cln") {
82 RegTestLnNodeType::Cln
83 } else if dir_name.starts_with("lnd") {
84 RegTestLnNodeType::Lnd
85 } else {
86 continue;
87 };
88
89 let node_id_path = path.join("node_id");
90 let node_id_str = fs::read_to_string(&node_id_path)
91 .with_context(|| format!("reading node ID from {}", node_id_path.display(),))?;
92
93 let node_id_hex = node_id_str.trim();
94 let node_id_bytes = hex::decode(node_id_hex)
95 .with_context(|| format!("decoding {} node ID to hex", node_id_path.display(),))?;
96
97 let public_key = PublicKey::from_slice(&node_id_bytes).with_context(|| {
98 format!("parsing {} public key from bytes", node_id_path.display(),)
99 })?;
100
101 match node_type {
102 RegTestLnNodeType::Cln => {
103 cln = Some(Self::build_cln_node(
104 public_key,
105 &self.lightning.cln,
106 &path,
107 )?);
108 }
109 RegTestLnNodeType::Lnd => {
110 lnd = Some(Self::build_lnd_node(
111 public_key,
112 &self.lightning.lnd,
113 &path,
114 )?);
115 }
116 }
117
118 if cln.is_some() && lnd.is_some() {
119 break;
120 }
121 }
122
123 Ok(RegTestLnNodes {
124 cln: cln.ok_or_else(|| {
125 anyhow!(
126 "cln credentials not found in {}",
127 credentials.to_string_lossy()
128 )
129 })?,
130 lnd: lnd.ok_or_else(|| {
131 anyhow!(
132 "lnd credentials not found in {}",
133 credentials.to_string_lossy()
134 )
135 })?,
136 })
137 }
138
139 fn build_cln_node(
140 public_key: PublicKey,
141 address: &str,
142 node_path: &Path,
143 ) -> anyhow::Result<ClnRegTestLnNode> {
144 let ca_cert_path = node_path.join("ca.pem");
145 let ca_cert_path = ca_cert_path.canonicalize().with_context(|| {
146 format!("canonicalizing CLN CA cert path {}", ca_cert_path.display(),)
147 })?;
148 let client_cert_path = node_path.join("client.pem");
149 let client_cert_path = client_cert_path.canonicalize().with_context(|| {
150 format!(
151 "canonicalizing CLN client cert path {}",
152 client_cert_path.display(),
153 )
154 })?;
155 let client_key_path = node_path.join("client-key.pem");
156 let client_key_path = client_key_path.canonicalize().with_context(|| {
157 format!(
158 "canonicalizing CLN client key path {}",
159 client_key_path.display(),
160 )
161 })?;
162
163 Ok(ClnRegTestLnNode {
164 public_key,
165 address: address.to_string(),
166 ca_cert_path,
167 client_cert_path,
168 client_key_path,
169 })
170 }
171
172 fn build_lnd_node(
173 public_key: PublicKey,
174 address: &str,
175 node_path: &Path,
176 ) -> anyhow::Result<LndRegTestLnNode> {
177 let tls_cert_path = node_path.join("tls.cert");
178 let tls_cert_path = tls_cert_path.canonicalize().with_context(|| {
179 format!(
180 "canonicalizing LND TLS cert path {}",
181 tls_cert_path.display(),
182 )
183 })?;
184 let macaroon_path = node_path.join("admin.macaroon");
185 let macaroon_path = macaroon_path.canonicalize().with_context(|| {
186 format!(
187 "canonicalizing LND macaroon path {}",
188 macaroon_path.display(),
189 )
190 })?;
191
192 Ok(LndRegTestLnNode {
193 public_key,
194 address: address.to_string(),
195 tls_cert_path,
196 macaroon_path,
197 })
198 }
199}