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
8 changes: 8 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ jobs:
if: "matrix.platform != 'windows-latest' && matrix.build-uniffi"
run: |
RUSTFLAGS="--cfg no_download --cfg cycle_tests" cargo test --features uniffi
- name: Test with HRN overrides (No UniFFI) on Rust ${{ matrix.toolchain }}
if: "matrix.platform == 'ubuntu-latest' && matrix.toolchain == 'stable'"
run: |
RUSTFLAGS="--cfg no_download" cargo test --features hrn_tests
- name: Test with UniFFI and HRN overrides on Rust ${{ matrix.toolchain }}
if: "matrix.platform != 'windows-latest' && matrix.build-uniffi"
run: |
RUSTFLAGS="--cfg no_download" cargo test --features uniffi,hrn_tests

doc:
name: Documentation
Expand Down
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ panic = 'abort' # Abort on panic

[features]
default = []
hrn_tests = []

[dependencies]
#lightning = { version = "0.2.0", features = ["std"] }
Expand All @@ -38,6 +39,7 @@ default = []
#lightning-transaction-sync = { version = "0.2.0", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
#lightning-liquidity = { version = "0.2.0", features = ["std"] }
#lightning-macros = { version = "0.2.0" }
#lightning-dns-resolver = { version = "0.3.0" }

lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "817ab5e583002df5e32b3a71e7ab093005a2a39a", features = ["std"] }
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "817ab5e583002df5e32b3a71e7ab093005a2a39a" }
Expand All @@ -50,6 +52,7 @@ lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightnin
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "817ab5e583002df5e32b3a71e7ab093005a2a39a", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "817ab5e583002df5e32b3a71e7ab093005a2a39a", features = ["std"] }
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "817ab5e583002df5e32b3a71e7ab093005a2a39a" }
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "817ab5e583002df5e32b3a71e7ab093005a2a39a" }

bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] }
bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]}
Expand Down Expand Up @@ -141,6 +144,7 @@ harness = false
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolver" }

#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
Expand All @@ -153,6 +157,7 @@ harness = false
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }

#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
Expand All @@ -165,6 +170,7 @@ harness = false
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }

#vss-client-ng = { path = "../vss-client" }
#vss-client-ng = { git = "https://github.com/lightningdevkit/vss-client", branch = "main" }
Expand All @@ -181,3 +187,4 @@ harness = false
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolver" }
1 change: 1 addition & 0 deletions benches/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ fn payment_benchmark(c: &mut Criterion) {
true,
false,
common::TestStoreType::Sqlite,
false,
);

let runtime =
Expand Down
14 changes: 14 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dictionary Config {
u64 probing_liquidity_limit_multiplier;
AnchorChannelsConfig? anchor_channels_config;
RouteParametersConfig? route_parameters;
HumanReadableNamesConfig? hrn_config;
};

dictionary AnchorChannelsConfig {
Expand Down Expand Up @@ -361,6 +362,7 @@ enum NodeError {
"InvalidBlindedPaths",
"AsyncPaymentServicesDisabled",
"HrnParsingFailed",
"HrnResolverNotConfigured",
};

dictionary NodeStatus {
Expand Down Expand Up @@ -395,6 +397,7 @@ enum BuildError {
"LoggerSetupFailed",
"NetworkMismatch",
"AsyncPaymentsConfigMismatch",
"DNSResolverSetupFailed",
};

[Trait]
Expand Down Expand Up @@ -514,6 +517,17 @@ dictionary RouteParametersConfig {
u8 max_channel_saturation_power_of_half;
};

[Enum]
interface HRNResolverConfig {
Blip32Onion();
LocalDns(string dns_server_address);
};

dictionary HumanReadableNamesConfig {
HRNResolverConfig client_resolution_config;
boolean disable_hrn_resolution_service;
};

dictionary CustomTlvRecord {
u64 type_num;
sequence<u8> value;
Expand Down
104 changes: 89 additions & 15 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::collections::HashMap;
use std::convert::TryInto;
use std::default::Default;
use std::path::PathBuf;
use std::sync::{Arc, Mutex, Once, RwLock};
use std::sync::{Arc, Mutex, Once, RwLock, Weak};
use std::time::SystemTime;
use std::{fmt, fs};

Expand All @@ -19,12 +19,14 @@ use bitcoin::bip32::{ChildNumber, Xpriv};
use bitcoin::key::Secp256k1;
use bitcoin::secp256k1::PublicKey;
use bitcoin::{BlockHash, Network};
use bitcoin_payment_instructions::dns_resolver::DNSHrnResolver;
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
use lightning::chain::{chainmonitor, BestBlock};
use lightning::ln::channelmanager::{self, ChainParameters, ChannelManagerReadArgs};
use lightning::ln::msgs::{RoutingMessageHandler, SocketAddress};
use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler};
use lightning::log_trace;
use lightning::onion_message::dns_resolution::DNSResolverMessageHandler;
use lightning::routing::gossip::NodeAlias;
use lightning::routing::router::DefaultRouter;
use lightning::routing::scoring::{
Expand All @@ -39,13 +41,14 @@ use lightning::util::persist::{
};
use lightning::util::ser::ReadableArgs;
use lightning::util::sweep::OutputSweeper;
use lightning_dns_resolver::OMDomainResolver;
use lightning_persister::fs_store::FilesystemStore;
use vss_client::headers::VssHeaderProvider;

use crate::chain::ChainSource;
use crate::config::{
default_user_config, may_announce_channel, AnnounceError, AsyncPaymentsRole,
BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig,
BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig, HRNResolverConfig,
DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL,
};
use crate::connection::ConnectionManager;
Expand Down Expand Up @@ -76,8 +79,8 @@ use crate::runtime::{Runtime, RuntimeSpawner};
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreWrapper, GossipSync, Graph,
KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager, PendingPaymentStore,
Persister, SyncAndAsyncKVStore,
HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager,
PendingPaymentStore, Persister, SyncAndAsyncKVStore,
};
use crate::wallet::persist::KVStoreWalletPersister;
use crate::wallet::Wallet;
Expand Down Expand Up @@ -189,6 +192,8 @@ pub enum BuildError {
NetworkMismatch,
/// The role of the node in an asynchronous payments context is not compatible with the current configuration.
AsyncPaymentsConfigMismatch,
/// An attempt to setup a DNS Resolver failed.
DNSResolverSetupFailed,
}

impl fmt::Display for BuildError {
Expand Down Expand Up @@ -221,6 +226,9 @@ impl fmt::Display for BuildError {
"The async payments role is not compatible with the current configuration."
)
},
Self::DNSResolverSetupFailed => {
write!(f, "An attempt to setup a DNS resolver has failed.")
},
}
}
}
Expand Down Expand Up @@ -1517,7 +1525,74 @@ fn build_with_store_internal(
})?;
}

let hrn_resolver = Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(&network_graph)));
let peer_manager_hook: Arc<Mutex<Option<Weak<PeerManager>>>> = Arc::new(Mutex::new(None));
let mut hrn_resolver_out = None;

let om_resolver = match &config.hrn_config {
None => Arc::new(IgnoringMessageHandler {}),
Some(hrn_config) => {
let runtime_handle = runtime.handle();

let client_resolver: Arc<dyn DNSResolverMessageHandler + Send + Sync> =
match &hrn_config.client_resolution_config {
HRNResolverConfig::Blip32Onion => {
let hrn_res = Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(
&network_graph,
)));
hrn_resolver_out = Some(Arc::new(HRNResolver::Onion(Arc::clone(&hrn_res))));

let pm_hook_clone = Arc::clone(&peer_manager_hook);
hrn_res.register_post_queue_action(Box::new(move || {
if let Ok(guard) = pm_hook_clone.lock() {
if let Some(weak_pm) = &*guard {
if let Some(pm) = weak_pm.upgrade() {
pm.process_events();
}
}
}
}));

hrn_res as Arc<dyn DNSResolverMessageHandler + Send + Sync>
},
HRNResolverConfig::LocalDns { dns_server_address } => {
let addr = dns_server_address
.parse()
.map_err(|_| BuildError::DNSResolverSetupFailed)?;
let hrn_res = Arc::new(DNSHrnResolver(addr));
hrn_resolver_out = Some(Arc::new(HRNResolver::Local(hrn_res)));
let resolver = Arc::new(OMDomainResolver::ignoring_incoming_proofs(addr));
resolver.set_runtime(runtime_handle.clone());
resolver as Arc<dyn DNSResolverMessageHandler + Send + Sync>
},
};

let should_act_as_service = if hrn_config.disable_hrn_resolution_service {
false
} else {
may_announce_channel(&config).is_ok()
};

if should_act_as_service {
if let HRNResolverConfig::LocalDns { dns_server_address } =
&hrn_config.client_resolution_config
{
let service_dns_addr = dns_server_address
.parse()
.map_err(|_| BuildError::DNSResolverSetupFailed)?;
Arc::new(OMDomainResolver::with_runtime(
service_dns_addr,
Some(client_resolver),
Some(runtime_handle.clone()),
))
} else {
log_error!(logger, "To act as an HRN resolution service, the DNS resolver must be configured to use a DNS server.");
return Err(BuildError::DNSResolverSetupFailed);
}
} else {
client_resolver
}
},
};

// Initialize the PeerManager
let onion_messenger: Arc<OnionMessenger> =
Expand All @@ -1530,7 +1605,7 @@ fn build_with_store_internal(
message_router,
Arc::clone(&channel_manager),
Arc::clone(&channel_manager),
Arc::clone(&hrn_resolver),
Arc::clone(&om_resolver),
IgnoringMessageHandler {},
))
} else {
Expand All @@ -1542,7 +1617,7 @@ fn build_with_store_internal(
message_router,
Arc::clone(&channel_manager),
Arc::clone(&channel_manager),
Arc::clone(&hrn_resolver),
Arc::clone(&om_resolver),
IgnoringMessageHandler {},
))
};
Expand Down Expand Up @@ -1663,7 +1738,7 @@ fn build_with_store_internal(
BuildError::InvalidSystemTime
})?;

let peer_manager = Arc::new(PeerManager::new(
let peer_manager: Arc<PeerManager> = Arc::new(PeerManager::new(
msg_handler,
cur_time.as_secs().try_into().map_err(|e| {
log_error!(logger, "Failed to get current time: {}", e);
Expand All @@ -1674,12 +1749,11 @@ fn build_with_store_internal(
Arc::clone(&keys_manager),
));

let peer_manager_clone = Arc::downgrade(&peer_manager);
hrn_resolver.register_post_queue_action(Box::new(move || {
if let Some(upgraded_pointer) = peer_manager_clone.upgrade() {
upgraded_pointer.process_events();
}
}));
if let Ok(mut guard) = peer_manager_hook.lock() {
*guard = Some(Arc::downgrade(&peer_manager));
} else {
return Err(BuildError::DNSResolverSetupFailed);
}

liquidity_source.as_ref().map(|l| l.set_peer_manager(Arc::downgrade(&peer_manager)));

Expand Down Expand Up @@ -1786,7 +1860,7 @@ fn build_with_store_internal(
node_metrics,
om_mailbox,
async_payments_role,
hrn_resolver,
hrn_resolver: hrn_resolver_out,
#[cfg(cycle_tests)]
_leak_checker,
})
Expand Down
42 changes: 41 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ pub(crate) const HRN_RESOLUTION_TIMEOUT_SECS: u64 = 5;
/// | `probing_liquidity_limit_multiplier` | 3 |
/// | `log_level` | Debug |
/// | `anchor_channels_config` | Some(..) |
/// | `route_parameters` | None |
/// | `route_parameters` | None |
/// | `hrn_config` | Some(..) |
///
/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their
/// respective default values.
Expand Down Expand Up @@ -192,6 +193,10 @@ pub struct Config {
/// **Note:** If unset, default parameters will be used, and you will be able to override the
/// parameters on a per-payment basis in the corresponding method calls.
pub route_parameters: Option<RouteParametersConfig>,
/// Configuration options for Human-Readable Names ([BIP 353]).
///
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
pub hrn_config: Option<HumanReadableNamesConfig>,
}

impl Default for Config {
Expand All @@ -206,6 +211,41 @@ impl Default for Config {
anchor_channels_config: Some(AnchorChannelsConfig::default()),
route_parameters: None,
node_alias: None,
hrn_config: Some(HumanReadableNamesConfig::default()),
}
}
}

/// Configuration options for how our node resolves Human-Readable Names (HRNs) when acting as a client.
#[derive(Debug, Clone)]
pub enum HRNResolverConfig {
/// Use bLIP-32 to ask other nodes to resolve names for us.
Blip32Onion,
/// Resolve names locally using a specific DNS server.
LocalDns {
/// The IP and port of the DNS server (e.g., "8.8.8.8:53").
dns_server_address: String,
},
}

/// Configuration options for Human-Readable Names ([BIP 353]).
///
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
#[derive(Debug, Clone)]
pub struct HumanReadableNamesConfig {
/// This sets how our node resolves names when we want to send a payment.
pub client_resolution_config: HRNResolverConfig,
/// if set, this allows others to use our node for HRN resolutions.
pub disable_hrn_resolution_service: bool,
}

impl Default for HumanReadableNamesConfig {
fn default() -> Self {
HumanReadableNamesConfig {
client_resolution_config: HRNResolverConfig::LocalDns {
dns_server_address: "8.8.8.8:53".to_string(),
},
disable_hrn_resolution_service: false,
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ pub enum Error {
AsyncPaymentServicesDisabled,
/// Parsing a Human-Readable Name has failed.
HrnParsingFailed,
/// A HRN resolver was not configured
HrnResolverNotConfigured,
}

impl fmt::Display for Error {
Expand Down Expand Up @@ -213,6 +215,9 @@ impl fmt::Display for Error {
Self::HrnParsingFailed => {
write!(f, "Failed to parse a human-readable name.")
},
Self::HrnResolverNotConfigured => {
write!(f, "A HRN resolver was not configured.")
},
}
}
}
Expand Down
Loading
Loading