Skip to content

Commit 5160236

Browse files
committed
Pass HRNResolver or DomainResolver into OnionMessenger
Inject specialized resolution capabilities into OnionMessenger to support outbound payments and third-party resolution services. This change refines the previous resolution logic by allowing the node to act as a robust BIP 353 participant. If configured as a service provider, the node utilizes a Domain Resolver to handle requests for other participants. Otherwise, it uses an HRN Resolver specifically for initiating its own outbound payments. Providing these as optional parameters in the Node constructor ensures the logic matches the node's designated role in the ecosystem.
1 parent 08bb72d commit 5160236

8 files changed

Lines changed: 172 additions & 29 deletions

File tree

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ default = []
3838
#lightning-transaction-sync = { version = "0.2.0", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
3939
#lightning-liquidity = { version = "0.2.0", features = ["std"] }
4040
#lightning-macros = { version = "0.2.0" }
41+
#lightning-dns-resolver = { version = "0.3.0" }
4142

4243
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "b6c17c593a5d7bacb18fe3b9f69074a0596ae8f0", features = ["std"] }
4344
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "b6c17c593a5d7bacb18fe3b9f69074a0596ae8f0" }
@@ -50,6 +51,7 @@ lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightnin
5051
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "b6c17c593a5d7bacb18fe3b9f69074a0596ae8f0", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
5152
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "b6c17c593a5d7bacb18fe3b9f69074a0596ae8f0", features = ["std"] }
5253
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "b6c17c593a5d7bacb18fe3b9f69074a0596ae8f0" }
54+
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "b6c17c593a5d7bacb18fe3b9f69074a0596ae8f0" }
5355

5456
bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] }
5557
bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]}
@@ -141,6 +143,7 @@ harness = false
141143
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
142144
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
143145
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
146+
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolver" }
144147

145148
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
146149
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
@@ -153,6 +156,7 @@ harness = false
153156
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
154157
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
155158
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
159+
#lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
156160

157161
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
158162
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
@@ -165,6 +169,7 @@ harness = false
165169
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
166170
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
167171
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
172+
#lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
168173

169174
#vss-client-ng = { path = "../vss-client" }
170175
#vss-client-ng = { git = "https://github.com/lightningdevkit/vss-client", branch = "main" }
@@ -181,3 +186,4 @@ harness = false
181186
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
182187
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
183188
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
189+
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolver" }

bindings/ldk_node.udl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ enum NodeError {
363363
"InvalidBlindedPaths",
364364
"AsyncPaymentServicesDisabled",
365365
"HrnParsingFailed",
366+
"HrnResolverNotConfigured",
366367
};
367368

368369
dictionary NodeStatus {
@@ -397,6 +398,8 @@ enum BuildError {
397398
"LoggerSetupFailed",
398399
"NetworkMismatch",
399400
"AsyncPaymentsConfigMismatch",
401+
"DNSResolverSetupFailed",
402+
"PeerManagerSetupFailed",
400403
};
401404

402405
[Trait]

src/builder.rs

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::collections::HashMap;
99
use std::convert::TryInto;
1010
use std::default::Default;
1111
use std::path::PathBuf;
12-
use std::sync::{Arc, Mutex, Once, RwLock};
12+
use std::sync::{Arc, Mutex, Once, RwLock, Weak};
1313
use std::time::SystemTime;
1414
use std::{fmt, fs};
1515

@@ -19,12 +19,14 @@ use bitcoin::bip32::{ChildNumber, Xpriv};
1919
use bitcoin::key::Secp256k1;
2020
use bitcoin::secp256k1::PublicKey;
2121
use bitcoin::{BlockHash, Network};
22+
use bitcoin_payment_instructions::dns_resolver::DNSHrnResolver;
2223
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
2324
use lightning::chain::{chainmonitor, BestBlock};
2425
use lightning::ln::channelmanager::{self, ChainParameters, ChannelManagerReadArgs};
2526
use lightning::ln::msgs::{RoutingMessageHandler, SocketAddress};
2627
use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler};
2728
use lightning::log_trace;
29+
use lightning::onion_message::dns_resolution::DNSResolverMessageHandler;
2830
use lightning::routing::gossip::NodeAlias;
2931
use lightning::routing::router::DefaultRouter;
3032
use lightning::routing::scoring::{
@@ -39,13 +41,14 @@ use lightning::util::persist::{
3941
};
4042
use lightning::util::ser::ReadableArgs;
4143
use lightning::util::sweep::OutputSweeper;
44+
use lightning_dns_resolver::OMDomainResolver;
4245
use lightning_persister::fs_store::FilesystemStore;
4346
use vss_client::headers::VssHeaderProvider;
4447

4548
use crate::chain::ChainSource;
4649
use crate::config::{
4750
default_user_config, may_announce_channel, AnnounceError, AsyncPaymentsRole,
48-
BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig,
51+
BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig, HRNResolverConfig,
4952
DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL,
5053
};
5154
use crate::connection::ConnectionManager;
@@ -76,8 +79,8 @@ use crate::runtime::{Runtime, RuntimeSpawner};
7679
use crate::tx_broadcaster::TransactionBroadcaster;
7780
use crate::types::{
7881
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreWrapper, GossipSync, Graph,
79-
KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager, PendingPaymentStore,
80-
Persister, SyncAndAsyncKVStore,
82+
HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager,
83+
PendingPaymentStore, Persister, SyncAndAsyncKVStore,
8184
};
8285
use crate::wallet::persist::KVStoreWalletPersister;
8386
use crate::wallet::Wallet;
@@ -189,6 +192,10 @@ pub enum BuildError {
189192
NetworkMismatch,
190193
/// The role of the node in an asynchronous payments context is not compatible with the current configuration.
191194
AsyncPaymentsConfigMismatch,
195+
/// An attempt to setup a DNS Resolver failed.
196+
DNSResolverSetupFailed,
197+
/// Failed to set up the peer manager.
198+
PeerManagerSetupFailed,
192199
}
193200

194201
impl fmt::Display for BuildError {
@@ -221,6 +228,12 @@ impl fmt::Display for BuildError {
221228
"The async payments role is not compatible with the current configuration."
222229
)
223230
},
231+
Self::DNSResolverSetupFailed => {
232+
write!(f, "An attempt to setup a DNS resolver has failed.")
233+
},
234+
Self::PeerManagerSetupFailed => {
235+
write!(f, "Failed to set up the peer manager.")
236+
},
224237
}
225238
}
226239
}
@@ -1545,7 +1558,83 @@ fn build_with_store_internal(
15451558
})?;
15461559
}
15471560

1548-
let hrn_resolver = Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(&network_graph)));
1561+
let peer_manager_hook: Arc<Mutex<Option<Weak<PeerManager>>>> = Arc::new(Mutex::new(None));
1562+
let mut hrn_resolver_out = None;
1563+
1564+
let om_resolver: Arc<dyn DNSResolverMessageHandler + Send + Sync> = match &config.hrn_config {
1565+
None => Arc::new(IgnoringMessageHandler {}),
1566+
Some(hrn_config) => {
1567+
let runtime_handle = runtime.handle();
1568+
1569+
let client_resolver: Arc<dyn DNSResolverMessageHandler + Send + Sync> =
1570+
match &hrn_config.resolution_config {
1571+
HRNResolverConfig::Blip32 => {
1572+
let hrn_res = Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(
1573+
&network_graph,
1574+
)));
1575+
hrn_resolver_out = Some(Arc::new(HRNResolver::Onion(Arc::clone(&hrn_res))));
1576+
1577+
let pm_hook_clone = Arc::clone(&peer_manager_hook);
1578+
hrn_res.register_post_queue_action(Box::new(move || {
1579+
if let Ok(guard) = pm_hook_clone.lock() {
1580+
if let Some(pm) = guard.as_ref().and_then(|weak| weak.upgrade()) {
1581+
pm.process_events();
1582+
}
1583+
}
1584+
}));
1585+
hrn_res as Arc<dyn DNSResolverMessageHandler + Send + Sync>
1586+
},
1587+
HRNResolverConfig::Dns { dns_server_address, .. } => {
1588+
let addr = dns_server_address
1589+
.parse()
1590+
.map_err(|_| BuildError::DNSResolverSetupFailed)?;
1591+
let hrn_res = Arc::new(DNSHrnResolver(addr));
1592+
hrn_resolver_out = Some(Arc::new(HRNResolver::Local(hrn_res)));
1593+
1594+
let resolver =
1595+
Arc::new(OMDomainResolver::<IgnoringMessageHandler>::with_runtime(
1596+
addr,
1597+
None,
1598+
Some(runtime_handle.clone()),
1599+
));
1600+
resolver as Arc<dyn DNSResolverMessageHandler + Send + Sync>
1601+
},
1602+
};
1603+
1604+
if let HRNResolverConfig::Dns {
1605+
enable_hrn_resolution_service: enable @ true,
1606+
ref dns_server_address,
1607+
..
1608+
} = hrn_config.resolution_config
1609+
{
1610+
if may_announce_channel(&config).is_ok() {
1611+
let service_dns_addr = dns_server_address
1612+
.parse()
1613+
.map_err(|_| BuildError::DNSResolverSetupFailed)?;
1614+
1615+
log_error!(
1616+
logger,
1617+
"{}",
1618+
format!(
1619+
"enable hrn res: {} - dns server addr: {}",
1620+
enable, dns_server_address
1621+
)
1622+
);
1623+
1624+
Arc::new(OMDomainResolver::with_runtime(
1625+
service_dns_addr,
1626+
Some(client_resolver),
1627+
Some(runtime_handle.clone()),
1628+
)) as Arc<dyn DNSResolverMessageHandler + Send + Sync>
1629+
} else {
1630+
log_error!(logger, "To act as an HRN resolution service, the node must be configured to announce channels.");
1631+
return Err(BuildError::DNSResolverSetupFailed);
1632+
}
1633+
} else {
1634+
client_resolver
1635+
}
1636+
},
1637+
};
15491638

15501639
// Initialize the PeerManager
15511640
let onion_messenger: Arc<OnionMessenger> =
@@ -1558,7 +1647,7 @@ fn build_with_store_internal(
15581647
message_router,
15591648
Arc::clone(&channel_manager),
15601649
Arc::clone(&channel_manager),
1561-
Arc::clone(&hrn_resolver),
1650+
Arc::clone(&om_resolver),
15621651
IgnoringMessageHandler {},
15631652
))
15641653
} else {
@@ -1570,7 +1659,7 @@ fn build_with_store_internal(
15701659
message_router,
15711660
Arc::clone(&channel_manager),
15721661
Arc::clone(&channel_manager),
1573-
Arc::clone(&hrn_resolver),
1662+
Arc::clone(&om_resolver),
15741663
IgnoringMessageHandler {},
15751664
))
15761665
};
@@ -1691,7 +1780,7 @@ fn build_with_store_internal(
16911780
BuildError::InvalidSystemTime
16921781
})?;
16931782

1694-
let peer_manager = Arc::new(PeerManager::new(
1783+
let peer_manager: Arc<PeerManager> = Arc::new(PeerManager::new(
16951784
msg_handler,
16961785
cur_time.as_secs().try_into().map_err(|e| {
16971786
log_error!(logger, "Failed to get current time: {}", e);
@@ -1702,12 +1791,11 @@ fn build_with_store_internal(
17021791
Arc::clone(&keys_manager),
17031792
));
17041793

1705-
let peer_manager_clone = Arc::downgrade(&peer_manager);
1706-
hrn_resolver.register_post_queue_action(Box::new(move || {
1707-
if let Some(upgraded_pointer) = peer_manager_clone.upgrade() {
1708-
upgraded_pointer.process_events();
1709-
}
1710-
}));
1794+
if let Ok(mut guard) = peer_manager_hook.lock() {
1795+
*guard = Some(Arc::downgrade(&peer_manager));
1796+
} else {
1797+
return Err(BuildError::PeerManagerSetupFailed);
1798+
}
17111799

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

@@ -1814,7 +1902,7 @@ fn build_with_store_internal(
18141902
node_metrics,
18151903
om_mailbox,
18161904
async_payments_role,
1817-
hrn_resolver,
1905+
hrn_resolver: Arc::new(hrn_resolver_out),
18181906
#[cfg(cycle_tests)]
18191907
_leak_checker,
18201908
})

src/error.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ pub enum Error {
131131
AsyncPaymentServicesDisabled,
132132
/// Parsing a Human-Readable Name has failed.
133133
HrnParsingFailed,
134+
/// A HRN resolver was not configured
135+
HrnResolverNotConfigured,
134136
}
135137

136138
impl fmt::Display for Error {
@@ -213,6 +215,9 @@ impl fmt::Display for Error {
213215
Self::HrnParsingFailed => {
214216
write!(f, "Failed to parse a human-readable name.")
215217
},
218+
Self::HrnResolverNotConfigured => {
219+
write!(f, "A HRN resolver was not configured.")
220+
},
216221
}
217222
}
218223
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ pub struct Node {
226226
node_metrics: Arc<RwLock<NodeMetrics>>,
227227
om_mailbox: Option<Arc<OnionMessageMailbox>>,
228228
async_payments_role: Option<AsyncPaymentsRole>,
229-
hrn_resolver: Arc<HRNResolver>,
229+
hrn_resolver: Arc<Option<Arc<HRNResolver>>>,
230230
#[cfg(cycle_tests)]
231231
_leak_checker: LeakChecker,
232232
}

src/payment/unified.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ pub struct UnifiedPayment {
6464
bolt12_payment: Arc<Bolt12Payment>,
6565
config: Arc<Config>,
6666
logger: Arc<Logger>,
67-
hrn_resolver: Arc<HRNResolver>,
67+
hrn_resolver: Arc<Option<Arc<HRNResolver>>>,
6868
}
6969

7070
impl UnifiedPayment {
7171
pub(crate) fn new(
7272
onchain_payment: Arc<OnchainPayment>, bolt11_invoice: Arc<Bolt11Payment>,
7373
bolt12_payment: Arc<Bolt12Payment>, config: Arc<Config>, logger: Arc<Logger>,
74-
hrn_resolver: Arc<HRNResolver>,
74+
hrn_resolver: Arc<Option<Arc<HRNResolver>>>,
7575
) -> Self {
7676
Self { onchain_payment, bolt11_invoice, bolt12_payment, config, logger, hrn_resolver }
7777
}
@@ -161,12 +161,13 @@ impl UnifiedPayment {
161161
&self, uri_str: &str, amount_msat: Option<u64>,
162162
route_parameters: Option<RouteParametersConfig>,
163163
) -> Result<UnifiedPaymentResult, Error> {
164-
let parse_fut = PaymentInstructions::parse(
165-
uri_str,
166-
self.config.network,
167-
self.hrn_resolver.as_ref(),
168-
false,
169-
);
164+
let resolver = self.hrn_resolver.as_ref().clone().ok_or_else(|| {
165+
log_error!(self.logger, "No HRN resolver configured. Cannot resolve HRNs.");
166+
Error::HrnResolverNotConfigured
167+
})?;
168+
169+
let parse_fut =
170+
PaymentInstructions::parse(uri_str, self.config.network, resolver.as_ref(), false);
170171

171172
let instructions =
172173
tokio::time::timeout(Duration::from_secs(HRN_RESOLUTION_TIMEOUT_SECS), parse_fut)
@@ -192,7 +193,7 @@ impl UnifiedPayment {
192193
Error::InvalidAmount
193194
})?;
194195

195-
let fut = instr.set_amount(amt, self.hrn_resolver.as_ref());
196+
let fut = instr.set_amount(amt, &*resolver);
196197

197198
tokio::time::timeout(Duration::from_secs(HRN_RESOLUTION_TIMEOUT_SECS), fut)
198199
.await

src/runtime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ impl Runtime {
208208
);
209209
}
210210

211-
fn handle(&self) -> &tokio::runtime::Handle {
211+
pub(crate) fn handle(&self) -> &tokio::runtime::Handle {
212212
match &self.mode {
213213
RuntimeMode::Owned(rt) => rt.handle(),
214214
RuntimeMode::Handle(handle) => handle,

0 commit comments

Comments
 (0)