-
Notifications
You must be signed in to change notification settings - Fork 157
Expand file tree
/
Copy pathconfig.rs
More file actions
867 lines (787 loc) · 36.7 KB
/
Copy pathconfig.rs
File metadata and controls
867 lines (787 loc) · 36.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
// This file is Copyright its original authors, visible in version control history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
// accordance with one or both of these licenses.
//! Objects for configuring the node.
use std::fmt;
use std::str::FromStr;
use std::time::Duration;
use bitcoin::secp256k1::PublicKey;
use bitcoin::Network;
use lightning::ln::msgs::SocketAddress;
use lightning::routing::gossip::NodeAlias;
use lightning::routing::router::RouteParametersConfig;
use lightning::util::config::{
ChannelConfig as LdkChannelConfig, MaxDustHTLCExposure as LdkMaxDustHTLCExposure, UserConfig,
};
use crate::logger::LogLevel;
// Config defaults
const DEFAULT_NETWORK: Network = Network::Bitcoin;
const DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS: u64 = 80;
const DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS: u64 = 30;
const DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS: u64 = 60 * 10;
const DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER: u64 = 3;
pub(crate) const DEFAULT_PROBING_INTERVAL_SECS: u64 = 10;
pub(crate) const MIN_PROBING_INTERVAL: Duration = Duration::from_millis(100);
pub(crate) const DEFAULT_PROBED_NODE_COOLDOWN_SECS: u64 = 60 * 60; // 1 hour
pub(crate) const DEFAULT_MAX_PROBE_LOCKED_MSAT: u64 = 100_000_000; // 100k sats
pub(crate) const DEFAULT_MIN_PROBE_AMOUNT_MSAT: u64 = 1_000_000; // 1k sats
pub(crate) const DEFAULT_MAX_PROBE_AMOUNT_MSAT: u64 = 10_000_000; // 10k sats
const DEFAULT_ANCHOR_PER_CHANNEL_RESERVE_SATS: u64 = 25_000;
// The default timeout after which we abort a wallet syncing operation.
const DEFAULT_BDK_WALLET_SYNC_TIMEOUT_SECS: u64 = 60;
// The default timeout after which we abort a wallet syncing operation.
const DEFAULT_LDK_WALLET_SYNC_TIMEOUT_SECS: u64 = 30;
// The default timeout after which we abort a fee rate cache update operation.
pub(crate) const DEFAULT_FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS: u64 = 10;
// The default timeout after which we abort a transaction broadcast operation.
pub(crate) const DEFAULT_TX_BROADCAST_TIMEOUT_SECS: u64 = 10;
// The default {Esplora,Electrum} client timeout we're using.
const DEFAULT_PER_REQUEST_TIMEOUT_SECS: u8 = 10;
/// The default log level.
pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Debug;
/// The default log file name.
pub const DEFAULT_LOG_FILENAME: &'static str = "ldk_node.log";
/// The default storage directory.
pub const DEFAULT_STORAGE_DIR_PATH: &str = "/tmp/ldk_node";
// The default Esplora server we're using. It supports `submitpackage`, check using POST on the
// `/txs/package` endpoint.
pub(crate) const DEFAULT_ESPLORA_SERVER_URL: &str = "https://blockstream.info/api";
/// The default stop gap used for BDK full scans of the on-chain wallet.
///
/// The current default is 20.
pub const DEFAULT_FULL_SCAN_STOP_GAP: u32 = 20;
/// The minimum allowed stop gap used for BDK full scans of the on-chain wallet.
///
/// Values below 1 are clamped to 1 when a full scan runs.
pub const MIN_FULL_SCAN_STOP_GAP: u32 = 1;
/// The maximum allowed stop gap used for BDK full scans of the on-chain wallet.
///
/// Values above 1000 are clamped to 1000 when a full scan runs.
pub const MAX_FULL_SCAN_STOP_GAP: u32 = 1000;
// The number of concurrent requests made against the API provider.
pub(crate) const BDK_CLIENT_CONCURRENCY: usize = 4;
// The timeout after which we abandon retrying failed payments.
pub(crate) const LDK_PAYMENT_RETRY_TIMEOUT: Duration = Duration::from_secs(10);
// The time in-between peer reconnection attempts.
pub(crate) const PEER_RECONNECTION_INTERVAL: Duration = Duration::from_secs(60);
// The time in-between RGS sync attempts.
pub(crate) const RGS_SYNC_INTERVAL: Duration = Duration::from_secs(60 * 60);
// The time in-between external scores sync attempts.
pub(crate) const EXTERNAL_PATHFINDING_SCORES_SYNC_INTERVAL: Duration = Duration::from_secs(60 * 60);
// The time in-between node announcement broadcast attempts.
pub(crate) const NODE_ANN_BCAST_INTERVAL: Duration = Duration::from_secs(60 * 60);
// The lower limit which we apply to any configured wallet sync intervals.
pub(crate) const WALLET_SYNC_INTERVAL_MINIMUM_SECS: u64 = 10;
// The timeout after which we give up waiting on LDK's event handler to exit on shutdown.
pub(crate) const LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS: u64 = 30;
// The timeout after which we give up waiting on a background task to exit on shutdown.
pub(crate) const BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS: u64 = 5;
// The maximum encoded size of an RGS snapshot we'll accept.
// In practice the maximum we see is around 4MiB.
pub(crate) const RGS_SNAPSHOT_MAX_SIZE: usize = 15 * 1024 * 1024;
// The timeout after which we abort a RGS sync operation.
pub(crate) const RGS_SYNC_TIMEOUT_SECS: u64 = 5;
/// The length in bytes of our wallets' keys seed.
pub const WALLET_KEYS_SEED_LEN: usize = 64;
// The maximum encoded size of external scores we'll accept.
// In practice we see scores files in the 5MiB range.
pub(crate) const EXTERNAL_PATHFINDING_SCORES_MAX_SIZE: usize = 20 * 1024 * 1024;
// The timeout after which we abort a external scores sync operation.
pub(crate) const EXTERNAL_PATHFINDING_SCORES_SYNC_TIMEOUT_SECS: u64 = 5;
// The timeout after which we abort a parsing/looking up an HRN resolution.
pub(crate) const HRN_RESOLUTION_TIMEOUT_SECS: u64 = 5;
// The timeout after which we abort an LNURL-auth operation.
pub(crate) const LNURL_AUTH_TIMEOUT_SECS: u64 = 15;
// The initial delay before retrying a failed liquidity protocol discovery operation.
pub(crate) const LIQUIDITY_DISCOVERY_RETRY_INITIAL_DELAY: Duration = Duration::from_secs(5);
// The maximum delay the discovery-retry backoff ramps up to, and the interval it keeps retrying at
// thereafter until every configured LSP has been discovered.
pub(crate) const LIQUIDITY_DISCOVERY_RETRY_MAX_DELAY: Duration = Duration::from_secs(60 * 60);
#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
/// Represents the configuration of an [`Node`] instance.
///
/// ### Defaults
///
/// | Parameter | Value |
/// |----------------------------------------|--------------------------------------|
/// | `storage_dir_path` | /tmp/ldk_node/ |
/// | `network` | Bitcoin |
/// | `listening_addresses` | None |
/// | `announcement_addresses` | None |
/// | `node_alias` | None |
/// | `trusted_peers_0conf` | [] |
/// | `probing_liquidity_limit_multiplier` | 3 |
/// | `anchor_channels_config` | AnchorChannelsConfig::default() |
/// | `route_parameters` | None |
/// | `tor_config` | None |
/// | `hrn_config` | HumanReadableNamesConfig::default() |
/// | `manually_handle_unknown_bolt11_payments` | false |
///
/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their
/// respective default values.
///
/// [`Node`]: crate::Node
pub struct Config {
/// The path where the underlying LDK and BDK persist their data.
pub storage_dir_path: String,
/// The used Bitcoin network.
pub network: Network,
/// The addresses on which the node will listen for incoming connections.
///
/// **Note**: We will only allow opening and accepting public channels if the `node_alias` and the
/// `listening_addresses` are set.
pub listening_addresses: Option<Vec<SocketAddress>>,
/// The addresses which the node will announce to the gossip network that it accepts connections on.
///
/// **Note**: If unset, the [`listening_addresses`] will be used as the list of addresses to announce.
///
/// [`listening_addresses`]: Config::listening_addresses
pub announcement_addresses: Option<Vec<SocketAddress>>,
/// The node alias that will be used when broadcasting announcements to the gossip network.
///
/// The provided alias must be a valid UTF-8 string and no longer than 32 bytes in total.
///
/// **Note**: We will only allow opening and accepting public channels if the `node_alias` and the
/// `listening_addresses` are set.
pub node_alias: Option<NodeAlias>,
/// A list of peers that we allow to establish zero confirmation channels to us.
///
/// **Note:** Allowing payments via zero-confirmation channels is potentially insecure if the
/// funding transaction ends up never being confirmed on-chain. Zero-confirmation channels
/// should therefore only be accepted from trusted peers.
pub trusted_peers_0conf: Vec<PublicKey>,
/// The liquidity factor by which we filter the outgoing channels used for sending probes.
///
/// Channels with available liquidity less than the required amount times this value won't be
/// used to send pre-flight probes.
pub probing_liquidity_limit_multiplier: u64,
/// Configuration options pertaining to Anchor channels, i.e., channels for which the
/// `option_zero_fee_commitments` or `option_anchors_zero_fee_htlc_tx` channel type is
/// negotiated.
///
/// Please refer to [`AnchorChannelsConfig`] for further information on Anchor channels.
pub anchor_channels_config: AnchorChannelsConfig,
/// Configuration options for payment routing and pathfinding.
///
/// Setting the [`RouteParametersConfig`] provides flexibility to customize how payments are routed,
/// including setting limits on routing fees, CLTV expiry, and channel utilization.
///
/// **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 enabling peer connections via the Tor network.
///
/// Setting [`TorConfig`] enables connecting to peers with OnionV3 addresses. No other connections
/// are routed via Tor. Please refer to [`TorConfig`] for further information.
///
/// **Note**: If unset, connecting to peer OnionV3 addresses will fail.
pub tor_config: Option<TorConfig>,
/// Configuration options for Human-Readable Names ([BIP 353]).
///
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
pub hrn_config: HumanReadableNamesConfig,
/// Whether to emit [`Event::PaymentClaimable`] for unknown BOLT 11 payments that were created
/// with a user-provided payment hash and therefore need to be manually claimed.
///
/// If disabled, such payments are failed back without being added to the payment store.
///
/// **Warning:** Enabling this may let any holder of a valid invoice generated by this node tie
/// up inbound HTLC slots and grow the persisted event queue until the payment is claimed,
/// failed, or times out.
///
/// [`Event::PaymentClaimable`]: crate::Event::PaymentClaimable
pub manually_handle_unknown_bolt11_payments: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
storage_dir_path: DEFAULT_STORAGE_DIR_PATH.to_string(),
network: DEFAULT_NETWORK,
listening_addresses: None,
announcement_addresses: None,
trusted_peers_0conf: Vec::new(),
probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER,
anchor_channels_config: AnchorChannelsConfig::default(),
tor_config: None,
route_parameters: None,
node_alias: None,
hrn_config: HumanReadableNamesConfig::default(),
manually_handle_unknown_bolt11_payments: false,
}
}
}
/// Configuration options for how our node resolves Human-Readable Names (BIP 353).
///
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
pub enum HRNResolverConfig {
/// Use [bLIP-32] to ask other nodes to resolve names for us.
///
/// [bLIP-32]: https://github.com/lightning/blips/blob/master/blip-0032.md
Blip32,
/// Resolve names locally using a specific DNS server.
Dns {
/// The IP and port of the DNS server.
///
/// **Default:** `8.8.8.8:53` (Google Public DNS)
dns_server_address: SocketAddress,
/// If set to true, this allows others to use our node for HRN resolutions.
///
/// **Default:** `false`
///
/// **Note:** Enabling `enable_hrn_resolution_service` allows your node to act
/// as a resolver for the rest of the network. For this to work, your node must
/// be announceable (publicly visible in the network graph) so that other nodes
/// can route resolution requests to you via Onion Messages. This does not affect
/// your node's ability to resolve names for its own outgoing payments.
enable_hrn_resolution_service: bool,
},
}
/// Configuration options for Human-Readable Names ([BIP 353]).
///
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct HumanReadableNamesConfig {
/// This sets how our node resolves names when we want to send a payment.
///
/// By default, this uses the `Dns` variant with the following settings:
/// * **DNS Server**: `8.8.8.8:53` (Google Public DNS)
/// * **Resolution Service**: Disabled (`false`)
pub resolution_config: HRNResolverConfig,
}
impl Default for HumanReadableNamesConfig {
fn default() -> Self {
HumanReadableNamesConfig {
resolution_config: HRNResolverConfig::Dns {
dns_server_address: SocketAddress::from_str("8.8.8.8:53")
.expect("Socket address conversion failed."),
enable_hrn_resolution_service: false,
},
}
}
}
/// Configuration options pertaining to 'Anchor' channels, i.e., channels for which the
/// `option_zero_fee_commitments` or `option_anchors_zero_fee_htlc_tx` channel type is negotiated.
///
/// Prior to the introduction of Anchor channels, the on-chain fees paying for the transactions
/// issued on channel closure were pre-determined and locked-in at the time of the channel
/// opening. This required to estimate what fee rate would be sufficient to still have the
/// closing transactions be spendable on-chain (i.e., not be considered dust). This legacy
/// design of pre-anchor channels proved inadequate in the unpredictable, often turbulent, fee
/// markets we experience today.
///
/// In contrast, Anchor channels allow to determine an adequate fee rate *at the time of channel
/// closure*, making them much more robust in the face of fee spikes. In turn, they require to
/// maintain a reserve of on-chain funds to have the channel closure transactions confirmed
/// on-chain, at least if the channel counterparty can't be trusted to do this for us.
///
/// See [BOLT 3] for more technical details on Anchor channels.
///
///
/// ### Defaults
///
/// | Parameter | Value |
/// |-------------------------------|--------|
/// | `trusted_peers_no_reserve` | [] |
/// | `per_channel_reserve_sats` | 25000 |
/// | `enable_zero_fee_commitments` | false |
///
///
/// [BOLT 3]: https://github.com/lightning/bolts/blob/master/03-transactions.md#htlc-timeout-and-htlc-success-transactions
#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct AnchorChannelsConfig {
/// A list of peers that we trust to get the required channel closing transactions confirmed
/// on-chain.
///
/// Channels with these peers won't count towards the retained on-chain reserve and we won't
/// take any action to get the required channel closing transactions confirmed ourselves.
///
/// **Note:** Trusting the channel counterparty to take the necessary actions to get the
/// required Anchor spending transactions confirmed on-chain is potentially insecure
/// as the channel may not be closed if they refuse to do so.
pub trusted_peers_no_reserve: Vec<PublicKey>,
/// The amount of satoshis per anchors-negotiated channel with an untrusted peer that we keep
/// as an emergency reserve in our on-chain wallet.
///
/// This allows for having the required Anchor output spending and HTLC transactions confirmed
/// when the channel is closed.
///
/// If the channel peer is not marked as trusted via
/// [`AnchorChannelsConfig::trusted_peers_no_reserve`], we will always try to spend the Anchor
/// outputs with *any* on-chain funds available, i.e., the total reserve value as well as any
/// spendable funds available in the on-chain wallet. Therefore, this per-channel multiplier is
/// really an emergency reserve that we maintain at all time to reduce the risk of
/// insufficient funds at time of a channel closure. To this end, we will refuse to open
/// outbound or accept inbound channels if we don't have sufficient on-chain funds available to
/// cover the additional reserve requirement.
///
/// **Note:** Depending on the fee market at the time of closure, this reserve amount might or
/// might not suffice to successfully spend the Anchor output and have the HTLC transactions
/// confirmed on-chain, i.e., you may want to adjust this value accordingly.
pub per_channel_reserve_sats: u64,
/// If set, we will first attempt to negotiate `option_zero_fee_commitments` before falling
/// back to `option_anchors_zero_fee_htlc_tx` and `option_static_remotekey`, as supported by
/// the peer. Zero-fee commitment channels remove all commitment feerate negotiation from
/// the channel, which eliminates a very common source of channel force-closures. These
/// channels instead source *all* the fees required to confirm the commitment from the
/// anchor reserve of the channel closer at the time of force-close. If set, your chain
/// source *must* support the `submitpackage` Bitcoin Core RPC, and relay [TRUC], [P2A],
/// and [Ephemeral Dust].
/// See [BOLT 3] for more technical details.
///
/// [TRUC]: https://github.com/bitcoin/bips/blob/master/bip-0431.mediawiki
/// [P2A]: https://github.com/bitcoin/bips/blob/master/bip-0433.mediawiki
/// [Ephemeral Dust]: https://bitcoincore.org/en/releases/29.0
/// [BOLT 3]: https://github.com/lightning/bolts/blob/master/03-transactions.md#shared_anchor-output-zero_fee_commitments
pub enable_zero_fee_commitments: bool,
}
impl Default for AnchorChannelsConfig {
fn default() -> Self {
Self {
trusted_peers_no_reserve: Vec::new(),
per_channel_reserve_sats: DEFAULT_ANCHOR_PER_CHANNEL_RESERVE_SATS,
enable_zero_fee_commitments: false,
}
}
}
/// Returns a [`Config`] object populated with default values.
///
/// See the documentation of [`Config`] for more information on the used defaults.
///
/// This is mostly meant for use in bindings, in Rust this is synonymous with
/// [`Config::default()`].
pub fn default_config() -> Config {
Config::default()
}
#[derive(Debug, PartialEq)]
pub(crate) enum AnnounceError {
MissingNodeAlias,
MissingListeningAddresses,
MissingAliasAndAddresses,
}
impl fmt::Display for AnnounceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AnnounceError::MissingNodeAlias => write!(f, "Node alias is not configured"),
AnnounceError::MissingListeningAddresses => {
write!(f, "Listening addresses are not configured")
},
AnnounceError::MissingAliasAndAddresses => {
write!(f, "Node alias and listening addresses are not configured")
},
}
}
}
pub(crate) fn may_announce_channel(config: &Config) -> Result<(), AnnounceError> {
let has_listening_addresses =
config.listening_addresses.as_ref().map_or(false, |addrs| !addrs.is_empty());
match (config.node_alias.is_some(), has_listening_addresses) {
(true, true) => Ok(()),
(true, false) => Err(AnnounceError::MissingListeningAddresses),
(false, true) => Err(AnnounceError::MissingNodeAlias),
(false, false) => Err(AnnounceError::MissingAliasAndAddresses),
}
}
pub(crate) fn default_user_config(config: &Config) -> UserConfig {
// Initialize the default config values.
//
// Note that methods such as Node::open_channel and Node::open_announced_channel might override
// some of the values set here, e.g. the ChannelHandshakeConfig, meaning these default values
// will mostly be relevant for inbound channels.
let mut user_config = UserConfig::default();
user_config.channel_handshake_limits.force_announced_channel_preference = false;
user_config.channel_handshake_config.negotiate_anchor_zero_fee_commitments =
config.anchor_channels_config.enable_zero_fee_commitments;
user_config.reject_inbound_splices = false;
if may_announce_channel(config).is_err() {
user_config.accept_forwards_to_priv_channels = false;
user_config.channel_handshake_config.announce_for_forwarding = false;
user_config.channel_handshake_limits.force_announced_channel_preference = true;
}
user_config
}
/// Options related to background syncing the Lightning and on-chain wallets.
///
/// ### Defaults
///
/// | Parameter | Value |
/// |----------------------------------------|--------------------|
/// | `onchain_wallet_sync_interval_secs` | 80 |
/// | `lightning_wallet_sync_interval_secs` | 30 |
/// | `fee_rate_cache_update_interval_secs` | 600 |
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct BackgroundSyncConfig {
/// The time in-between background sync attempts of the onchain wallet, in seconds.
///
/// **Note:** A minimum of 10 seconds is enforced when background syncing is enabled.
pub onchain_wallet_sync_interval_secs: u64,
/// The time in-between background sync attempts of the LDK wallet, in seconds.
///
/// **Note:** A minimum of 10 seconds is enforced when background syncing is enabled.
pub lightning_wallet_sync_interval_secs: u64,
/// The time in-between background update attempts to our fee rate cache, in seconds.
///
/// **Note:** A minimum of 10 seconds is enforced when background syncing is enabled.
pub fee_rate_cache_update_interval_secs: u64,
}
impl Default for BackgroundSyncConfig {
fn default() -> Self {
Self {
onchain_wallet_sync_interval_secs: DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS,
lightning_wallet_sync_interval_secs: DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS,
fee_rate_cache_update_interval_secs: DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS,
}
}
}
/// Timeout-related parameters for syncing the Lightning and on-chain wallets.
///
/// ### Defaults
///
/// | Parameter | Value |
/// |----------------------------------------|--------------------|
/// | `onchain_wallet_sync_timeout_secs` | 60 |
/// | `lightning_wallet_sync_timeout_secs` | 30 |
/// | `fee_rate_cache_update_timeout_secs` | 10 |
/// | `tx_broadcast_timeout_secs` | 10 |
/// | `per_request_timeout_secs` | 10 |
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct SyncTimeoutsConfig {
/// The timeout after which we abort syncing the onchain wallet.
pub onchain_wallet_sync_timeout_secs: u64,
/// The timeout after which we abort syncing the LDK wallet.
pub lightning_wallet_sync_timeout_secs: u64,
/// The timeout after which we abort updating the fee rate cache.
pub fee_rate_cache_update_timeout_secs: u64,
/// The timeout after which we abort broadcasting a transaction.
pub tx_broadcast_timeout_secs: u64,
/// The per-request timeout after which we abort a single Electrum or Esplora API request.
pub per_request_timeout_secs: u8,
}
impl Default for SyncTimeoutsConfig {
fn default() -> Self {
Self {
onchain_wallet_sync_timeout_secs: DEFAULT_BDK_WALLET_SYNC_TIMEOUT_SECS,
lightning_wallet_sync_timeout_secs: DEFAULT_LDK_WALLET_SYNC_TIMEOUT_SECS,
fee_rate_cache_update_timeout_secs: DEFAULT_FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS,
tx_broadcast_timeout_secs: DEFAULT_TX_BROADCAST_TIMEOUT_SECS,
per_request_timeout_secs: DEFAULT_PER_REQUEST_TIMEOUT_SECS,
}
}
}
/// Configuration for syncing with an Esplora backend.
///
/// Background syncing is enabled by default, using the default values specified in
/// [`BackgroundSyncConfig`].
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct EsploraSyncConfig {
/// Background sync configuration.
///
/// If set to `None`, background syncing will be disabled. Users will need to manually
/// sync via [`Node::sync_wallets`] for the wallets and fee rate updates.
///
/// [`Node::sync_wallets`]: crate::Node::sync_wallets
pub background_sync_config: Option<BackgroundSyncConfig>,
/// Sync timeouts configuration.
pub timeouts_config: SyncTimeoutsConfig,
/// The stop gap used for BDK full scans of the on-chain wallet.
///
/// A full scan for each keychain stops after this many consecutive script pubkeys
/// with no associated transactions. This value is only used for BDK `full_scan`
/// calls, which ldk-node performs on the first on-chain wallet sync or when
/// [`Self::force_wallet_full_scan`] is set. Incremental BDK `sync` calls do not use it.
///
/// **Default:** 20 ([`DEFAULT_FULL_SCAN_STOP_GAP`])
///
/// **Allowed values:** 1 ([`MIN_FULL_SCAN_STOP_GAP`]) to 1000
/// ([`MAX_FULL_SCAN_STOP_GAP`]), inclusive. Values outside this range will be clamped to the
/// nearest bound and a warning will be logged when the full scan runs.
///
/// **Note:** Large values can cause many Esplora requests, hit server rate limits,
/// take a long time to complete, or cause syncs to fail with
/// [`SyncTimeoutsConfig::onchain_wallet_sync_timeout_secs`].
pub full_scan_stop_gap: u32,
/// Whether to force BDK full scans until one succeeds.
///
/// This can be useful when restoring a wallet from seed on a node that has already synced
/// before, but may be missing funds sent to previously-unknown addresses.
pub force_wallet_full_scan: bool,
}
impl Default for EsploraSyncConfig {
fn default() -> Self {
Self {
background_sync_config: Some(BackgroundSyncConfig::default()),
timeouts_config: SyncTimeoutsConfig::default(),
full_scan_stop_gap: DEFAULT_FULL_SCAN_STOP_GAP,
force_wallet_full_scan: false,
}
}
}
/// Configuration for syncing with an Electrum backend.
///
/// Background syncing is enabled by default, using the default values specified in
/// [`BackgroundSyncConfig`].
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct ElectrumSyncConfig {
/// Background sync configuration.
///
/// If set to `None`, background syncing will be disabled. Users will need to manually
/// sync via [`Node::sync_wallets`] for the wallets and fee rate updates.
///
/// [`Node::sync_wallets`]: crate::Node::sync_wallets
pub background_sync_config: Option<BackgroundSyncConfig>,
/// Sync timeouts configuration.
pub timeouts_config: SyncTimeoutsConfig,
/// The stop gap used for BDK full scans of the on-chain wallet.
///
/// A full scan for each keychain stops after this many consecutive script pubkeys
/// with no associated transactions. This value is only used for BDK `full_scan`
/// calls, which ldk-node performs on the first on-chain wallet sync or when
/// [`Self::force_wallet_full_scan`] is set. Incremental BDK `sync` calls do not use it.
///
/// **Default:** 20 ([`DEFAULT_FULL_SCAN_STOP_GAP`])
///
/// **Allowed values:** 1 ([`MIN_FULL_SCAN_STOP_GAP`]) to 1000
/// ([`MAX_FULL_SCAN_STOP_GAP`]), inclusive. Values outside this range will be clamped to the
/// nearest bound and a warning will be logged when the full scan runs.
///
/// **Note:** Large values can cause many Electrum requests, hit server rate limits,
/// take a long time to complete, or cause syncs to fail with
/// [`SyncTimeoutsConfig::onchain_wallet_sync_timeout_secs`].
pub full_scan_stop_gap: u32,
/// Whether to force BDK full scans until one succeeds.
///
/// This can be useful when restoring a wallet from seed on a node that has already synced
/// before, but may be missing funds sent to previously-unknown addresses.
pub force_wallet_full_scan: bool,
}
impl Default for ElectrumSyncConfig {
fn default() -> Self {
Self {
background_sync_config: Some(BackgroundSyncConfig::default()),
timeouts_config: SyncTimeoutsConfig::default(),
full_scan_stop_gap: DEFAULT_FULL_SCAN_STOP_GAP,
force_wallet_full_scan: false,
}
}
}
pub(crate) fn clamp_full_scan_stop_gap(full_scan_stop_gap: u32) -> u32 {
full_scan_stop_gap.clamp(MIN_FULL_SCAN_STOP_GAP, MAX_FULL_SCAN_STOP_GAP)
}
/// Configuration for syncing with Bitcoin Core backend via REST.
#[derive(Debug, Clone)]
pub struct BitcoindRestClientConfig {
/// Host URL.
pub rest_host: String,
/// Host port.
pub rest_port: u16,
}
/// Configuration for connecting to peers via the Tor Network.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct TorConfig {
/// Tor daemon SOCKS proxy address. Only connections to OnionV3 peers will be made
/// via this proxy; other connections (IPv4 peers, Electrum server) will not be
/// routed over Tor.
pub proxy_address: SocketAddress,
}
/// Options which apply on a per-channel basis and may change at runtime or based on negotiation
/// with our counterparty.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Please refer to [`LdkChannelConfig`] for further details.
pub forwarding_fee_proportional_millionths: u32,
/// Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in
/// excess of [`ChannelConfig::forwarding_fee_proportional_millionths`].
/// This may be allowed to change at runtime in a later update, however doing so must result in
/// update messages sent to notify all nodes of our updated relay fee.
///
/// Please refer to [`LdkChannelConfig`] for further details.
pub forwarding_fee_base_msat: u32,
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over
/// the channel this config applies to.
///
/// Please refer to [`LdkChannelConfig`] for further details.
pub cltv_expiry_delta: u16,
/// Limit our total exposure to potential loss to on-chain fees on close, including in-flight
/// HTLCs which are burned to fees as they are too small to claim on-chain and fees on
/// commitment transaction(s) broadcasted by our counterparty in excess of our own fee estimate.
///
/// Please refer to [`LdkChannelConfig`] for further details.
pub max_dust_htlc_exposure: MaxDustHTLCExposure,
/// The additional fee we're willing to pay to avoid waiting for the counterparty's
/// `to_self_delay` to reclaim funds.
///
/// Please refer to [`LdkChannelConfig`] for further details.
pub force_close_avoidance_max_fee_satoshis: u64,
/// If set, allows this channel's counterparty to skim an additional fee off this node's inbound
/// HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users.
///
/// Please refer to [`LdkChannelConfig`] for further details.
pub accept_underpaying_htlcs: bool,
}
impl From<LdkChannelConfig> for ChannelConfig {
fn from(value: LdkChannelConfig) -> Self {
Self {
forwarding_fee_proportional_millionths: value.forwarding_fee_proportional_millionths,
forwarding_fee_base_msat: value.forwarding_fee_base_msat,
cltv_expiry_delta: value.cltv_expiry_delta,
max_dust_htlc_exposure: value.max_dust_htlc_exposure.into(),
force_close_avoidance_max_fee_satoshis: value.force_close_avoidance_max_fee_satoshis,
accept_underpaying_htlcs: value.accept_underpaying_htlcs,
}
}
}
impl From<ChannelConfig> for LdkChannelConfig {
fn from(value: ChannelConfig) -> Self {
Self {
forwarding_fee_proportional_millionths: value.forwarding_fee_proportional_millionths,
forwarding_fee_base_msat: value.forwarding_fee_base_msat,
cltv_expiry_delta: value.cltv_expiry_delta,
max_dust_htlc_exposure: value.max_dust_htlc_exposure.into(),
force_close_avoidance_max_fee_satoshis: value.force_close_avoidance_max_fee_satoshis,
accept_underpaying_htlcs: value.accept_underpaying_htlcs,
}
}
}
impl Default for ChannelConfig {
fn default() -> Self {
LdkChannelConfig::default().into()
}
}
/// Options for how to set the max dust exposure allowed on a channel.
///
/// See [`LdkChannelConfig::max_dust_htlc_exposure`] for details.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
pub enum MaxDustHTLCExposure {
/// This sets a fixed limit on the total dust exposure in millisatoshis.
///
/// Please refer to [`LdkMaxDustHTLCExposure`] for further details.
FixedLimit {
/// The fixed limit, in millisatoshis.
limit_msat: u64,
},
/// This sets a multiplier on the feerate to determine the maximum allowed dust exposure.
///
/// Please refer to [`LdkMaxDustHTLCExposure`] for further details.
FeeRateMultiplier {
/// The applied fee rate multiplier.
multiplier: u64,
},
}
impl From<LdkMaxDustHTLCExposure> for MaxDustHTLCExposure {
fn from(value: LdkMaxDustHTLCExposure) -> Self {
match value {
LdkMaxDustHTLCExposure::FixedLimitMsat(limit_msat) => Self::FixedLimit { limit_msat },
LdkMaxDustHTLCExposure::FeeRateMultiplier(multiplier) => {
Self::FeeRateMultiplier { multiplier }
},
}
}
}
impl From<MaxDustHTLCExposure> for LdkMaxDustHTLCExposure {
fn from(value: MaxDustHTLCExposure) -> Self {
match value {
MaxDustHTLCExposure::FixedLimit { limit_msat } => Self::FixedLimitMsat(limit_msat),
MaxDustHTLCExposure::FeeRateMultiplier { multiplier } => {
Self::FeeRateMultiplier(multiplier)
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
/// The role of the node in an asynchronous payments context.
///
/// See <https://github.com/lightning/bolts/pull/1149> for more information about the async payments protocol.
pub enum AsyncPaymentsRole {
/// Node acts a client in an async payments context. This means that if possible, it will instruct its peers to hold
/// HTLCs for it, so that it can go offline.
Client,
/// Node acts as a server in an async payments context. This means that it will hold async payments HTLCs and onion
/// messages for its peers.
Server,
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::{
clamp_full_scan_stop_gap, may_announce_channel, AnnounceError, Config, ElectrumSyncConfig,
EsploraSyncConfig, NodeAlias, SocketAddress, DEFAULT_FULL_SCAN_STOP_GAP,
MAX_FULL_SCAN_STOP_GAP, MIN_FULL_SCAN_STOP_GAP,
};
#[test]
fn node_announce_channel() {
// Default configuration with node alias and listening addresses unset
let mut node_config = Config::default();
assert_eq!(
may_announce_channel(&node_config),
Err(AnnounceError::MissingAliasAndAddresses)
);
// Set node alias with listening addresses unset
let alias_frm_str = |alias: &str| {
let mut bytes = [0u8; 32];
bytes[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes());
NodeAlias(bytes)
};
node_config.node_alias = Some(alias_frm_str("LDK_Node"));
assert_eq!(
may_announce_channel(&node_config),
Err(AnnounceError::MissingListeningAddresses)
);
// Set announcement addresses with listening addresses unset
let announcement_address = SocketAddress::from_str("123.45.67.89:9735")
.expect("Socket address conversion failed.");
node_config.announcement_addresses = Some(vec![announcement_address]);
assert_eq!(
may_announce_channel(&node_config),
Err(AnnounceError::MissingListeningAddresses)
);
// Set node alias with an empty list of listening addresses
node_config.listening_addresses = Some(vec![]);
assert_eq!(
may_announce_channel(&node_config),
Err(AnnounceError::MissingListeningAddresses)
);
// Set node alias with a non-empty list of listening addresses
let socket_address =
SocketAddress::from_str("localhost:8000").expect("Socket address conversion failed.");
if let Some(ref mut addresses) = node_config.listening_addresses {
addresses.push(socket_address);
}
assert!(may_announce_channel(&node_config).is_ok());
}
#[test]
fn full_scan_stop_gap_defaults() {
assert_eq!(EsploraSyncConfig::default().full_scan_stop_gap, DEFAULT_FULL_SCAN_STOP_GAP);
assert_eq!(ElectrumSyncConfig::default().full_scan_stop_gap, DEFAULT_FULL_SCAN_STOP_GAP);
}
#[test]
fn full_scan_stop_gap_is_clamped_to_valid_range() {
assert_eq!(clamp_full_scan_stop_gap(MIN_FULL_SCAN_STOP_GAP), MIN_FULL_SCAN_STOP_GAP);
assert_eq!(
clamp_full_scan_stop_gap(DEFAULT_FULL_SCAN_STOP_GAP),
DEFAULT_FULL_SCAN_STOP_GAP
);
assert_eq!(clamp_full_scan_stop_gap(MAX_FULL_SCAN_STOP_GAP), MAX_FULL_SCAN_STOP_GAP);
assert_eq!(clamp_full_scan_stop_gap(0), MIN_FULL_SCAN_STOP_GAP);
assert_eq!(clamp_full_scan_stop_gap(MAX_FULL_SCAN_STOP_GAP + 1), MAX_FULL_SCAN_STOP_GAP);
}
}