Skip to content

Commit d9d4611

Browse files
authored
Merge pull request #1863 from TheBlueMatt/2022-11-holding-cell-batch-update
Lean on the holding cell when batch-forwarding/failing HTLCs
2 parents eea56e9 + 1833070 commit d9d4611

File tree

2 files changed

+134
-233
lines changed

2 files changed

+134
-233
lines changed

lightning/src/ln/channel.rs

+85-68
Original file line numberDiff line numberDiff line change
@@ -1955,9 +1955,26 @@ impl<Signer: Sign> Channel<Signer> {
19551955
/// an HTLC more than once or fulfill once and then attempt to fail after reconnect. We cannot,
19561956
/// however, fail more than once as we wait for an upstream failure to be irrevocably committed
19571957
/// before we fail backwards.
1958-
/// If we do fail twice, we debug_assert!(false) and return Ok(None). Thus, will always return
1959-
/// Ok(_) if debug assertions are turned on or preconditions are met.
1960-
pub fn get_update_fail_htlc<L: Deref>(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket, logger: &L) -> Result<Option<msgs::UpdateFailHTLC>, ChannelError> where L::Target: Logger {
1958+
///
1959+
/// If we do fail twice, we `debug_assert!(false)` and return `Ok(None)`. Thus, this will always
1960+
/// return `Ok(_)` if preconditions are met. In any case, `Err`s will only be
1961+
/// [`ChannelError::Ignore`].
1962+
pub fn queue_fail_htlc<L: Deref>(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket, logger: &L)
1963+
-> Result<(), ChannelError> where L::Target: Logger {
1964+
self.fail_htlc(htlc_id_arg, err_packet, true, logger)
1965+
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
1966+
}
1967+
1968+
/// We can only have one resolution per HTLC. In some cases around reconnect, we may fulfill
1969+
/// an HTLC more than once or fulfill once and then attempt to fail after reconnect. We cannot,
1970+
/// however, fail more than once as we wait for an upstream failure to be irrevocably committed
1971+
/// before we fail backwards.
1972+
///
1973+
/// If we do fail twice, we `debug_assert!(false)` and return `Ok(None)`. Thus, this will always
1974+
/// return `Ok(_)` if preconditions are met. In any case, `Err`s will only be
1975+
/// [`ChannelError::Ignore`].
1976+
fn fail_htlc<L: Deref>(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket, mut force_holding_cell: bool, logger: &L)
1977+
-> Result<Option<msgs::UpdateFailHTLC>, ChannelError> where L::Target: Logger {
19611978
if (self.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) {
19621979
panic!("Was asked to fail an HTLC when channel was not in an operational state");
19631980
}
@@ -1995,8 +2012,13 @@ impl<Signer: Sign> Channel<Signer> {
19952012
return Ok(None);
19962013
}
19972014

1998-
// Now update local state:
19992015
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32)) != 0 {
2016+
debug_assert!(force_holding_cell, "!force_holding_cell is only called when emptying the holding cell, so we shouldn't end up back in it!");
2017+
force_holding_cell = true;
2018+
}
2019+
2020+
// Now update local state:
2021+
if force_holding_cell {
20002022
for pending_update in self.holding_cell_htlc_updates.iter() {
20012023
match pending_update {
20022024
&HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
@@ -3171,8 +3193,8 @@ impl<Signer: Sign> Channel<Signer> {
31713193
} else { Ok((None, Vec::new())) }
31723194
}
31733195

3174-
/// Used to fulfill holding_cell_htlcs when we get a remote ack (or implicitly get it by them
3175-
/// fulfilling or failing the last pending HTLC)
3196+
/// Frees any pending commitment updates in the holding cell, generating the relevant messages
3197+
/// for our counterparty.
31763198
fn free_holding_cell_htlcs<L: Deref>(&mut self, logger: &L) -> Result<(Option<(msgs::CommitmentUpdate, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash)>), ChannelError> where L::Target: Logger {
31773199
assert_eq!(self.channel_state & ChannelState::MonitorUpdateInProgress as u32, 0);
31783200
if self.holding_cell_htlc_updates.len() != 0 || self.holding_cell_update_fee.is_some() {
@@ -3198,7 +3220,7 @@ impl<Signer: Sign> Channel<Signer> {
31983220
// to rebalance channels.
31993221
match &htlc_update {
32003222
&HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet, ..} => {
3201-
match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone(), logger) {
3223+
match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone(), false, logger) {
32023224
Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()),
32033225
Err(e) => {
32043226
match e {
@@ -3234,13 +3256,13 @@ impl<Signer: Sign> Channel<Signer> {
32343256
monitor_update.updates.append(&mut additional_monitor_update.updates);
32353257
},
32363258
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, ref err_packet } => {
3237-
match self.get_update_fail_htlc(htlc_id, err_packet.clone(), logger) {
3259+
match self.fail_htlc(htlc_id, err_packet.clone(), false, logger) {
32383260
Ok(update_fail_msg_option) => {
32393261
// If an HTLC failure was previously added to the holding cell (via
3240-
// `get_update_fail_htlc`) then generating the fail message itself
3241-
// must not fail - we should never end up in a state where we
3242-
// double-fail an HTLC or fail-then-claim an HTLC as it indicates
3243-
// we didn't wait for a full revocation before failing.
3262+
// `queue_fail_htlc`) then generating the fail message itself must
3263+
// not fail - we should never end up in a state where we double-fail
3264+
// an HTLC or fail-then-claim an HTLC as it indicates we didn't wait
3265+
// for a full revocation before failing.
32443266
update_fail_htlcs.push(update_fail_msg_option.unwrap())
32453267
},
32463268
Err(e) => {
@@ -3257,7 +3279,7 @@ impl<Signer: Sign> Channel<Signer> {
32573279
return Ok((None, htlcs_to_fail));
32583280
}
32593281
let update_fee = if let Some(feerate) = self.holding_cell_update_fee.take() {
3260-
self.send_update_fee(feerate, logger)
3282+
self.send_update_fee(feerate, false, logger)
32613283
} else {
32623284
None
32633285
};
@@ -3557,12 +3579,22 @@ impl<Signer: Sign> Channel<Signer> {
35573579
}
35583580
}
35593581

3582+
/// Queues up an outbound update fee by placing it in the holding cell. You should call
3583+
/// [`Self::maybe_free_holding_cell_htlcs`] in order to actually generate and send the
3584+
/// commitment update.
3585+
pub fn queue_update_fee<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) where L::Target: Logger {
3586+
let msg_opt = self.send_update_fee(feerate_per_kw, true, logger);
3587+
assert!(msg_opt.is_none(), "We forced holding cell?");
3588+
}
3589+
35603590
/// Adds a pending update to this channel. See the doc for send_htlc for
35613591
/// further details on the optionness of the return value.
35623592
/// If our balance is too low to cover the cost of the next commitment transaction at the
35633593
/// new feerate, the update is cancelled.
3564-
/// You MUST call send_commitment prior to any other calls on this Channel
3565-
fn send_update_fee<L: Deref>(&mut self, feerate_per_kw: u32, logger: &L) -> Option<msgs::UpdateFee> where L::Target: Logger {
3594+
///
3595+
/// You MUST call [`Self::send_commitment_no_state_update`] prior to any other calls on this
3596+
/// [`Channel`] if `force_holding_cell` is false.
3597+
fn send_update_fee<L: Deref>(&mut self, feerate_per_kw: u32, mut force_holding_cell: bool, logger: &L) -> Option<msgs::UpdateFee> where L::Target: Logger {
35663598
if !self.is_outbound() {
35673599
panic!("Cannot send fee from inbound channel");
35683600
}
@@ -3599,6 +3631,10 @@ impl<Signer: Sign> Channel<Signer> {
35993631
}
36003632

36013633
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateInProgress as u32)) != 0 {
3634+
force_holding_cell = true;
3635+
}
3636+
3637+
if force_holding_cell {
36023638
self.holding_cell_update_fee = Some(feerate_per_kw);
36033639
return None;
36043640
}
@@ -3612,16 +3648,6 @@ impl<Signer: Sign> Channel<Signer> {
36123648
})
36133649
}
36143650

3615-
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 {
3616-
match self.send_update_fee(feerate_per_kw, logger) {
3617-
Some(update_fee) => {
3618-
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
3619-
Ok(Some((update_fee, commitment_signed, monitor_update)))
3620-
},
3621-
None => Ok(None)
3622-
}
3623-
}
3624-
36253651
/// Removes any uncommitted inbound HTLCs and resets the state of uncommitted outbound HTLC
36263652
/// updates, to be used on peer disconnection. After this, update_*_htlc messages need to be
36273653
/// resent.
@@ -5495,8 +5521,26 @@ impl<Signer: Sign> Channel<Signer> {
54955521

54965522
// Send stuff to our remote peers:
54975523

5524+
/// Queues up an outbound HTLC to send by placing it in the holding cell. You should call
5525+
/// [`Self::maybe_free_holding_cell_htlcs`] in order to actually generate and send the
5526+
/// commitment update.
5527+
///
5528+
/// `Err`s will only be [`ChannelError::Ignore`].
5529+
pub fn queue_add_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
5530+
onion_routing_packet: msgs::OnionPacket, logger: &L)
5531+
-> Result<(), ChannelError> where L::Target: Logger {
5532+
self
5533+
.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, true, logger)
5534+
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
5535+
.map_err(|err| {
5536+
if let ChannelError::Ignore(_) = err { /* fine */ }
5537+
else { debug_assert!(false, "Queueing cannot trigger channel failure"); }
5538+
err
5539+
})
5540+
}
5541+
54985542
/// Adds a pending outbound HTLC to this channel, note that you probably want
5499-
/// send_htlc_and_commit instead cause you'll want both messages at once.
5543+
/// [`Self::send_htlc_and_commit`] instead cause you'll want both messages at once.
55005544
///
55015545
/// This returns an optional UpdateAddHTLC as we may be in a state where we cannot add HTLCs on
55025546
/// the wire:
@@ -5507,10 +5551,13 @@ impl<Signer: Sign> Channel<Signer> {
55075551
/// we may not yet have sent the previous commitment update messages and will need to
55085552
/// regenerate them.
55095553
///
5510-
/// You MUST call send_commitment prior to calling any other methods on this Channel!
5554+
/// You MUST call [`Self::send_commitment_no_state_update`] prior to calling any other methods
5555+
/// on this [`Channel`] if `force_holding_cell` is false.
55115556
///
5512-
/// If an Err is returned, it's a ChannelError::Ignore!
5513-
pub fn send_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<msgs::UpdateAddHTLC>, ChannelError> where L::Target: Logger {
5557+
/// `Err`s will only be [`ChannelError::Ignore`].
5558+
fn send_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
5559+
onion_routing_packet: msgs::OnionPacket, mut force_holding_cell: bool, logger: &L)
5560+
-> Result<Option<msgs::UpdateAddHTLC>, ChannelError> where L::Target: Logger {
55145561
if (self.channel_state & (ChannelState::ChannelReady as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelReady as u32) {
55155562
return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned()));
55165563
}
@@ -5605,8 +5652,12 @@ impl<Signer: Sign> Channel<Signer> {
56055652
return Err(ChannelError::Ignore(format!("Cannot send value that would put our balance under counterparty-announced channel reserve value ({})", chan_reserve_msat)));
56065653
}
56075654

5608-
// Now update local state:
56095655
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateInProgress as u32)) != 0 {
5656+
force_holding_cell = true;
5657+
}
5658+
5659+
// Now update local state:
5660+
if force_holding_cell {
56105661
self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::AddHTLC {
56115662
amount_msat,
56125663
payment_hash,
@@ -5639,41 +5690,6 @@ impl<Signer: Sign> Channel<Signer> {
56395690
Ok(Some(res))
56405691
}
56415692

5642-
/// Creates a signed commitment transaction to send to the remote peer.
5643-
/// Always returns a ChannelError::Close if an immediately-preceding (read: the
5644-
/// last call to this Channel) send_htlc returned Ok(Some(_)) and there is an Err.
5645-
/// May panic if called except immediately after a successful, Ok(Some(_))-returning send_htlc.
5646-
pub fn send_commitment<L: Deref>(&mut self, logger: &L) -> Result<(msgs::CommitmentSigned, ChannelMonitorUpdate), ChannelError> where L::Target: Logger {
5647-
if (self.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) {
5648-
panic!("Cannot create commitment tx until channel is fully established");
5649-
}
5650-
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
5651-
panic!("Cannot create commitment tx until remote revokes their previous commitment");
5652-
}
5653-
if (self.channel_state & (ChannelState::PeerDisconnected as u32)) == (ChannelState::PeerDisconnected as u32) {
5654-
panic!("Cannot create commitment tx while disconnected, as send_htlc will have returned an Err so a send_commitment precondition has been violated");
5655-
}
5656-
if (self.channel_state & (ChannelState::MonitorUpdateInProgress as u32)) == (ChannelState::MonitorUpdateInProgress as u32) {
5657-
panic!("Cannot create commitment tx while awaiting monitor update unfreeze, as send_htlc will have returned an Err so a send_commitment precondition has been violated");
5658-
}
5659-
let mut have_updates = self.is_outbound() && self.pending_update_fee.is_some();
5660-
for htlc in self.pending_outbound_htlcs.iter() {
5661-
if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
5662-
have_updates = true;
5663-
}
5664-
if have_updates { break; }
5665-
}
5666-
for htlc in self.pending_inbound_htlcs.iter() {
5667-
if let InboundHTLCState::LocalRemoved(_) = htlc.state {
5668-
have_updates = true;
5669-
}
5670-
if have_updates { break; }
5671-
}
5672-
if !have_updates {
5673-
panic!("Cannot create commitment tx until we have some updates to send");
5674-
}
5675-
self.send_commitment_no_status_check(logger)
5676-
}
56775693
/// Only fails in case of bad keys
56785694
fn send_commitment_no_status_check<L: Deref>(&mut self, logger: &L) -> Result<(msgs::CommitmentSigned, ChannelMonitorUpdate), ChannelError> where L::Target: Logger {
56795695
log_trace!(logger, "Updating HTLC state for a newly-sent commitment_signed...");
@@ -5796,10 +5812,11 @@ impl<Signer: Sign> Channel<Signer> {
57965812

57975813
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
57985814
/// to send to the remote peer in one go.
5799-
/// Shorthand for calling send_htlc() followed by send_commitment(), see docs on those for
5800-
/// more info.
5815+
///
5816+
/// Shorthand for calling [`Self::send_htlc`] followed by a commitment update, see docs on
5817+
/// [`Self::send_htlc`] and [`Self::send_commitment_no_state_update`] for more info.
58015818
pub fn send_htlc_and_commit<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<(msgs::UpdateAddHTLC, msgs::CommitmentSigned, ChannelMonitorUpdate)>, ChannelError> where L::Target: Logger {
5802-
match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, logger)? {
5819+
match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger)? {
58035820
Some(update_add_htlc) => {
58045821
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?;
58055822
Ok(Some((update_add_htlc, commitment_signed, monitor_update)))

0 commit comments

Comments
 (0)