Skip to content

Commit 2646629

Browse files
committed
Enable using VssStore with VssHeaderProvider.
1 parent 26e61e8 commit 2646629

File tree

4 files changed

+86
-22
lines changed

4 files changed

+86
-22
lines changed

src/builder.rs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ use bitcoin::secp256k1::PublicKey;
6565
use bitcoin::{BlockHash, Network};
6666

6767
#[cfg(any(vss, vss_test))]
68-
use bitcoin::bip32::ChildNumber;
68+
use bitcoin::bip32::{ChildNumber, Xpriv};
69+
#[cfg(any(vss, vss_test))]
70+
use std::collections::HashMap;
6971
use std::convert::TryInto;
7072
use std::default::Default;
7173
use std::fmt;
@@ -74,6 +76,8 @@ use std::path::PathBuf;
7476
use std::sync::atomic::AtomicBool;
7577
use std::sync::{Arc, Mutex, RwLock};
7678
use std::time::SystemTime;
79+
#[cfg(any(vss, vss_test))]
80+
use vss_client::headers::{FixedHeaders, VssHeaderProvider};
7781

7882
#[derive(Debug, Clone)]
7983
enum ChainDataSourceConfig {
@@ -357,36 +361,56 @@ impl NodeBuilder {
357361
self.build_with_store(kv_store)
358362
}
359363

360-
/// Builds a [`Node`] instance with a [`VssStore`] backend and according to the options
364+
/// Builds a [`Node`] instance with a [VSS] backend and according to the options
361365
/// previously configured.
366+
///
367+
/// Uses [`FixedHeaders`] as default method for authentication/authorization.
368+
/// Given `fixed_headers` are included as it is in all the requests made to VSS.
369+
///
370+
/// **Caution**: VSS support is in **alpha** and is considered experimental.
371+
/// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
372+
/// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
373+
///
374+
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
362375
#[cfg(any(vss, vss_test))]
363-
pub fn build_with_vss_store(&self, url: String, store_id: String) -> Result<Node, BuildError> {
364-
use bitcoin::key::Secp256k1;
376+
pub fn build_with_vss_store_and_fixed_headers(
377+
&self, vss_url: String, store_id: String, fixed_headers: HashMap<String, String>,
378+
) -> Result<Node, BuildError> {
379+
let header_provider = Arc::new(FixedHeaders::new(fixed_headers));
380+
381+
self.build_with_vss_store_and_header_provider(vss_url, store_id, header_provider)
382+
}
365383

384+
/// Builds a [`Node`] instance with a [VSS] backend and according to the options
385+
/// previously configured.
386+
///
387+
/// Given `header_provider` is used to attach headers to every request made
388+
/// to VSS.
389+
///
390+
/// **Caution**: VSS support is in **alpha** and is considered experimental.
391+
/// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
392+
/// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
393+
///
394+
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
395+
#[cfg(any(vss, vss_test))]
396+
pub fn build_with_vss_store_and_header_provider(
397+
&self, vss_url: String, store_id: String, header_provider: Arc<dyn VssHeaderProvider>,
398+
) -> Result<Node, BuildError> {
366399
let logger = setup_logger(&self.config)?;
367400

368401
let seed_bytes = seed_bytes_from_config(
369402
&self.config,
370403
self.entropy_source_config.as_ref(),
371404
Arc::clone(&logger),
372405
)?;
373-
let config = Arc::new(self.config.clone());
374406

375-
let xprv = bitcoin::bip32::Xpriv::new_master(config.network, &seed_bytes).map_err(|e| {
376-
log_error!(logger, "Failed to derive master secret: {}", e);
377-
BuildError::InvalidSeedBytes
378-
})?;
407+
let config = Arc::new(self.config.clone());
379408

380-
let vss_xprv = xprv
381-
.derive_priv(&Secp256k1::new(), &[ChildNumber::Hardened { index: 877 }])
382-
.map_err(|e| {
383-
log_error!(logger, "Failed to derive VSS secret: {}", e);
384-
BuildError::KVStoreSetupFailed
385-
})?;
409+
let vss_xprv = derive_vss_xprv(config.clone(), &seed_bytes, Arc::clone(&logger))?;
386410

387411
let vss_seed_bytes: [u8; 32] = vss_xprv.private_key.secret_bytes();
388412

389-
let vss_store = Arc::new(VssStore::new(url, store_id, vss_seed_bytes));
413+
let vss_store = Arc::new(VssStore::new(vss_url, store_id, vss_seed_bytes, header_provider));
390414
build_with_store_internal(
391415
config,
392416
self.chain_data_source_config.as_ref(),
@@ -1079,6 +1103,23 @@ fn seed_bytes_from_config(
10791103
}
10801104
}
10811105

1106+
#[cfg(any(vss, vss_test))]
1107+
fn derive_vss_xprv(
1108+
config: Arc<Config>, seed_bytes: &[u8; 64], logger: Arc<FilesystemLogger>,
1109+
) -> Result<Xpriv, BuildError> {
1110+
use bitcoin::key::Secp256k1;
1111+
1112+
let xprv = Xpriv::new_master(config.network, seed_bytes).map_err(|e| {
1113+
log_error!(logger, "Failed to derive master secret: {}", e);
1114+
BuildError::InvalidSeedBytes
1115+
})?;
1116+
1117+
xprv.derive_priv(&Secp256k1::new(), &[ChildNumber::Hardened { index: 877 }]).map_err(|e| {
1118+
log_error!(logger, "Failed to derive VSS secret: {}", e);
1119+
BuildError::KVStoreSetupFailed
1120+
})
1121+
}
1122+
10821123
/// Sanitize the user-provided node alias to ensure that it is a valid protocol-specified UTF-8 string.
10831124
pub(crate) fn sanitize_alias(alias_str: &str) -> Result<NodeAlias, BuildError> {
10841125
let alias = alias_str.trim();

src/io/vss_store.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use lightning::io::{self, Error, ErrorKind};
99
#[cfg(test)]
1010
use std::panic::RefUnwindSafe;
11+
use std::sync::Arc;
1112
use std::time::Duration;
1213

1314
use crate::io::utils::check_namespace_key_validity;
@@ -17,6 +18,7 @@ use rand::RngCore;
1718
use tokio::runtime::Runtime;
1819
use vss_client::client::VssClient;
1920
use vss_client::error::VssError;
21+
use vss_client::headers::VssHeaderProvider;
2022
use vss_client::types::{
2123
DeleteObjectRequest, GetObjectRequest, KeyValue, ListKeyVersionsRequest, PutObjectRequest,
2224
Storable,
@@ -43,7 +45,10 @@ pub struct VssStore {
4345
}
4446

4547
impl VssStore {
46-
pub(crate) fn new(base_url: String, store_id: String, data_encryption_key: [u8; 32]) -> Self {
48+
pub(crate) fn new(
49+
base_url: String, store_id: String, data_encryption_key: [u8; 32],
50+
header_provider: Arc<dyn VssHeaderProvider>,
51+
) -> Self {
4752
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
4853
let storable_builder = StorableBuilder::new(data_encryption_key, RandEntropySource);
4954
let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(100))
@@ -59,7 +64,7 @@ impl VssStore {
5964
)
6065
}) as _);
6166

62-
let client = VssClient::new(base_url, retry_policy);
67+
let client = VssClient::new_with_headers(base_url, retry_policy, header_provider);
6368
Self { client, store_id, runtime, storable_builder }
6469
}
6570

@@ -238,6 +243,8 @@ mod tests {
238243
use crate::io::test_utils::do_read_write_remove_list_persist;
239244
use rand::distributions::Alphanumeric;
240245
use rand::{thread_rng, Rng, RngCore};
246+
use std::collections::HashMap;
247+
use vss_client::headers::FixedHeaders;
241248

242249
#[test]
243250
fn read_write_remove_list_persist() {
@@ -246,7 +253,9 @@ mod tests {
246253
let rand_store_id: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
247254
let mut data_encryption_key = [0u8; 32];
248255
rng.fill_bytes(&mut data_encryption_key);
249-
let vss_store = VssStore::new(vss_base_url, rand_store_id, data_encryption_key);
256+
let header_provider = Arc::new(FixedHeaders::new(HashMap::new()));
257+
let vss_store =
258+
VssStore::new(vss_base_url, rand_store_id, data_encryption_key, header_provider);
250259

251260
do_read_write_remove_list_persist(&vss_store);
252261
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ pub use bip39;
100100
pub use bitcoin;
101101
pub use lightning;
102102
pub use lightning_invoice;
103+
#[cfg(any(vss, vss_test))]
104+
pub use vss_client;
103105

104106
pub use balance::{BalanceDetails, LightningBalance, PendingSweepBalance};
105107
pub use error::Error as NodeError;

tests/integration_tests_vss.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
mod common;
1111

1212
use ldk_node::Builder;
13+
use std::collections::HashMap;
1314

1415
#[test]
1516
fn channel_full_cycle_with_vss_store() {
@@ -20,15 +21,26 @@ fn channel_full_cycle_with_vss_store() {
2021
let mut builder_a = Builder::from_config(config_a);
2122
builder_a.set_chain_source_esplora(esplora_url.clone(), None);
2223
let vss_base_url = std::env::var("TEST_VSS_BASE_URL").unwrap();
23-
let node_a =
24-
builder_a.build_with_vss_store(vss_base_url.clone(), "node_1_store".to_string()).unwrap();
24+
let node_a = builder_a
25+
.build_with_vss_store_and_fixed_headers(
26+
vss_base_url.clone(),
27+
"node_1_store".to_string(),
28+
HashMap::new(),
29+
)
30+
.unwrap();
2531
node_a.start().unwrap();
2632

2733
println!("\n== Node B ==");
2834
let config_b = common::random_config(true);
2935
let mut builder_b = Builder::from_config(config_b);
3036
builder_b.set_chain_source_esplora(esplora_url.clone(), None);
31-
let node_b = builder_b.build_with_vss_store(vss_base_url, "node_2_store".to_string()).unwrap();
37+
let node_b = builder_b
38+
.build_with_vss_store_and_fixed_headers(
39+
vss_base_url,
40+
"node_2_store".to_string(),
41+
HashMap::new(),
42+
)
43+
.unwrap();
3244
node_b.start().unwrap();
3345

3446
common::do_channel_full_cycle(

0 commit comments

Comments
 (0)