Skip to content

Commit e83f2cf

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 b699f3e commit e83f2cf

5 files changed

Lines changed: 150 additions & 27 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 = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["std"] }
4344
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
@@ -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 = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
5152
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["std"] }
5253
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
54+
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
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"]}
@@ -144,6 +146,7 @@ harness = false
144146
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
145147
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
146148
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
149+
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolver" }
147150

148151
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
149152
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
@@ -156,6 +159,7 @@ harness = false
156159
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
157160
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
158161
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
162+
#lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
159163

160164
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
161165
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
@@ -168,6 +172,7 @@ harness = false
168172
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
169173
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
170174
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
175+
#lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
171176

172177
#vss-client-ng = { path = "../vss-client" }
173178
#vss-client-ng = { git = "https://github.com/lightningdevkit/vss-client", branch = "main" }
@@ -184,3 +189,4 @@ harness = false
184189
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
185190
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
186191
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
192+
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolver" }

src/builder.rs

Lines changed: 81 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,14 +41,15 @@ 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::v1::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, TorConfig,
49-
DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL,
51+
BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig, HRNResolverConfig,
52+
TorConfig, DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL,
5053
};
5154
use crate::connection::ConnectionManager;
5255
use crate::entropy::NodeEntropy;
@@ -77,8 +80,8 @@ use crate::runtime::{Runtime, RuntimeSpawner};
7780
use crate::tx_broadcaster::TransactionBroadcaster;
7881
use crate::types::{
7982
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreRef, DynStoreWrapper,
80-
GossipSync, Graph, KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager,
81-
PendingPaymentStore, SyncAndAsyncKVStore,
83+
GossipSync, Graph, HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore,
84+
PeerManager, PendingPaymentStore, SyncAndAsyncKVStore,
8285
};
8386
use crate::wallet::persist::KVStoreWalletPersister;
8487
use crate::wallet::Wallet;
@@ -195,6 +198,8 @@ pub enum BuildError {
195198
NetworkMismatch,
196199
/// The role of the node in an asynchronous payments context is not compatible with the current configuration.
197200
AsyncPaymentsConfigMismatch,
201+
/// An attempt to setup a DNS Resolver failed.
202+
DNSResolverSetupFailed,
198203
}
199204

200205
impl fmt::Display for BuildError {
@@ -229,6 +234,9 @@ impl fmt::Display for BuildError {
229234
"The async payments role is not compatible with the current configuration."
230235
)
231236
},
237+
Self::DNSResolverSetupFailed => {
238+
write!(f, "An attempt to setup a DNS resolver has failed.")
239+
},
232240
}
233241
}
234242
}
@@ -1726,7 +1734,68 @@ fn build_with_store_internal(
17261734
})?;
17271735
}
17281736

1729-
let hrn_resolver = Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(&network_graph)));
1737+
// This hook resolves a circular dependency:
1738+
// 1. PeerManager requires OnionMessenger (via MessageHandler).
1739+
// 2. OnionMessenger (via HRN resolver) needs to call PeerManager::process_events.
1740+
//
1741+
// We provide the resolver with a Weak pointer via this Mutex-protected "hook."
1742+
// This allows us to initialize the resolver before the PeerManager exists,
1743+
// and prevents a reference cycle (memory leak).
1744+
let peer_manager_hook: Arc<Mutex<Option<Weak<PeerManager>>>> = Arc::new(Mutex::new(None));
1745+
let hrn_resolver;
1746+
1747+
let runtime_handle = runtime.handle();
1748+
1749+
let om_resolver: Arc<dyn DNSResolverMessageHandler + Send + Sync> = match &config
1750+
.hrn_config
1751+
.resolution_config
1752+
{
1753+
HRNResolverConfig::Blip32 => {
1754+
let hrn_res =
1755+
Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(&network_graph)));
1756+
hrn_resolver = HRNResolver::Onion(Arc::clone(&hrn_res));
1757+
1758+
// We clone the hook because it's moved into a Send + Sync closure that outlives this scope.
1759+
let pm_hook_clone = Arc::clone(&peer_manager_hook);
1760+
hrn_res.register_post_queue_action(Box::new(move || {
1761+
if let Ok(guard) = pm_hook_clone.lock() {
1762+
if let Some(pm) = guard.as_ref().and_then(|weak| weak.upgrade()) {
1763+
pm.process_events();
1764+
}
1765+
}
1766+
}));
1767+
hrn_res as Arc<dyn DNSResolverMessageHandler + Send + Sync>
1768+
},
1769+
HRNResolverConfig::Dns { dns_server_address, enable_hrn_resolution_service, .. } => {
1770+
let addr = dns_server_address.parse().map_err(|_| {
1771+
log_error!(logger, "Failed to parse DNS server address: {}", dns_server_address);
1772+
BuildError::DNSResolverSetupFailed
1773+
})?;
1774+
1775+
let hrn_res = Arc::new(DNSHrnResolver(addr));
1776+
hrn_resolver = HRNResolver::Local(hrn_res);
1777+
1778+
if *enable_hrn_resolution_service {
1779+
if let Err(_) = may_announce_channel(&config) {
1780+
log_error!(
1781+
logger,
1782+
"HRN resolution service enabled, but node is not announceable."
1783+
);
1784+
return Err(BuildError::DNSResolverSetupFailed);
1785+
}
1786+
1787+
Arc::new(OMDomainResolver::<IgnoringMessageHandler>::with_runtime(
1788+
addr,
1789+
None,
1790+
Some(runtime_handle.clone()),
1791+
)) as Arc<dyn DNSResolverMessageHandler + Send + Sync>
1792+
} else {
1793+
// The user wants to use DNS to pay others, but NOT provide a service to others.
1794+
Arc::new(IgnoringMessageHandler {})
1795+
as Arc<dyn DNSResolverMessageHandler + Send + Sync>
1796+
}
1797+
},
1798+
};
17301799

17311800
// Initialize the PeerManager
17321801
let onion_messenger: Arc<OnionMessenger> =
@@ -1739,7 +1808,7 @@ fn build_with_store_internal(
17391808
message_router,
17401809
Arc::clone(&channel_manager),
17411810
Arc::clone(&channel_manager),
1742-
Arc::clone(&hrn_resolver),
1811+
Arc::clone(&om_resolver),
17431812
IgnoringMessageHandler {},
17441813
))
17451814
} else {
@@ -1751,7 +1820,7 @@ fn build_with_store_internal(
17511820
message_router,
17521821
Arc::clone(&channel_manager),
17531822
Arc::clone(&channel_manager),
1754-
Arc::clone(&hrn_resolver),
1823+
Arc::clone(&om_resolver),
17551824
IgnoringMessageHandler {},
17561825
))
17571826
};
@@ -1882,12 +1951,9 @@ fn build_with_store_internal(
18821951
Arc::clone(&keys_manager),
18831952
));
18841953

1885-
let peer_manager_clone = Arc::downgrade(&peer_manager);
1886-
hrn_resolver.register_post_queue_action(Box::new(move || {
1887-
if let Some(upgraded_pointer) = peer_manager_clone.upgrade() {
1888-
upgraded_pointer.process_events();
1889-
}
1890-
}));
1954+
if let Ok(mut guard) = peer_manager_hook.lock() {
1955+
*guard = Some(Arc::downgrade(&peer_manager));
1956+
}
18911957

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

@@ -2001,7 +2067,7 @@ fn build_with_store_internal(
20012067
node_metrics,
20022068
om_mailbox,
20032069
async_payments_role,
2004-
hrn_resolver,
2070+
hrn_resolver: Arc::new(hrn_resolver),
20052071
#[cfg(cycle_tests)]
20062072
_leak_checker,
20072073
})

src/payment/unified.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use bip21::{DeserializationError, DeserializeParams, Param, SerializeParams};
2323
use bitcoin::address::NetworkChecked;
2424
use bitcoin::{Amount, Txid};
2525
use bitcoin_payment_instructions::amount::Amount as BPIAmount;
26+
use bitcoin_payment_instructions::hrn_resolution::DummyHrnResolver;
2627
use bitcoin_payment_instructions::{PaymentInstructions, PaymentMethod};
2728
use lightning::ln::channelmanager::PaymentId;
2829
use lightning::offers::offer::Offer;
@@ -165,12 +166,16 @@ impl UnifiedPayment {
165166
&self, uri_str: &str, amount_msat: Option<u64>,
166167
route_parameters: Option<RouteParametersConfig>,
167168
) -> Result<UnifiedPaymentResult, Error> {
168-
let parse_fut = PaymentInstructions::parse(
169-
uri_str,
170-
self.config.network,
171-
self.hrn_resolver.as_ref(),
172-
false,
173-
);
169+
let resolver;
170+
171+
if let Ok(_) = HumanReadableName::from_encoded(uri_str) {
172+
resolver = Arc::clone(&self.hrn_resolver);
173+
} else {
174+
resolver = Arc::new(HRNResolver::Dummy(DummyHrnResolver));
175+
}
176+
177+
let parse_fut =
178+
PaymentInstructions::parse(uri_str, self.config.network, resolver.as_ref(), false);
174179

175180
let instructions =
176181
tokio::time::timeout(Duration::from_secs(HRN_RESOLUTION_TIMEOUT_SECS), parse_fut)
@@ -196,7 +201,7 @@ impl UnifiedPayment {
196201
Error::InvalidAmount
197202
})?;
198203

199-
let fut = instr.set_amount(amt, self.hrn_resolver.as_ref());
204+
let fut = instr.set_amount(amt, &*resolver);
200205

201206
tokio::time::timeout(Duration::from_secs(HRN_RESOLUTION_TIMEOUT_SECS), fut)
202207
.await
@@ -235,7 +240,7 @@ impl UnifiedPayment {
235240
match method {
236241
PaymentMethod::LightningBolt12(offer) => {
237242
let offer = maybe_wrap(offer.clone());
238-
243+
239244
let payment_result = if let Ok(hrn) = HumanReadableName::from_encoded(uri_str) {
240245
let hrn = maybe_wrap(hrn.clone());
241246
self.bolt12_payment.send_using_amount_inner(&offer, amount_msat.unwrap_or(0), None, None, route_parameters, Some(hrn))

src/runtime.rs

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

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

src/types.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,23 @@ use std::future::Future;
1010
use std::pin::Pin;
1111
use std::sync::{Arc, Mutex};
1212

13+
use bitcoin_payment_instructions::amount::Amount as BPIAmount;
14+
use bitcoin_payment_instructions::dns_resolver::DNSHrnResolver;
15+
use bitcoin_payment_instructions::hrn_resolution::{
16+
DummyHrnResolver, HrnResolutionFuture, HrnResolver, HumanReadableName, LNURLResolutionFuture,
17+
};
18+
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
19+
1320
use bitcoin::secp256k1::PublicKey;
1421
use bitcoin::{OutPoint, ScriptBuf};
15-
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
22+
1623
use lightning::chain::chainmonitor;
1724
use lightning::impl_writeable_tlv_based;
1825
use lightning::ln::channel_state::{ChannelDetails as LdkChannelDetails, ChannelShutdownState};
1926
use lightning::ln::msgs::{RoutingMessageHandler, SocketAddress};
2027
use lightning::ln::peer_handler::IgnoringMessageHandler;
2128
use lightning::ln::types::ChannelId;
29+
use lightning::onion_message::dns_resolution::DNSResolverMessageHandler;
2230
use lightning::routing::gossip;
2331
use lightning::routing::router::DefaultRouter;
2432
use lightning::routing::scoring::{CombinedScorer, ProbabilisticScoringFeeParameters};
@@ -318,11 +326,49 @@ pub(crate) type OnionMessenger = lightning::onion_message::messenger::OnionMesse
318326
Arc<MessageRouter>,
319327
Arc<ChannelManager>,
320328
Arc<ChannelManager>,
321-
Arc<HRNResolver>,
329+
Arc<dyn DNSResolverMessageHandler + Sync + Send>,
322330
IgnoringMessageHandler,
323331
>;
324332

325-
pub(crate) type HRNResolver = LDKOnionMessageDNSSECHrnResolver<Arc<Graph>, Arc<Logger>>;
333+
pub enum HRNResolver {
334+
Onion(Arc<LDKOnionMessageDNSSECHrnResolver<Arc<Graph>, Arc<Logger>>>),
335+
Local(Arc<DNSHrnResolver>),
336+
Dummy(DummyHrnResolver),
337+
}
338+
339+
impl HrnResolver for HRNResolver {
340+
fn resolve_hrn<'a>(&'a self, hrn: &'a HumanReadableName) -> HrnResolutionFuture<'a> {
341+
match self {
342+
HRNResolver::Onion(inner) => inner.resolve_hrn(hrn),
343+
HRNResolver::Local(inner) => inner.resolve_hrn(hrn),
344+
HRNResolver::Dummy(inner) => inner.resolve_hrn(hrn),
345+
}
346+
}
347+
348+
fn resolve_lnurl<'a>(&'a self, url: &'a str) -> HrnResolutionFuture<'a> {
349+
match self {
350+
HRNResolver::Onion(inner) => inner.resolve_lnurl(url),
351+
HRNResolver::Local(inner) => inner.resolve_lnurl(url),
352+
HRNResolver::Dummy(inner) => inner.resolve_lnurl(url),
353+
}
354+
}
355+
356+
fn resolve_lnurl_to_invoice<'a>(
357+
&'a self, callback_url: String, amount: BPIAmount, expected_description_hash: [u8; 32],
358+
) -> LNURLResolutionFuture<'a> {
359+
match self {
360+
HRNResolver::Onion(inner) => {
361+
inner.resolve_lnurl_to_invoice(callback_url, amount, expected_description_hash)
362+
},
363+
HRNResolver::Local(inner) => {
364+
inner.resolve_lnurl_to_invoice(callback_url, amount, expected_description_hash)
365+
},
366+
HRNResolver::Dummy(inner) => {
367+
inner.resolve_lnurl_to_invoice(callback_url, amount, expected_description_hash)
368+
},
369+
}
370+
}
371+
}
326372

327373
pub(crate) type MessageRouter = lightning::onion_message::messenger::DefaultMessageRouter<
328374
Arc<Graph>,

0 commit comments

Comments
 (0)