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: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ lightning-block-sync = { version = "0.2.0-rc1", features = ["rest-client", "rpc-
lightning-transaction-sync = { version = "0.2.0-rc1", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
lightning-liquidity = { version = "0.2.0-rc1", features = ["std"] }
lightning-macros = { version = "0.2.0-rc1" }
lightning-dns-resolver = { version = "0.3.0-rc1" }

#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["std"] }
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
Expand All @@ -52,6 +53,7 @@ lightning-macros = { version = "0.2.0-rc1" }
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main", features = ["esplora-async-https", "electrum-rustls-ring", "time"] }
#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", features = ["std"] }
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
Expand All @@ -64,6 +66,7 @@ lightning-macros = { version = "0.2.0-rc1" }
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03", features = ["esplora-async-https", "electrum-rustls-ring", "time"] }
#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" }

#lightning = { path = "../rust-lightning/lightning", features = ["std"] }
#lightning-types = { path = "../rust-lightning/lightning-types" }
Expand All @@ -76,6 +79,7 @@ lightning-macros = { version = "0.2.0-rc1" }
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync", features = ["esplora-async-https", "electrum-rustls-ring", "time"] }
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity", features = ["std"] }
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolvers" }

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 @@ -103,6 +107,8 @@ log = { version = "0.4.22", default-features = false, features = ["std"]}

vss-client = "0.3"
prost = { version = "0.11.6", default-features = false}
#bitcoin-payment-instructions = { version = "0.5" }
bitcoin-payment-instructions = { git = "https://github.com/chuksys/bitcoin-payment-instructions", branch = "bump-ldk-deps" }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }
Expand Down Expand Up @@ -147,4 +153,4 @@ check-cfg = [
"cfg(tokio_unstable)",
"cfg(cln_test)",
"cfg(lnd_test)",
]
]
30 changes: 24 additions & 6 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 @@ -130,7 +131,7 @@ interface Node {
Bolt12Payment bolt12_payment();
SpontaneousPayment spontaneous_payment();
OnchainPayment onchain_payment();
UnifiedQrPayment unified_qr_payment();
UnifiedPayment unified_payment();
LSPS1Liquidity lsps1_liquidity();
[Throws=NodeError]
void connect(PublicKey node_id, SocketAddress address, boolean persist);
Expand Down Expand Up @@ -203,7 +204,7 @@ interface Bolt12Payment {
[Throws=NodeError]
PaymentId send([ByRef]Offer offer, u64? quantity, string? payer_note);
[Throws=NodeError]
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note);
PaymentId send_using_amount([ByRef]Offer offer, u64 amount_msat, u64? quantity, string? payer_note, HumanReadableName? hrn);
[Throws=NodeError]
Offer receive(u64 amount_msat, [ByRef]string description, u32? expiry_secs, u64? quantity);
[Throws=NodeError]
Expand Down Expand Up @@ -252,11 +253,11 @@ interface FeeRate {
u64 to_sat_per_vb_ceil();
};

interface UnifiedQrPayment {
interface UnifiedPayment {
[Throws=NodeError]
string receive(u64 amount_sats, [ByRef]string message, u32 expiry_sec);
[Throws=NodeError]
QrPaymentResult send([ByRef]string uri_str);
[Throws=NodeError, Async]
UnifiedPaymentResult send([ByRef]string uri_str, u64? amount_msat);
};

interface LSPS1Liquidity {
Expand Down Expand Up @@ -322,6 +323,9 @@ enum NodeError {
"LiquidityFeeTooHigh",
"InvalidBlindedPaths",
"AsyncPaymentServicesDisabled",
"HrnParsingFailed",
"HrnResolverNotConfigured",
"TimeoutOccurred",
};

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

[Trait]
Expand Down Expand Up @@ -431,7 +436,7 @@ interface PaymentKind {
};

[Enum]
interface QrPaymentResult {
interface UnifiedPaymentResult {
Onchain(Txid txid);
Bolt11(PaymentId payment_id);
Bolt12(PaymentId payment_id);
Expand Down Expand Up @@ -476,6 +481,12 @@ dictionary RouteParametersConfig {
u8 max_channel_saturation_power_of_half;
};

dictionary HumanReadableNamesConfig {
sequence<PublicKey> default_dns_resolvers;
boolean is_hrn_resolver;
string dns_server_address;
};

dictionary CustomTlvRecord {
u64 type_num;
sequence<u8> value;
Expand Down Expand Up @@ -783,6 +794,13 @@ interface Offer {
PublicKey? issuer_signing_pubkey();
};

interface HumanReadableName {
[Throws=NodeError, Name=from_encoded]
constructor([ByRef] string encoded);
string user();
string domain();
};

[Traits=(Debug, Display, Eq)]
interface Refund {
[Throws=NodeError, Name=from_str]
Expand Down
60 changes: 56 additions & 4 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ use bip39::Mnemonic;
use bitcoin::bip32::{ChildNumber, Xpriv};
use bitcoin::secp256k1::PublicKey;
use bitcoin::{BlockHash, Network};
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
use lightning::chain::{chainmonitor, BestBlock, Watch};
use lightning::io::Cursor;
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 @@ -38,6 +40,7 @@ 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::{FixedHeaders, LnurlAuthToJwtProvider, VssHeaderProvider};

Expand Down Expand Up @@ -69,8 +72,8 @@ use crate::peer_store::PeerStore;
use crate::runtime::Runtime;
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
ChainMonitor, ChannelManager, DynStore, GossipSync, Graph, KeysManager, MessageRouter,
OnionMessenger, PaymentStore, PeerManager, Persister,
ChainMonitor, ChannelManager, DomainResolver, DynStore, GossipSync, Graph, HRNResolver,
KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager, Persister,
};
use crate::wallet::persist::KVStoreWalletPersister;
use crate::wallet::Wallet;
Expand Down Expand Up @@ -195,6 +198,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 @@ -229,12 +234,20 @@ 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.")
},
}
}
}

impl std::error::Error for BuildError {}

enum Resolver {
HRN(Arc<HRNResolver>),
DNS(Arc<DomainResolver>),
}

/// A builder for an [`Node`] instance, allowing to set some configuration and module choices from
/// the getgo.
///
Expand Down Expand Up @@ -1536,6 +1549,32 @@ fn build_with_store_internal(
})?;
}

let resolver = if let Some(hrn_config) = &config.hrn_config {
if hrn_config.is_hrn_resolver {
let dns_addr = hrn_config.dns_server_address.as_str();

Resolver::DNS(Arc::new(OMDomainResolver::ignoring_incoming_proofs(
dns_addr.parse().map_err(|_| BuildError::DNSResolverSetupFailed)?,
)))
} else {
Resolver::HRN(Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(
&network_graph,
))))
}
} else {
// hrn_config is None, default to the HRN resolver.
Resolver::HRN(Arc::new(LDKOnionMessageDNSSECHrnResolver::new(Arc::clone(&network_graph))))
};

let om_resolver = match resolver {
Resolver::DNS(ref dns_resolver) => {
Arc::clone(dns_resolver) as Arc<dyn DNSResolverMessageHandler + Send + Sync>
},
Resolver::HRN(ref hrn_resolver) => {
Arc::clone(hrn_resolver) as Arc<dyn DNSResolverMessageHandler + Send + Sync>
},
};

// Initialize the PeerManager
let onion_messenger: Arc<OnionMessenger> =
if let Some(AsyncPaymentsRole::Server) = async_payments_role {
Expand All @@ -1547,7 +1586,7 @@ fn build_with_store_internal(
message_router,
Arc::clone(&channel_manager),
Arc::clone(&channel_manager),
IgnoringMessageHandler {},
Arc::clone(&om_resolver),
IgnoringMessageHandler {},
))
} else {
Expand All @@ -1559,7 +1598,7 @@ fn build_with_store_internal(
message_router,
Arc::clone(&channel_manager),
Arc::clone(&channel_manager),
IgnoringMessageHandler {},
Arc::clone(&om_resolver),
IgnoringMessageHandler {},
))
};
Expand Down Expand Up @@ -1691,6 +1730,18 @@ fn build_with_store_internal(
Arc::clone(&keys_manager),
));

let peer_manager_clone = Arc::clone(&peer_manager);

let hrn_resolver = match resolver {
Resolver::DNS(_) => None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, so if we're resolving for others, we won't be able to send to HRNs ourselves?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding, it seems this is the case. The onion messenger can take only one type of dns_resolver at a time - either the one sending out the query or the one handling the query and responding with the proof. If our node is configured to resolve for others, we'd have to pass the appropriate resolver to the onion messenger, preventing us from sending to HRNs ourselves.

Resolver::HRN(ref hrn_resolver) => {
hrn_resolver.register_post_queue_action(Box::new(move || {
peer_manager_clone.process_events();
}));
Some(hrn_resolver)
},
};

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

gossip_source.set_gossip_verifier(
Expand Down Expand Up @@ -1797,6 +1848,7 @@ fn build_with_store_internal(
node_metrics,
om_mailbox,
async_payments_role,
hrn_resolver: hrn_resolver.cloned(),
})
}

Expand Down
25 changes: 24 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ pub(crate) const EXTERNAL_PATHFINDING_SCORES_SYNC_TIMEOUT_SECS: u64 = 5;
/// | `probing_liquidity_limit_multiplier` | 3 |
/// | `log_level` | Debug |
/// | `anchor_channels_config` | Some(..) |
/// | `route_parameters` | None |
/// | `route_parameters` | None |
/// | `hrn_config` | None |
///
/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their
/// respective default values.
Expand Down Expand Up @@ -184,6 +185,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 @@ -198,10 +203,28 @@ impl Default for Config {
anchor_channels_config: Some(AnchorChannelsConfig::default()),
route_parameters: None,
node_alias: None,
hrn_config: None,
}
}
}

/// 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 {
/// The Default DNS resolvers to be used for resolving Human-Readable Names.
///
/// If not empty, the values set will be used as DNS resolvers when sending to HRNs.
///
/// **Note:** If empty, DNS resolvers would be selected from the network graph.
pub default_dns_resolvers: Vec<PublicKey>,
/// This allows us to use our node as a DNS resolver for 3rd party HRN resolutions.
pub is_hrn_resolver: bool,
/// The DNS Server which will be used for resolving HRNs.
pub dns_server_address: String,
}

/// Configuration options pertaining to 'Anchor' channels, i.e., channels for which the
/// `option_anchors_zero_fee_htlc_tx` channel type is negotiated.
///
Expand Down
15 changes: 15 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ pub enum Error {
InvalidBlindedPaths,
/// Asynchronous payment services are disabled.
AsyncPaymentServicesDisabled,
/// Parsing a Human-Readable Name has failed.
HrnParsingFailed,
/// A HRN resolver was not configured
HrnResolverNotConfigured,
/// A Timeout occurred during an operation.
TimeoutOccurred,
}

impl fmt::Display for Error {
Expand Down Expand Up @@ -202,6 +208,15 @@ impl fmt::Display for Error {
Self::AsyncPaymentServicesDisabled => {
write!(f, "Asynchronous payment services are disabled.")
},
Self::HrnParsingFailed => {
write!(f, "Failed to parse a human-readable name.")
},
Self::HrnResolverNotConfigured => {
write!(f, "A HRN resolver was not configured.")
},
Self::TimeoutOccurred => {
write!(f, "A Timeout occured during an operation.")
},
}
}
}
Expand Down
Loading
Loading