Skip to content

Commit 33c47e1

Browse files
author
Antoine Riard
committed
Cancel the outbound feerate update if above what we can afford
1 parent 858edb0 commit 33c47e1

File tree

2 files changed

+106
-11
lines changed

2 files changed

+106
-11
lines changed

lightning/src/ln/channel.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub struct ChannelValueStat {
6161
pub counterparty_dust_limit_msat: u64,
6262
}
6363

64-
#[derive(Clone, Copy, PartialEq)]
64+
#[derive(Debug, Clone, Copy, PartialEq)]
6565
enum FeeUpdateState {
6666
// Inbound states mirroring InboundHTLCState
6767
RemoteAnnounced,
@@ -2456,6 +2456,13 @@ impl<Signer: Sign> Channel<Signer> {
24562456
}
24572457
}
24582458
}
2459+
if update_fee {
2460+
let total_fee = Channel::<Signer>::commit_tx_fee_sat(feerate_per_kw, num_htlcs + /* HTLC feerate buffer */ 2);
2461+
let counterparty_reserve_we_require = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
2462+
if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
2463+
return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee with feerate buffer".to_owned())));
2464+
}
2465+
}
24592466
}
24602467

24612468
if msg.htlc_signatures.len() != num_htlcs {
@@ -2958,7 +2965,7 @@ impl<Signer: Sign> Channel<Signer> {
29582965
/// Adds a pending update to this channel. See the doc for send_htlc for
29592966
/// further details on the optionness of the return value.
29602967
/// You MUST call send_commitment prior to any other calls on this Channel
2961-
fn send_update_fee(&mut self, feerate_per_kw: u32) -> Option<msgs::UpdateFee> {
2968+
fn send_update_fee<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) -> Option<msgs::UpdateFee> where L::Target: Logger {
29622969
if !self.is_outbound() {
29632970
panic!("Cannot send fee from inbound channel");
29642971
}
@@ -2969,6 +2976,26 @@ impl<Signer: Sign> Channel<Signer> {
29692976
panic!("Cannot update fee while peer is disconnected/we're awaiting a monitor update (ChannelManager should have caught this)");
29702977
}
29712978

2979+
// Before proposing a feerate update, check that we can actually afford the new fee.
2980+
let inbound_stats = self.get_inbound_pending_htlc_stats();
2981+
let outbound_stats = self.get_outbound_pending_htlc_stats();
2982+
// In case of a concurrent update_add_htlc proposed by our counterparty, we might
2983+
// not have enough balance value remaining to cover the onchain cost of this new
2984+
// HTLC weight. If this happens, our counterparty fails the reception of our
2985+
// commitment_signed including this new HTLC due to infringement on the channel
2986+
// reserve.
2987+
// To prevent this case, we compute our outbound update_fee with a HTLC buffer of
2988+
// size 2. However, if the number of concurrent update_add_htlc is higher, this still
2989+
// leads to a channel force-close. Ultimately, this is an issue coming from the
2990+
// design of LN state machines, allowing asynchronous updates.
2991+
let total_fee = Channel::<Signer>::commit_tx_fee_sat(feerate_per_kw, (inbound_stats.pending_htlcs + /* HTLC feerate buffer */ 2 + outbound_stats.pending_htlcs) as usize);
2992+
let holder_balance_after_fee_sub = (self.value_to_self_msat / 1000).checked_sub(total_fee).map(|a| a.checked_sub(outbound_stats.pending_htlcs_value_msat / 1000)).unwrap_or(None).unwrap_or(u64::max_value());
2993+
if holder_balance_after_fee_sub < self.counterparty_selected_channel_reserve_satoshis.unwrap() {
2994+
//TODO: auto-close after a number of failures?
2995+
log_debug!(logger, "Cannot afford to send new feerate at {}", feerate_per_kw);
2996+
return None;
2997+
}
2998+
29722999
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateFailed as u32)) != 0 {
29733000
self.holding_cell_update_fee = Some(feerate_per_kw);
29743001
return None;
@@ -2984,7 +3011,7 @@ impl<Signer: Sign> Channel<Signer> {
29843011
}
29853012

29863013
pub fn send_update_fee_and_commit<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) -> Result<Option<(msgs::UpdateFee, msgs::CommitmentSigned, ChannelMonitorUpdate)>, ChannelError> where L::Target: Logger {
2987-
match self.send_update_fee(feerate_per_kw) {
3014+
match self.send_update_fee(feerate_per_kw, logger) {
29883015
Some(update_fee) => {
29893016
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
29903017
Ok(Some((update_fee, commitment_signed, monitor_update)))
@@ -4728,6 +4755,19 @@ impl<Signer: Sign> Channel<Signer> {
47284755
}
47294756
}
47304757

4758+
if self.is_outbound() {
4759+
// Log if we can't afford next remote commitment tx fee at pending outbound feerate update.
4760+
if let Some(pending_feerate) = self.pending_update_fee {
4761+
assert_eq!(pending_feerate.1, FeeUpdateState::Outbound);
4762+
let next_total_fee = Channel::<Signer>::commit_tx_fee_sat(pending_feerate.0, self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len());
4763+
let outbound_stats = self.get_outbound_pending_htlc_stats();
4764+
let holder_balance_after_fee_sub_sats = (self.value_to_self_msat / 1000).checked_sub(next_total_fee).map(|a| a.checked_sub(outbound_stats.pending_htlcs_value_msat / 1000)).unwrap_or(None).unwrap_or(u64::max_value());
4765+
if holder_balance_after_fee_sub_sats < self.counterparty_selected_channel_reserve_satoshis.unwrap() {
4766+
log_trace!(logger, "Outbound update_fee HTLC buffer overflow - counterparty should force-close this channel");
4767+
}
4768+
}
4769+
}
4770+
47314771
{
47324772
let mut htlcs = Vec::with_capacity(counterparty_commitment_tx.3.len());
47334773
for &(ref htlc, _) in counterparty_commitment_tx.3.iter() {

lightning/src/ln/functional_tests.rs

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
2222
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, PaymentId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA};
2323
use ln::channel::{Channel, ChannelError};
2424
use ln::{chan_utils, onion_utils};
25-
use ln::chan_utils::HTLC_SUCCESS_TX_WEIGHT;
25+
use ln::chan_utils::{HTLC_SUCCESS_TX_WEIGHT, HTLCOutputInCommitment};
2626
use routing::network_graph::{NetworkUpdate, RoutingFees};
2727
use routing::router::{Route, RouteHop, RouteHint, RouteHintHop, get_route, get_keysend_route};
2828
use routing::scorer::Scorer;
@@ -585,9 +585,10 @@ fn test_update_fee_that_funder_cannot_afford() {
585585
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
586586
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
587587
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
588-
let channel_value = 1888;
588+
let channel_value = 1977;
589589
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_value, 700000, InitFeatures::known(), InitFeatures::known());
590590
let channel_id = chan.2;
591+
let secp_ctx = Secp256k1::new();
591592

592593
let feerate = 260;
593594
{
@@ -622,20 +623,74 @@ fn test_update_fee_that_funder_cannot_afford() {
622623
*feerate_lock = feerate + 2;
623624
}
624625
nodes[0].node.timer_tick_occurred();
625-
check_added_monitors!(nodes[0], 1);
626+
nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Cannot afford to send new feerate at {}", feerate + 2), 1);
627+
check_added_monitors!(nodes[0], 0);
626628

627-
let update2_msg = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
629+
const INITIAL_COMMITMENT_NUMBER: u64 = 281474976710654;
628630

629-
nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), &update2_msg.update_fee.unwrap());
631+
// Get the EnforcingSigner for each channel, which will be used to (1) get the keys
632+
// needed to sign the new commitment tx and (2) sign the new commitment tx.
633+
let (local_revocation_basepoint, local_htlc_basepoint, local_funding) = {
634+
let chan_lock = nodes[0].node.channel_state.lock().unwrap();
635+
let local_chan = chan_lock.by_id.get(&chan.2).unwrap();
636+
let chan_signer = local_chan.get_signer();
637+
let pubkeys = chan_signer.pubkeys();
638+
(pubkeys.revocation_basepoint, pubkeys.htlc_basepoint,
639+
pubkeys.funding_pubkey)
640+
};
641+
let (remote_delayed_payment_basepoint, remote_htlc_basepoint,remote_point, remote_funding) = {
642+
let chan_lock = nodes[1].node.channel_state.lock().unwrap();
643+
let remote_chan = chan_lock.by_id.get(&chan.2).unwrap();
644+
let chan_signer = remote_chan.get_signer();
645+
let pubkeys = chan_signer.pubkeys();
646+
(pubkeys.delayed_payment_basepoint, pubkeys.htlc_basepoint,
647+
chan_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &secp_ctx),
648+
pubkeys.funding_pubkey)
649+
};
650+
651+
// Assemble the set of keys we can use for signatures for our commitment_signed message.
652+
let commit_tx_keys = chan_utils::TxCreationKeys::derive_new(&secp_ctx, &remote_point, &remote_delayed_payment_basepoint,
653+
&remote_htlc_basepoint, &local_revocation_basepoint, &local_htlc_basepoint).unwrap();
654+
655+
let res = {
656+
let local_chan_lock = nodes[0].node.channel_state.lock().unwrap();
657+
let local_chan = local_chan_lock.by_id.get(&chan.2).unwrap();
658+
let local_chan_signer = local_chan.get_signer();
659+
let mut htlcs: Vec<(HTLCOutputInCommitment, ())> = vec![];
660+
let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
661+
INITIAL_COMMITMENT_NUMBER - 1,
662+
700,
663+
1088,
664+
false, local_funding, remote_funding,
665+
commit_tx_keys.clone(),
666+
feerate + 2,
667+
&mut htlcs,
668+
&local_chan.channel_transaction_parameters.as_counterparty_broadcastable()
669+
);
670+
local_chan_signer.sign_counterparty_commitment(&commitment_tx, &secp_ctx).unwrap()
671+
};
672+
673+
let commit_signed_msg = msgs::CommitmentSigned {
674+
channel_id: chan.2,
675+
signature: res.0,
676+
htlc_signatures: res.1
677+
};
678+
679+
let update_fee = msgs::UpdateFee {
680+
channel_id: chan.2,
681+
feerate_per_kw: feerate + 2,
682+
};
683+
684+
nodes[1].node.handle_update_fee(&nodes[0].node.get_our_node_id(), &update_fee);
630685

631686
//While producing the commitment_signed response after handling a received update_fee request the
632687
//check to see if the funder, who sent the update_fee request, can afford the new fee (funder_balance >= fee+channel_reserve)
633688
//Should produce and error.
634-
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &update2_msg.commitment_signed);
635-
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Funding remote cannot afford proposed new fee".to_string(), 1);
689+
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &commit_signed_msg);
690+
nodes[1].logger.assert_log("lightning::ln::channelmanager".to_string(), "Funding remote cannot afford proposed new fee with feerate buffer".to_string(), 1);
636691
check_added_monitors!(nodes[1], 1);
637692
check_closed_broadcast!(nodes[1], true);
638-
check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: String::from("Funding remote cannot afford proposed new fee") });
693+
check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: String::from("Funding remote cannot afford proposed new fee with feerate buffer") });
639694
}
640695

641696
#[test]

0 commit comments

Comments
 (0)