Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ interface Builder {
[Throws=BuildError]
Node build_with_fs_store(NodeEntropy node_entropy);
[Throws=BuildError]
Node build_with_vss_store(NodeEntropy node_entropy, string vss_url, string store_id, string lnurl_auth_server_url, record<string, string> fixed_headers);
Node build_with_vss_store(NodeEntropy node_entropy, string vss_url, string store_id, record<string, string> fixed_headers);
[Throws=BuildError]
Node build_with_vss_store_and_lnurl_auth(NodeEntropy node_entropy, string vss_url, string store_id, string lnurl_auth_server_url, record<string, string> fixed_headers);
[Throws=BuildError]
Node build_with_vss_store_and_fixed_headers(NodeEntropy node_entropy, string vss_url, string store_id, record<string, string> fixed_headers);
[Throws=BuildError]
Expand Down
84 changes: 77 additions & 7 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,37 @@ impl NodeBuilder {
self.build_with_store(node_entropy, kv_store)
}

/// Builds a [`Node`] instance with a [VSS] backend and according to the options
/// previously configured.
///
/// Uses a simple authentication scheme proving knowledge of a secret key.
///
/// `fixed_headers` are included as it is in all the requests made to VSS.
///
/// `store_id` allows you to segment LDK Node storage from other storage accessed with
/// [`VssStoreBuilder`] using the same [`NodeEntropy`] (as storage with different keys is
/// obviously segmented to prevent wallets from reading data for unrelated wallets). It can be
/// any value.
///
/// **Caution**: VSS support is in **alpha** and is considered experimental.
/// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
/// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
///
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
pub fn build_with_vss_store(
&self, node_entropy: NodeEntropy, vss_url: String, store_id: String,
fixed_headers: HashMap<String, String>,
) -> Result<Node, BuildError> {
let logger = setup_logger(&self.log_writer_config, &self.config)?;
let builder = VssStoreBuilder::new(node_entropy, vss_url, store_id, self.config.network);
let vss_store = builder.build_with_sigs_auth(fixed_headers).map_err(|e| {
log_error!(logger, "Failed to setup VSS store: {}", e);
BuildError::KVStoreSetupFailed
})?;

self.build_with_store(node_entropy, vss_store)
}

/// Builds a [`Node`] instance with a [VSS] backend and according to the options
/// previously configured.
///
Expand All @@ -593,6 +624,11 @@ impl NodeBuilder {
/// The returned JWT token in response to the signed LNURL request, will be used for
/// authentication/authorization of all the requests made to VSS.
///
/// `store_id` allows you to segment LDK Node storage from other storage accessed with
/// [`VssStoreBuilder`] using the same authentication (as storage with different keys is
/// obviously segmented to prevent wallets from reading data for unrelated wallets). It can be
/// any value.
///
/// `fixed_headers` are included as it is in all the requests made to VSS and LNURL auth server.
///
/// **Caution**: VSS support is in **alpha** and is considered experimental.
Expand All @@ -601,16 +637,17 @@ impl NodeBuilder {
///
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
/// [LNURL-auth]: https://github.com/lnurl/luds/blob/luds/04.md
pub fn build_with_vss_store(
pub fn build_with_vss_store_and_lnurl_auth(
&self, node_entropy: NodeEntropy, vss_url: String, store_id: String,
lnurl_auth_server_url: String, fixed_headers: HashMap<String, String>,
) -> Result<Node, BuildError> {
let logger = setup_logger(&self.log_writer_config, &self.config)?;
let builder = VssStoreBuilder::new(node_entropy, vss_url, store_id, self.config.network);
let vss_store = builder.build(lnurl_auth_server_url, fixed_headers).map_err(|e| {
log_error!(logger, "Failed to setup VSS store: {}", e);
BuildError::KVStoreSetupFailed
})?;
let vss_store =
builder.build_with_lnurl(lnurl_auth_server_url, fixed_headers).map_err(|e| {
log_error!(logger, "Failed to setup VSS store: {}", e);
BuildError::KVStoreSetupFailed
})?;

self.build_with_store(node_entropy, vss_store)
}
Expand Down Expand Up @@ -956,6 +993,34 @@ impl ArcedNodeBuilder {
self.inner.read().unwrap().build_with_fs_store(*node_entropy).map(Arc::new)
}

/// Builds a [`Node`] instance with a [VSS] backend and according to the options
/// previously configured.
///
/// Uses a simple authentication scheme proving knowledge of a secret key.
///
/// `fixed_headers` are included as it is in all the requests made to VSS and LNURL auth server.
///
/// `store_id` allows you to segment LDK Node storage from other storage accessed with
/// [`VssStoreBuilder`] using the same [`NodeEntropy`] (as storage with different keys is
/// obviously segmented to prevent wallets from reading data for unrelated wallets). It can be
/// any value.
///
/// **Caution**: VSS support is in **alpha** and is considered experimental.
/// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
/// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
///
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
pub fn build_with_vss_store(
&self, node_entropy: Arc<NodeEntropy>, vss_url: String, store_id: String,
fixed_headers: HashMap<String, String>,
) -> Result<Arc<Node>, BuildError> {
self.inner
.read()
.unwrap()
.build_with_vss_store(*node_entropy, vss_url, store_id, fixed_headers)
.map(Arc::new)
}

/// Builds a [`Node`] instance with a [VSS] backend and according to the options
/// previously configured.
///
Expand All @@ -967,20 +1032,25 @@ impl ArcedNodeBuilder {
///
/// `fixed_headers` are included as it is in all the requests made to VSS and LNURL auth server.
///
/// `store_id` allows you to segment LDK Node storage from other storage accessed with
/// [`VssStoreBuilder`] using the same authentication (as storage with different keys is
/// obviously segmented to prevent wallets from reading data for unrelated wallets). It can be
/// any value.
///
/// **Caution**: VSS support is in **alpha** and is considered experimental.
/// Using VSS (or any remote persistence) may cause LDK to panic if persistence failures are
/// unrecoverable, i.e., if they remain unresolved after internal retries are exhausted.
///
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
/// [LNURL-auth]: https://github.com/lnurl/luds/blob/luds/04.md
pub fn build_with_vss_store(
pub fn build_with_vss_store_and_lnurl_auth(
&self, node_entropy: Arc<NodeEntropy>, vss_url: String, store_id: String,
lnurl_auth_server_url: String, fixed_headers: HashMap<String, String>,
) -> Result<Arc<Node>, BuildError> {
self.inner
.read()
.unwrap()
.build_with_vss_store(
.build_with_vss_store_and_lnurl_auth(
*node_entropy,
vss_url,
store_id,
Expand Down
63 changes: 53 additions & 10 deletions src/io/vss_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use prost::Message;
use rand::RngCore;
use vss_client::client::VssClient;
use vss_client::error::VssError;
use vss_client::headers::sigs_auth::SigsAuthProvider;
use vss_client::headers::{FixedHeaders, LnurlAuthToJwtProvider, VssHeaderProvider};
use vss_client::types::{
DeleteObjectRequest, GetObjectRequest, KeyValue, ListKeyVersionsRequest, PutObjectRequest,
Expand Down Expand Up @@ -69,6 +70,7 @@ impl_writeable_tlv_based_enum!(VssSchemaVersion,

const VSS_HARDENED_CHILD_INDEX: u32 = 877;
const VSS_LNURL_AUTH_HARDENED_CHILD_INDEX: u32 = 138;
const VSS_SIGS_AUTH_HARDENED_CHILD_INDEX: u32 = 139;
const VSS_SCHEMA_VERSION_KEY: &str = "vss_schema_version";

// We set this to a small number of threads that would still allow to make some progress if one
Expand Down Expand Up @@ -853,6 +855,44 @@ impl VssStoreBuilder {
Self { node_entropy, vss_url, store_id, network }
}

/// Builds a [`VssStore`] with the simple signature-based authentication scheme.
///
/// `fixed_headers` are included as it is in all the requests made to VSS and LNURL auth
/// server.
///
/// **Caution**: VSS support is in **alpha** and is considered experimental. Using VSS (or any
/// remote persistence) may cause LDK to panic if persistence failures are unrecoverable, i.e.,
/// if they remain unresolved after internal retries are exhausted.
///
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
/// [LNURL-auth]: https://github.com/lnurl/luds/blob/luds/04.md
pub fn build_with_sigs_auth(
&self, fixed_headers: HashMap<String, String>,
) -> Result<VssStore, VssStoreBuildError> {
let secp_ctx = Secp256k1::new();
let seed_bytes = self.node_entropy.to_seed_bytes();
let vss_xprv = Xpriv::new_master(self.network, &seed_bytes)
.map_err(|_| VssStoreBuildError::KeyDerivationFailed)
.and_then(|master| {
master
.derive_priv(
&secp_ctx,
&[ChildNumber::Hardened { index: VSS_HARDENED_CHILD_INDEX }],
)
.map_err(|_| VssStoreBuildError::KeyDerivationFailed)
})?;

let sigs_auth_xprv = vss_xprv
.derive_priv(
&secp_ctx,
&[ChildNumber::Hardened { index: VSS_SIGS_AUTH_HARDENED_CHILD_INDEX }],
)
.map_err(|_| VssStoreBuildError::KeyDerivationFailed)?;

let auth_provider = SigsAuthProvider::new(sigs_auth_xprv.private_key, fixed_headers);
self.build_with_header_provider(Arc::new(auth_provider))
}

/// Builds a [`VssStore`] with [LNURL-auth] based authentication scheme as default method for
/// authentication/authorization.
///
Expand All @@ -869,7 +909,7 @@ impl VssStoreBuilder {
///
/// [VSS]: https://github.com/lightningdevkit/vss-server/blob/main/README.md
/// [LNURL-auth]: https://github.com/lnurl/luds/blob/luds/04.md
pub fn build(
pub fn build_with_lnurl(
&self, lnurl_auth_server_url: String, fixed_headers: HashMap<String, String>,
) -> Result<VssStore, VssStoreBuildError> {
let secp_ctx = Secp256k1::new();
Expand Down Expand Up @@ -962,7 +1002,6 @@ mod tests {

use rand::distr::Alphanumeric;
use rand::{rng, Rng, RngCore};
use vss_client::headers::FixedHeaders;

use super::*;
use crate::io::test_utils::do_read_write_remove_list_persist;
Expand All @@ -972,11 +1011,13 @@ mod tests {
let vss_base_url = std::env::var("TEST_VSS_BASE_URL").unwrap();
let mut rng = rng();
let rand_store_id: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
let mut vss_seed = [0u8; 32];
rng.fill_bytes(&mut vss_seed);
let header_provider = Arc::new(FixedHeaders::new(HashMap::new()));
let mut node_seed = [0u8; 64];
rng.fill_bytes(&mut node_seed);
let entropy = NodeEntropy::from_seed_bytes(vss_seed);
let vss_store =
VssStore::new(vss_base_url, rand_store_id, vss_seed, header_provider).unwrap();
VssStoreBuilder::new(entropy, vss_base_url, rand_store_id, Network::Testnet)
.build_with_sigs_auth(HashMap::new())
.unwrap();
do_read_write_remove_list_persist(&vss_store);
}

Expand All @@ -985,11 +1026,13 @@ mod tests {
let vss_base_url = std::env::var("TEST_VSS_BASE_URL").unwrap();
let mut rng = rng();
let rand_store_id: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
let mut vss_seed = [0u8; 32];
rng.fill_bytes(&mut vss_seed);
let header_provider = Arc::new(FixedHeaders::new(HashMap::new()));
let mut node_seed = [0u8; 64];
rng.fill_bytes(&mut node_seed);
let entropy = NodeEntropy::from_seed_bytes(vss_seed);
let vss_store =
VssStore::new(vss_base_url, rand_store_id, vss_seed, header_provider).unwrap();
VssStoreBuilder::new(entropy, vss_base_url, rand_store_id, Network::Testnet)
.build_with_sigs_auth(HashMap::new())
.unwrap();

do_read_write_remove_list_persist(&vss_store);
drop(vss_store)
Expand Down
Loading
Loading