Skip to content

Commit 5fba01a

Browse files
committed
Track anchor reserves for unresolved monitors
Anchor reserve accounting only looked at channels returned by the ChannelManager. That misses an important force-close transition: ChannelManager::list_channels can stop returning a channel before its commitment transaction confirms. During that window the ChannelMonitor can still broadcast, rebroadcast, or fee-bump the holder commitment and its anchor spend, so the wallet's emergency reserve must remain available. We now require a anchor reserve to be kept for non-trusted channels where the type is not yet known; we've recently made anchor channels always supported in ldk-node, so at this point it is safe to assume most channels of ldk-node will be anchor channels. We now no longer count existing 0FC channels to validate support for submitpackage on the chain source if those channels are in the trusted peers list. Co-Authored-By: HAL 9000
1 parent 7830a16 commit 5fba01a

7 files changed

Lines changed: 192 additions & 71 deletions

File tree

src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,6 +2103,7 @@ fn build_with_store_internal(
21032103
Arc::clone(&wallet),
21042104
Arc::clone(&channel_manager),
21052105
Arc::clone(&keys_manager),
2106+
Arc::clone(&chain_monitor),
21062107
Arc::clone(&tx_broadcaster),
21072108
Arc::clone(&kv_store),
21082109
Arc::clone(&config),

src/event.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ use crate::payment::PaymentMetadata;
5555
use crate::probing::Prober;
5656
use crate::runtime::Runtime;
5757
use crate::types::{
58-
CustomTlvRecord, DynStore, KeysManager, OnionMessenger, PaymentStore, Sweeper, Wallet,
58+
ChainMonitor, CustomTlvRecord, DynStore, KeysManager, OnionMessenger, PaymentStore, Sweeper,
59+
Wallet,
5960
};
6061
use crate::{
6162
hex_utils, BumpTransactionEventHandler, ChannelManager, Error, Graph, PeerInfo, PeerStore,
@@ -530,6 +531,7 @@ where
530531
wallet: Arc<Wallet>,
531532
bump_tx_event_handler: Arc<BumpTransactionEventHandler>,
532533
channel_manager: Arc<ChannelManager>,
534+
chain_monitor: Arc<ChainMonitor>,
533535
connection_manager: Arc<ConnectionManager<L>>,
534536
output_sweeper: Arc<Sweeper>,
535537
network_graph: Arc<Graph>,
@@ -553,19 +555,20 @@ where
553555
pub fn new(
554556
event_queue: Arc<EventQueue<L>>, wallet: Arc<Wallet>,
555557
bump_tx_event_handler: Arc<BumpTransactionEventHandler>,
556-
channel_manager: Arc<ChannelManager>, connection_manager: Arc<ConnectionManager<L>>,
557-
output_sweeper: Arc<Sweeper>, network_graph: Arc<Graph>,
558-
liquidity_source: Arc<LiquiditySource<Arc<Logger>>>, payment_store: Arc<PaymentStore>,
559-
peer_store: Arc<PeerStore<L>>, keys_manager: Arc<KeysManager>,
560-
static_invoice_store: Option<StaticInvoiceStore>, onion_messenger: Arc<OnionMessenger>,
561-
om_mailbox: Option<Arc<OnionMessageMailbox>>, prober: Option<Arc<Prober>>,
562-
runtime: Arc<Runtime>, logger: L, config: Arc<Config>,
558+
channel_manager: Arc<ChannelManager>, chain_monitor: Arc<ChainMonitor>,
559+
connection_manager: Arc<ConnectionManager<L>>, output_sweeper: Arc<Sweeper>,
560+
network_graph: Arc<Graph>, liquidity_source: Arc<LiquiditySource<Arc<Logger>>>,
561+
payment_store: Arc<PaymentStore>, peer_store: Arc<PeerStore<L>>,
562+
keys_manager: Arc<KeysManager>, static_invoice_store: Option<StaticInvoiceStore>,
563+
onion_messenger: Arc<OnionMessenger>, om_mailbox: Option<Arc<OnionMessageMailbox>>,
564+
prober: Option<Arc<Prober>>, runtime: Arc<Runtime>, logger: L, config: Arc<Config>,
563565
) -> Self {
564566
Self {
565567
event_queue,
566568
wallet,
567569
bump_tx_event_handler,
568570
channel_manager,
571+
chain_monitor,
569572
connection_manager,
570573
output_sweeper,
571574
network_graph,
@@ -1276,6 +1279,7 @@ where
12761279
if required_reserve_sats > 0 {
12771280
let cur_anchor_reserve_sats = crate::total_anchor_channels_reserve_sats(
12781281
&self.channel_manager,
1282+
&self.chain_monitor,
12791283
&self.config,
12801284
);
12811285
let spendable_amount_sats =

src/lib.rs

Lines changed: 120 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ mod types;
109109
mod util;
110110
mod wallet;
111111

112+
use std::collections::HashSet;
112113
use std::default::Default;
113114
use std::sync::{Arc, Mutex, RwLock};
114115
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
@@ -129,9 +130,9 @@ pub use builder::BuildError;
129130
pub use builder::NodeBuilder as Builder;
130131
use chain::ChainSource;
131132
use config::{
132-
default_user_config, may_announce_channel, AsyncPaymentsRole, ChannelConfig, Config,
133-
LNURL_AUTH_TIMEOUT_SECS, NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL,
134-
RGS_SYNC_INTERVAL,
133+
default_user_config, may_announce_channel, AnchorChannelsConfig, AsyncPaymentsRole,
134+
ChannelConfig, Config, LNURL_AUTH_TIMEOUT_SECS, NODE_ANN_BCAST_INTERVAL,
135+
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
135136
};
136137
use connection::ConnectionManager;
137138
pub use error::Error as NodeError;
@@ -147,6 +148,7 @@ use gossip::GossipSource;
147148
use graph::NetworkGraph;
148149
use io::utils::update_and_persist_node_metrics;
149150
pub use lightning;
151+
use lightning::chain::chainmonitor::LockedChannelMonitor;
150152
use lightning::chain::BlockLocator;
151153
use lightning::impl_writeable_tlv_based;
152154
use lightning::ln::chan_utils::FUNDING_TRANSACTION_WITNESS_WEIGHT;
@@ -156,7 +158,7 @@ use lightning::ln::channelmanager::PaymentId;
156158
use lightning::ln::msgs::{BaseMessageHandler, SocketAddress};
157159
use lightning::ln::peer_handler::CustomMessageHandler;
158160
use lightning::routing::gossip::NodeAlias;
159-
use lightning::sign::EntropySource;
161+
use lightning::sign::{EntropySource, InMemorySigner};
160162
use lightning::util::persist::KVStore;
161163
use lightning::util::wallet_utils::{Input, Wallet as LdkWallet};
162164
use lightning_background_processor::process_events_async;
@@ -306,27 +308,19 @@ impl Node {
306308
e
307309
})?;
308310

309-
let manager_owns_any_0fc_channels =
310-
self.channel_manager.list_channels().into_iter().any(|channel| {
311-
channel
312-
.channel_shutdown_state
313-
.map_or(true, |s| s != ChannelShutdownState::ShutdownComplete)
314-
&& channel
315-
.channel_type
316-
.as_ref()
317-
.map_or(false, |c| c.requires_anchor_zero_fee_commitments())
318-
});
319-
let monitor_owns_any_0fc_channels =
320-
self.chain_monitor.list_monitors().into_iter().any(|channel_id| {
321-
self.chain_monitor
322-
.get_monitor(channel_id)
323-
.map(|monitor| {
324-
monitor.channel_type_features().requires_anchor_zero_fee_commitments()
325-
})
326-
.unwrap_or(false)
327-
});
328-
let zero_fee_commitments_support_required = manager_owns_any_0fc_channels
329-
|| monitor_owns_any_0fc_channels
311+
let zero_fee_channel_count = channels_requiring_reserve_count(
312+
&self.channel_manager,
313+
&self.chain_monitor,
314+
&self.config.anchor_channels_config,
315+
// Do not count keyed anchor channel types
316+
false,
317+
// Do not count a channel if the type is not yet known to avoid requiring
318+
// support for `submitpackage` in case ldk-node restarts in the middle of
319+
// channel negotiation.
320+
false,
321+
);
322+
323+
let zero_fee_commitments_support_required = zero_fee_channel_count != 0
330324
|| self.config.anchor_channels_config.enable_zero_fee_commitments;
331325

332326
// Block to ensure we update our fee rate cache once on startup.
@@ -655,6 +649,7 @@ impl Node {
655649
Arc::clone(&self.wallet),
656650
bump_tx_event_handler,
657651
Arc::clone(&self.channel_manager),
652+
Arc::clone(&self.chain_monitor),
658653
Arc::clone(&self.connection_manager),
659654
Arc::clone(&self.output_sweeper),
660655
Arc::clone(&self.network_graph),
@@ -1104,6 +1099,7 @@ impl Node {
11041099
OnchainPayment::new(
11051100
Arc::clone(&self.wallet),
11061101
Arc::clone(&self.channel_manager),
1102+
Arc::clone(&self.chain_monitor),
11071103
Arc::clone(&self.config),
11081104
Arc::clone(&self.is_running),
11091105
Arc::clone(&self.logger),
@@ -1116,6 +1112,7 @@ impl Node {
11161112
Arc::new(OnchainPayment::new(
11171113
Arc::clone(&self.wallet),
11181114
Arc::clone(&self.channel_manager),
1115+
Arc::clone(&self.chain_monitor),
11191116
Arc::clone(&self.config),
11201117
Arc::clone(&self.is_running),
11211118
Arc::clone(&self.logger),
@@ -1305,8 +1302,11 @@ impl Node {
13051302
},
13061303
FundingAmount::Max => {
13071304
// Determine max funding amount from all available on-chain funds.
1308-
let cur_anchor_reserve_sats =
1309-
total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
1305+
let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(
1306+
&self.channel_manager,
1307+
&self.chain_monitor,
1308+
&self.config,
1309+
);
13101310
let new_channel_reserve =
13111311
self.new_channel_anchor_reserve_sats(&peer_info.node_id)?;
13121312
let total_anchor_reserve_sats = cur_anchor_reserve_sats + new_channel_reserve;
@@ -1410,8 +1410,11 @@ impl Node {
14101410
&self, amount_sats: u64, peer_node_id: &PublicKey, for_new_channel: bool,
14111411
) -> Result<(), Error> {
14121412
let action_str = if for_new_channel { "create channel" } else { "splice-in" };
1413-
let cur_anchor_reserve_sats =
1414-
total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
1413+
let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(
1414+
&self.channel_manager,
1415+
&self.chain_monitor,
1416+
&self.config,
1417+
);
14151418
let spendable_amount_sats =
14161419
self.wallet.get_spendable_amount_sats(cur_anchor_reserve_sats).unwrap_or(0);
14171420

@@ -1661,8 +1664,11 @@ impl Node {
16611664
let splice_amount_sats = match splice_amount_sats {
16621665
FundingAmount::Exact { amount_sats } => amount_sats,
16631666
FundingAmount::Max => {
1664-
let cur_anchor_reserve_sats =
1665-
total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
1667+
let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(
1668+
&self.channel_manager,
1669+
&self.chain_monitor,
1670+
&self.config,
1671+
);
16661672

16671673
const EMPTY_SCRIPT_SIG_WEIGHT: u64 =
16681674
1 /* empty script_sig */ * bitcoin::constants::WITNESS_SCALE_FACTOR as u64;
@@ -2130,8 +2136,11 @@ impl Node {
21302136

21312137
/// Retrieves an overview of all known balances.
21322138
pub fn list_balances(&self) -> BalanceDetails {
2133-
let cur_anchor_reserve_sats =
2134-
total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
2139+
let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(
2140+
&self.channel_manager,
2141+
&self.chain_monitor,
2142+
&self.config,
2143+
);
21352144
let (total_onchain_balance_sats, spendable_onchain_balance_sats) =
21362145
self.wallet.get_balances(cur_anchor_reserve_sats).unwrap_or((0, 0));
21372146

@@ -2453,22 +2462,85 @@ impl_writeable_tlv_based!(NodeMetrics, {
24532462
});
24542463

24552464
pub(crate) fn total_anchor_channels_reserve_sats(
2456-
channel_manager: &ChannelManager, config: &Config,
2465+
channel_manager: &ChannelManager, chain_monitor: &ChainMonitor, config: &Config,
24572466
) -> u64 {
2458-
channel_manager
2459-
.list_channels()
2460-
.into_iter()
2461-
.filter(|c| {
2462-
!config
2463-
.anchor_channels_config
2464-
.trusted_peers_no_reserve
2465-
.contains(&c.counterparty.node_id)
2466-
&& c.channel_shutdown_state
2467-
.map_or(true, |s| s != ChannelShutdownState::ShutdownComplete)
2468-
&& c.channel_type.as_ref().map_or(false, requires_anchor_channel_type)
2469-
})
2470-
.count() as u64
2471-
* config.anchor_channels_config.per_channel_reserve_sats
2467+
let count = channels_requiring_reserve_count(
2468+
channel_manager,
2469+
chain_monitor,
2470+
&config.anchor_channels_config,
2471+
true,
2472+
true,
2473+
);
2474+
count as u64 * config.anchor_channels_config.per_channel_reserve_sats
2475+
}
2476+
2477+
fn channels_requiring_reserve_count(
2478+
channel_manager: &ChannelManager, chain_monitor: &ChainMonitor,
2479+
anchor_channels_config: &AnchorChannelsConfig, count_keyed_anchor_type: bool,
2480+
count_if_type_not_yet_known: bool,
2481+
) -> usize {
2482+
let mut channels_requiring_reserve = HashSet::new();
2483+
2484+
let feature_test = if count_keyed_anchor_type {
2485+
requires_anchor_channel_type
2486+
} else {
2487+
|features: &ChannelTypeFeatures| features.requires_anchor_zero_fee_commitments()
2488+
};
2489+
2490+
for channel_id in chain_monitor.list_monitors() {
2491+
let monitor = match chain_monitor.get_monitor(channel_id) {
2492+
Ok(monitor) => monitor,
2493+
Err(()) => continue,
2494+
};
2495+
2496+
if monitor_requires_anchor_reserve(monitor, anchor_channels_config, feature_test) {
2497+
channels_requiring_reserve.insert(channel_id);
2498+
}
2499+
}
2500+
2501+
for channel in channel_manager.list_channels() {
2502+
if channel_requires_anchor_reserve(
2503+
&channel,
2504+
anchor_channels_config,
2505+
feature_test,
2506+
count_if_type_not_yet_known,
2507+
) {
2508+
channels_requiring_reserve.insert(channel.channel_id);
2509+
}
2510+
}
2511+
2512+
channels_requiring_reserve.len()
2513+
}
2514+
2515+
fn monitor_requires_anchor_reserve<F: FnOnce(&ChannelTypeFeatures) -> bool>(
2516+
monitor: LockedChannelMonitor<'_, InMemorySigner>,
2517+
anchor_channels_config: &AnchorChannelsConfig, feature_test: F,
2518+
) -> bool {
2519+
if !feature_test(&monitor.channel_type_features()) {
2520+
return false;
2521+
}
2522+
2523+
if monitor.get_claimable_balances().is_empty() {
2524+
return false;
2525+
}
2526+
2527+
let counterparty_node_id = monitor.get_counterparty_node_id();
2528+
if anchor_channels_config.trusted_peers_no_reserve.contains(&counterparty_node_id) {
2529+
return false;
2530+
}
2531+
2532+
return true;
2533+
}
2534+
2535+
fn channel_requires_anchor_reserve<F: FnOnce(&ChannelTypeFeatures) -> bool>(
2536+
channel: &LdkChannelDetails, anchor_channels_config: &AnchorChannelsConfig, feature_test: F,
2537+
count_if_type_not_yet_known: bool,
2538+
) -> bool {
2539+
!anchor_channels_config.trusted_peers_no_reserve.contains(&channel.counterparty.node_id)
2540+
&& channel
2541+
.channel_shutdown_state
2542+
.map_or(true, |s| s != ChannelShutdownState::ShutdownComplete)
2543+
&& channel.channel_type.as_ref().map_or(count_if_type_not_yet_known, feature_test)
24722544
}
24732545

24742546
pub(crate) fn new_channel_anchor_reserve_sats(

src/liquidity/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ use crate::liquidity::client::lsps2::LSPS2Client;
3636
use crate::liquidity::service::lsps2::{LSPS2Service, LSPS2ServiceLiquiditySource};
3737
use crate::logger::{log_debug, log_error, log_info, LdkLogger, Logger};
3838
use crate::runtime::Runtime;
39-
use crate::types::{Broadcaster, ChannelManager, DynStore, KeysManager, LiquidityManager, Wallet};
39+
use crate::types::{
40+
Broadcaster, ChainMonitor, ChannelManager, DynStore, KeysManager, LiquidityManager, Wallet,
41+
};
4042
use crate::{Config, Error};
4143

4244
const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
@@ -203,6 +205,7 @@ where
203205
lsps2_service: Option<LSPS2Service>,
204206
wallet: Arc<Wallet>,
205207
channel_manager: Arc<ChannelManager>,
208+
chain_monitor: Arc<ChainMonitor>,
206209
keys_manager: Arc<KeysManager>,
207210
tx_broadcaster: Arc<Broadcaster>,
208211
kv_store: Arc<DynStore>,
@@ -216,7 +219,8 @@ where
216219
{
217220
pub(crate) fn new(
218221
wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
219-
tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>, config: Arc<Config>, logger: L,
222+
chain_monitor: Arc<ChainMonitor>, tx_broadcaster: Arc<Broadcaster>,
223+
kv_store: Arc<DynStore>, config: Arc<Config>, logger: L,
220224
) -> Self {
221225
let lsp_nodes = Vec::new();
222226
let lsps2_service = None;
@@ -225,6 +229,7 @@ where
225229
lsps2_service,
226230
wallet,
227231
channel_manager,
232+
chain_monitor,
228233
keys_manager,
229234
tx_broadcaster,
230235
kv_store,
@@ -322,6 +327,7 @@ where
322327
lsps2_service: self.lsps2_service,
323328
wallet: self.wallet,
324329
channel_manager: self.channel_manager,
330+
chain_monitor: self.chain_monitor,
325331
peer_manager: RwLock::new(None),
326332
keys_manager: self.keys_manager,
327333
liquidity_manager: Arc::clone(&liquidity_manager),

src/liquidity/service/lsps2.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceCo
2323
use lightning_types::payment::PaymentHash;
2424

2525
use crate::logger::{log_error, LdkLogger};
26-
use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet};
26+
use crate::types::{
27+
ChainMonitor, ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet,
28+
};
2729
use crate::{total_anchor_channels_reserve_sats, Config};
2830

2931
const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
@@ -41,6 +43,7 @@ where
4143
pub(crate) lsps2_service: Option<LSPS2Service>,
4244
pub(crate) wallet: Arc<Wallet>,
4345
pub(crate) channel_manager: Arc<ChannelManager>,
46+
pub(crate) chain_monitor: Arc<ChainMonitor>,
4447
pub(crate) peer_manager: RwLock<Option<Weak<PeerManager>>>,
4548
pub(crate) keys_manager: Arc<KeysManager>,
4649
pub(crate) liquidity_manager: Arc<LiquidityManager>,
@@ -448,8 +451,11 @@ where
448451
* service_config.channel_over_provisioning_ppm as u64)
449452
/ 1_000_000;
450453
let channel_amount_sats = (amt_to_forward_msat + over_provisioning_msat) / 1000;
451-
let cur_anchor_reserve_sats =
452-
total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
454+
let cur_anchor_reserve_sats = total_anchor_channels_reserve_sats(
455+
&self.channel_manager,
456+
&self.chain_monitor,
457+
&self.config,
458+
);
453459
let spendable_amount_sats =
454460
self.wallet.get_spendable_amount_sats(cur_anchor_reserve_sats).unwrap_or(0);
455461
let anchor_channel =

0 commit comments

Comments
 (0)