Skip to content

Commit 4cc8687

Browse files
committed
Track incoming UpdateAddHTLC until HTLC resolution
This commit serves as a stepping stone to moving towards resolving HTLCs once the HTLC has been fully committed to by both sides. Currently, we decode HTLC onions immediately upon receiving an `update_add_htlc`. Doing so determines what we should do with the HTLC: forward it, or immediately fail it back if it cannot be accepted. This action is tracked until the HTLC is fully committed to by both sides, and a new commitment in the latter case is proposed to fully remove the HTLC. While this has worked so far, it has some minor privacy implications, as forwarding/failing back do not go through the usual `PendingHTLCsForwardable` flow. It also presents issues with the quiescence handshake, as failures through this path do not go through the holding cell abstraction, leading to a potential violation of the handshake by sending an `update_fail_*` after already having sent `stfu`. Since `pending_inbound_htlcs` are written pre-TLVs, we introduce a new serialization version in which we change the `PendingHTLCStatus` serialization of `InboundHTLC::AwaitingRemoteRevokeToRemove/AwaitingRemovedRemoteRevoke` to be an option instead. We'll still write it as the current version (`MIN_SERIALIZATION_VERSION`), but we'll support reading the new version to allow users to downgrade back to this commit.
1 parent 2740f58 commit 4cc8687

File tree

2 files changed

+127
-34
lines changed

2 files changed

+127
-34
lines changed

lightning/src/ln/channel.rs

Lines changed: 125 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,35 @@ enum InboundHTLCRemovalReason {
104104
Fulfill(PaymentPreimage),
105105
}
106106

107+
/// Represents the resolution status of an inbound HTLC.
108+
#[derive(Clone)]
109+
enum InboundHTLCResolution {
110+
/// Resolved implies the action we must take with the inbound HTLC has already been determined,
111+
/// i.e., we already know whether it must be failed back or forwarded.
112+
Resolved {
113+
pending_htlc_status: PendingHTLCStatus,
114+
},
115+
/// Pending implies we will attempt to resolve the inbound HTLC once it has been fully committed
116+
/// to by both sides of the channel, i.e., once a `revoke_and_ack` has been processed by both
117+
/// nodes for the state update in which it was proposed.
118+
Pending {
119+
update_add_htlc: msgs::UpdateAddHTLC,
120+
},
121+
}
122+
123+
impl_writeable_tlv_based_enum!(InboundHTLCResolution,
124+
(0, Resolved) => {
125+
(0, pending_htlc_status, required),
126+
},
127+
(2, Pending) => {
128+
(0, update_add_htlc, required),
129+
};
130+
);
131+
107132
enum InboundHTLCState {
108133
/// Offered by remote, to be included in next local commitment tx. I.e., the remote sent an
109134
/// update_add_htlc message for this HTLC.
110-
RemoteAnnounced(PendingHTLCStatus),
135+
RemoteAnnounced(InboundHTLCResolution),
111136
/// Included in a received commitment_signed message (implying we've
112137
/// revoke_and_ack'd it), but the remote hasn't yet revoked their previous
113138
/// state (see the example below). We have not yet included this HTLC in a
@@ -137,13 +162,13 @@ enum InboundHTLCState {
137162
/// Implies AwaitingRemoteRevoke.
138163
///
139164
/// [BOLT #2]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
140-
AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus),
165+
AwaitingRemoteRevokeToAnnounce(InboundHTLCResolution),
141166
/// Included in a received commitment_signed message (implying we've revoke_and_ack'd it).
142167
/// We have also included this HTLC in our latest commitment_signed and are now just waiting
143168
/// on the remote's revoke_and_ack to make this HTLC an irrevocable part of the state of the
144169
/// channel (before it can then get forwarded and/or removed).
145170
/// Implies AwaitingRemoteRevoke.
146-
AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus),
171+
AwaitingAnnouncedRemoteRevoke(InboundHTLCResolution),
147172
Committed,
148173
/// Removed by us and a new commitment_signed was sent (if we were AwaitingRemoteRevoke when we
149174
/// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -1291,6 +1316,7 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
12911316
monitor_pending_forwards: Vec<(PendingHTLCInfo, u64)>,
12921317
monitor_pending_failures: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
12931318
monitor_pending_finalized_fulfills: Vec<HTLCSource>,
1319+
monitor_pending_update_adds: Vec<msgs::UpdateAddHTLC>,
12941320

12951321
/// If we went to send a commitment update (ie some messages then [`msgs::CommitmentSigned`])
12961322
/// but our signer (initially) refused to give us a signature, we should retry at some point in
@@ -1755,6 +1781,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
17551781
monitor_pending_forwards: Vec::new(),
17561782
monitor_pending_failures: Vec::new(),
17571783
monitor_pending_finalized_fulfills: Vec::new(),
1784+
monitor_pending_update_adds: Vec::new(),
17581785

17591786
signer_pending_commitment_update: false,
17601787
signer_pending_funding: false,
@@ -1976,6 +2003,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
19762003
monitor_pending_forwards: Vec::new(),
19772004
monitor_pending_failures: Vec::new(),
19782005
monitor_pending_finalized_fulfills: Vec::new(),
2006+
monitor_pending_update_adds: Vec::new(),
19792007

19802008
signer_pending_commitment_update: false,
19812009
signer_pending_funding: false,
@@ -4255,7 +4283,9 @@ impl<SP: Deref> Channel<SP> where
42554283
amount_msat: msg.amount_msat,
42564284
payment_hash: msg.payment_hash,
42574285
cltv_expiry: msg.cltv_expiry,
4258-
state: InboundHTLCState::RemoteAnnounced(pending_forward_status),
4286+
state: InboundHTLCState::RemoteAnnounced(InboundHTLCResolution::Resolved {
4287+
pending_htlc_status: pending_forward_status
4288+
}),
42594289
});
42604290
Ok(())
42614291
}
@@ -4461,13 +4491,13 @@ impl<SP: Deref> Channel<SP> where
44614491
}
44624492

44634493
for htlc in self.context.pending_inbound_htlcs.iter_mut() {
4464-
let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
4465-
Some(forward_info.clone())
4494+
let htlc_resolution = if let &InboundHTLCState::RemoteAnnounced(ref resolution) = &htlc.state {
4495+
Some(resolution.clone())
44664496
} else { None };
4467-
if let Some(forward_info) = new_forward {
4497+
if let Some(htlc_resolution) = htlc_resolution {
44684498
log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToAnnounce due to commitment_signed in channel {}.",
44694499
&htlc.payment_hash, &self.context.channel_id);
4470-
htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info);
4500+
htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce(htlc_resolution);
44714501
need_commitment = true;
44724502
}
44734503
}
@@ -4777,6 +4807,7 @@ impl<SP: Deref> Channel<SP> where
47774807

47784808
log_trace!(logger, "Updating HTLCs on receipt of RAA in channel {}...", &self.context.channel_id());
47794809
let mut to_forward_infos = Vec::new();
4810+
let mut pending_update_adds = Vec::new();
47804811
let mut revoked_htlcs = Vec::new();
47814812
let mut finalized_claimed_htlcs = Vec::new();
47824813
let mut update_fail_htlcs = Vec::new();
@@ -4824,29 +4855,37 @@ impl<SP: Deref> Channel<SP> where
48244855
let mut state = InboundHTLCState::Committed;
48254856
mem::swap(&mut state, &mut htlc.state);
48264857

4827-
if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state {
4858+
if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(resolution) = state {
48284859
log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce {} to AwaitingAnnouncedRemoteRevoke", &htlc.payment_hash);
4829-
htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info);
4860+
htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution);
48304861
require_commitment = true;
4831-
} else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state {
4832-
match forward_info {
4833-
PendingHTLCStatus::Fail(fail_msg) => {
4834-
log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to LocalRemoved due to PendingHTLCStatus indicating failure", &htlc.payment_hash);
4835-
require_commitment = true;
4836-
match fail_msg {
4837-
HTLCFailureMsg::Relay(msg) => {
4838-
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
4839-
update_fail_htlcs.push(msg)
4840-
},
4841-
HTLCFailureMsg::Malformed(msg) => {
4842-
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
4843-
update_fail_malformed_htlcs.push(msg)
4862+
} else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution) = state {
4863+
match resolution {
4864+
InboundHTLCResolution::Resolved { pending_htlc_status } =>
4865+
match pending_htlc_status {
4866+
PendingHTLCStatus::Fail(fail_msg) => {
4867+
log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to LocalRemoved due to PendingHTLCStatus indicating failure", &htlc.payment_hash);
4868+
require_commitment = true;
4869+
match fail_msg {
4870+
HTLCFailureMsg::Relay(msg) => {
4871+
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
4872+
update_fail_htlcs.push(msg)
4873+
},
4874+
HTLCFailureMsg::Malformed(msg) => {
4875+
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
4876+
update_fail_malformed_htlcs.push(msg)
4877+
},
4878+
}
48444879
},
4880+
PendingHTLCStatus::Forward(forward_info) => {
4881+
log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed, attempting to forward", &htlc.payment_hash);
4882+
to_forward_infos.push((forward_info, htlc.htlc_id));
4883+
htlc.state = InboundHTLCState::Committed;
4884+
}
48454885
}
4846-
},
4847-
PendingHTLCStatus::Forward(forward_info) => {
4886+
InboundHTLCResolution::Pending { update_add_htlc } => {
48484887
log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", &htlc.payment_hash);
4849-
to_forward_infos.push((forward_info, htlc.htlc_id));
4888+
pending_update_adds.push(update_add_htlc);
48504889
htlc.state = InboundHTLCState::Committed;
48514890
}
48524891
}
@@ -4907,6 +4946,8 @@ impl<SP: Deref> Channel<SP> where
49074946
}
49084947
}
49094948

4949+
self.context.monitor_pending_update_adds.append(&mut pending_update_adds);
4950+
49104951
if self.context.channel_state.is_monitor_update_in_progress() {
49114952
// We can't actually generate a new commitment transaction (incl by freeing holding
49124953
// cells) while we can't update the monitor, so we just return what we have.
@@ -8232,7 +8273,7 @@ fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures)
82328273
ret
82338274
}
82348275

8235-
const SERIALIZATION_VERSION: u8 = 3;
8276+
const SERIALIZATION_VERSION: u8 = 4;
82368277
const MIN_SERIALIZATION_VERSION: u8 = 3;
82378278

82388279
impl_writeable_tlv_based_enum!(InboundHTLCRemovalReason,;
@@ -8294,7 +8335,18 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
82948335
// Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
82958336
// called.
82968337

8297-
write_ver_prefix!(writer, MIN_SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
8338+
let version_to_write = if self.context.pending_inbound_htlcs.iter().any(|htlc| match htlc.state {
8339+
InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_resolution)|
8340+
InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_resolution) => {
8341+
matches!(htlc_resolution, InboundHTLCResolution::Pending { .. })
8342+
},
8343+
_ => false,
8344+
}) {
8345+
SERIALIZATION_VERSION
8346+
} else {
8347+
MIN_SERIALIZATION_VERSION
8348+
};
8349+
write_ver_prefix!(writer, version_to_write, MIN_SERIALIZATION_VERSION);
82988350

82998351
// `user_id` used to be a single u64 value. In order to remain backwards compatible with
83008352
// versions prior to 0.0.113, the u128 is serialized as two separate u64 values. We write
@@ -8350,13 +8402,29 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
83508402
htlc.payment_hash.write(writer)?;
83518403
match &htlc.state {
83528404
&InboundHTLCState::RemoteAnnounced(_) => unreachable!(),
8353-
&InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_state) => {
8405+
&InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_resolution) => {
83548406
1u8.write(writer)?;
8355-
htlc_state.write(writer)?;
8407+
if version_to_write <= 3 {
8408+
if let InboundHTLCResolution::Resolved { pending_htlc_status } = htlc_resolution {
8409+
pending_htlc_status.write(writer)?;
8410+
} else {
8411+
panic!();
8412+
}
8413+
} else {
8414+
htlc_resolution.write(writer)?;
8415+
}
83568416
},
8357-
&InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_state) => {
8417+
&InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_resolution) => {
83588418
2u8.write(writer)?;
8359-
htlc_state.write(writer)?;
8419+
if version_to_write <= 3 {
8420+
if let InboundHTLCResolution::Resolved { pending_htlc_status } = htlc_resolution {
8421+
pending_htlc_status.write(writer)?;
8422+
} else {
8423+
panic!();
8424+
}
8425+
} else {
8426+
htlc_resolution.write(writer)?;
8427+
}
83608428
},
83618429
&InboundHTLCState::Committed => {
83628430
3u8.write(writer)?;
@@ -8582,6 +8650,11 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
85828650

85838651
let holder_max_accepted_htlcs = if self.context.holder_max_accepted_htlcs == DEFAULT_MAX_HTLCS { None } else { Some(self.context.holder_max_accepted_htlcs) };
85848652

8653+
let mut monitor_pending_update_adds = None;
8654+
if !self.context.monitor_pending_update_adds.is_empty() {
8655+
monitor_pending_update_adds = Some(&self.context.monitor_pending_update_adds);
8656+
}
8657+
85858658
write_tlv_fields!(writer, {
85868659
(0, self.context.announcement_sigs, option),
85878660
// minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
@@ -8599,6 +8672,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
85998672
(7, self.context.shutdown_scriptpubkey, option),
86008673
(8, self.context.blocked_monitor_updates, optional_vec),
86018674
(9, self.context.target_closing_feerate_sats_per_kw, option),
8675+
(10, monitor_pending_update_adds, option), // Added in 0.0.122
86028676
(11, self.context.monitor_pending_finalized_fulfills, required_vec),
86038677
(13, self.context.channel_creation_height, required),
86048678
(15, preimages, required_vec),
@@ -8693,8 +8767,22 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
86938767
cltv_expiry: Readable::read(reader)?,
86948768
payment_hash: Readable::read(reader)?,
86958769
state: match <u8 as Readable>::read(reader)? {
8696-
1 => InboundHTLCState::AwaitingRemoteRevokeToAnnounce(Readable::read(reader)?),
8697-
2 => InboundHTLCState::AwaitingAnnouncedRemoteRevoke(Readable::read(reader)?),
8770+
1 => {
8771+
let resolution = if ver <= 3 {
8772+
InboundHTLCResolution::Resolved { pending_htlc_status: Readable::read(reader)? }
8773+
} else {
8774+
Readable::read(reader)?
8775+
};
8776+
InboundHTLCState::AwaitingRemoteRevokeToAnnounce(resolution)
8777+
},
8778+
2 => {
8779+
let resolution = if ver <= 3 {
8780+
InboundHTLCResolution::Resolved { pending_htlc_status: Readable::read(reader)? }
8781+
} else {
8782+
Readable::read(reader)?
8783+
};
8784+
InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution)
8785+
},
86988786
3 => InboundHTLCState::Committed,
86998787
4 => InboundHTLCState::LocalRemoved(Readable::read(reader)?),
87008788
_ => return Err(DecodeError::InvalidValue),
@@ -8911,6 +8999,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
89118999
let mut holding_cell_blinding_points_opt: Option<Vec<Option<PublicKey>>> = None;
89129000

89139001
let mut malformed_htlcs: Option<Vec<(u64, u16, [u8; 32])>> = None;
9002+
let mut monitor_pending_update_adds: Option<Vec<msgs::UpdateAddHTLC>> = None;
89149003

89159004
read_tlv_fields!(reader, {
89169005
(0, announcement_sigs, option),
@@ -8923,6 +9012,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
89239012
(7, shutdown_scriptpubkey, option),
89249013
(8, blocked_monitor_updates, optional_vec),
89259014
(9, target_closing_feerate_sats_per_kw, option),
9015+
(10, monitor_pending_update_adds, option), // Added in 0.0.122
89269016
(11, monitor_pending_finalized_fulfills, optional_vec),
89279017
(13, channel_creation_height, option),
89289018
(15, preimages_opt, optional_vec),
@@ -9094,6 +9184,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
90949184
monitor_pending_forwards,
90959185
monitor_pending_failures,
90969186
monitor_pending_finalized_fulfills: monitor_pending_finalized_fulfills.unwrap(),
9187+
monitor_pending_update_adds: monitor_pending_update_adds.unwrap_or(Vec::new()),
90979188

90989189
signer_pending_commitment_update: false,
90999190
signer_pending_funding: false,

lightning/src/util/ser.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,8 @@ impl_for_vec!(crate::ln::msgs::SocketAddress);
894894
impl_for_vec!((A, B), A, B);
895895
impl_writeable_for_vec!(&crate::routing::router::BlindedTail);
896896
impl_readable_for_vec!(crate::routing::router::BlindedTail);
897+
impl_for_vec_with_element_length_prefix!(crate::ln::msgs::UpdateAddHTLC);
898+
impl_writeable_for_vec_with_element_length_prefix!(&crate::ln::msgs::UpdateAddHTLC);
897899

898900
impl Writeable for Vec<Witness> {
899901
#[inline]

0 commit comments

Comments
 (0)