Skip to content

Commit 080b233

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 2c256c9 commit 080b233

File tree

8 files changed

+164
-30
lines changed

8 files changed

+164
-30
lines changed

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
@@ -365,6 +365,7 @@ enum NodeError {
365365
"InvalidBlindedPaths",
366366
"AsyncPaymentServicesDisabled",
367367
"HrnParsingFailed",
368+
"HrnResolverNotConfigured",
368369
};
369370

370371
dictionary NodeStatus {
@@ -399,6 +400,8 @@ enum BuildError {
399400
"LoggerSetupFailed",
400401
"NetworkMismatch",
401402
"AsyncPaymentsConfigMismatch",
403+
"DNSResolverSetupFailed",
404+
"PeerManagerSetupFailed",
402405
};
403406

404407
[Trait]

src/builder.rs

Lines changed: 95 additions & 16 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,13 @@ 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};
27-
use lightning::log_trace;
28+
use lightning::onion_message::dns_resolution::DNSResolverMessageHandler;
2829
use lightning::routing::gossip::NodeAlias;
2930
use lightning::routing::router::DefaultRouter;
3031
use lightning::routing::scoring::{
@@ -39,13 +40,15 @@ use lightning::util::persist::{
3940
};
4041
use lightning::util::ser::ReadableArgs;
4142
use lightning::util::sweep::OutputSweeper;
43+
use lightning::{log_trace, log_warn};
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,74 @@ 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: 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+
Arc::new(OMDomainResolver::with_runtime(
1616+
service_dns_addr,
1617+
Some(client_resolver),
1618+
Some(runtime_handle.clone()),
1619+
)) as Arc<dyn DNSResolverMessageHandler + Send + Sync>
1620+
} else {
1621+
log_warn!(logger, "Unable to act as an HRN resolution service. To act as an HRN resolution service, the node must be configured to announce channels.");
1622+
client_resolver
1623+
}
1624+
} else {
1625+
client_resolver
1626+
}
1627+
},
1628+
};
15491629

15501630
// Initialize the PeerManager
15511631
let onion_messenger: Arc<OnionMessenger> =
@@ -1558,7 +1638,7 @@ fn build_with_store_internal(
15581638
message_router,
15591639
Arc::clone(&channel_manager),
15601640
Arc::clone(&channel_manager),
1561-
Arc::clone(&hrn_resolver),
1641+
Arc::clone(&om_resolver),
15621642
IgnoringMessageHandler {},
15631643
))
15641644
} else {
@@ -1570,7 +1650,7 @@ fn build_with_store_internal(
15701650
message_router,
15711651
Arc::clone(&channel_manager),
15721652
Arc::clone(&channel_manager),
1573-
Arc::clone(&hrn_resolver),
1653+
Arc::clone(&om_resolver),
15741654
IgnoringMessageHandler {},
15751655
))
15761656
};
@@ -1691,7 +1771,7 @@ fn build_with_store_internal(
16911771
BuildError::InvalidSystemTime
16921772
})?;
16931773

1694-
let peer_manager = Arc::new(PeerManager::new(
1774+
let peer_manager: Arc<PeerManager> = Arc::new(PeerManager::new(
16951775
msg_handler,
16961776
cur_time.as_secs().try_into().map_err(|e| {
16971777
log_error!(logger, "Failed to get current time: {}", e);
@@ -1702,12 +1782,11 @@ fn build_with_store_internal(
17021782
Arc::clone(&keys_manager),
17031783
));
17041784

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-
}));
1785+
if let Ok(mut guard) = peer_manager_hook.lock() {
1786+
*guard = Some(Arc::downgrade(&peer_manager));
1787+
} else {
1788+
return Err(BuildError::PeerManagerSetupFailed);
1789+
}
17111790

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

@@ -1814,7 +1893,7 @@ fn build_with_store_internal(
18141893
node_metrics,
18151894
om_mailbox,
18161895
async_payments_role,
1817-
hrn_resolver,
1896+
hrn_resolver: Arc::new(hrn_resolver_out),
18181897
#[cfg(cycle_tests)]
18191898
_leak_checker,
18201899
})

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)