}
}
-#[derive(PartialEq)]
+enum InboundHTLCRemovalReason {
+ FailRelay(msgs::OnionErrorPacket),
+ FailMalformed(([u8; 32], u16)),
+ Fulfill([u8; 32]),
+}
+
enum InboundHTLCState {
/// Added by remote, to be included in next local commitment tx.
- RemoteAnnounced,
+ RemoteAnnounced(PendingHTLCStatus),
/// Included in a received commitment_signed message (implying we've revoke_and_ack'ed it), but
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
/// a remote revoke_and_ack on a previous state before we can do so.
- AwaitingRemoteRevokeToAnnounce,
+ AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus),
/// Included in a received commitment_signed message (implying we've revoke_and_ack'ed it), but
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
/// accept this HTLC. Implies AwaitingRemoteRevoke.
/// We have included this HTLC in our latest commitment_signed and are now just waiting on a
/// revoke_and_ack.
- AwaitingAnnouncedRemoteRevoke,
+ AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus),
Committed,
/// Removed by us and a new commitment_signed was sent (if we were AwaitingRemoteRevoke when we
/// created it we would have put it in the holding cell instead). When they next revoke_and_ack
/// ChannelMonitor::would_broadcast_at_height) so we actually remove the HTLC from our own
/// local state before then, once we're sure that the next commitment_signed and
/// ChannelMonitor::provide_latest_local_commitment_tx_info will not include this HTLC.
- LocalRemoved,
+ LocalRemoved(InboundHTLCRemovalReason),
}
struct InboundHTLCOutput {
cltv_expiry: u32,
payment_hash: [u8; 32],
state: InboundHTLCState,
- /// If we're in LocalRemoved, set to true if we fulfilled the HTLC, and can claim money
- local_removed_fulfilled: bool,
- /// state pre-Committed implies pending_forward_state, otherwise it must be None
- pending_forward_state: Option<PendingHTLCStatus>,
}
#[derive(PartialEq)]
for ref htlc in self.pending_inbound_htlcs.iter() {
let include = match htlc.state {
- InboundHTLCState::RemoteAnnounced => !generated_by_local,
- InboundHTLCState::AwaitingRemoteRevokeToAnnounce => !generated_by_local,
- InboundHTLCState::AwaitingAnnouncedRemoteRevoke => true,
+ InboundHTLCState::RemoteAnnounced(_) => !generated_by_local,
+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => !generated_by_local,
+ InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => true,
InboundHTLCState::Committed => true,
- InboundHTLCState::LocalRemoved => !generated_by_local,
+ InboundHTLCState::LocalRemoved(_) => !generated_by_local,
};
if include {
add_htlc_output!(htlc, false);
remote_htlc_total_msat += htlc.amount_msat;
} else {
- match htlc.state {
- InboundHTLCState::LocalRemoved => {
- if generated_by_local && htlc.local_removed_fulfilled {
- value_to_self_msat_offset += htlc.amount_msat as i64;
+ match &htlc.state {
+ &InboundHTLCState::LocalRemoved(ref reason) => {
+ if generated_by_local {
+ if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
+ value_to_self_msat_offset += htlc.amount_msat as i64;
+ }
}
},
_ => {},
for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() {
if htlc.htlc_id == htlc_id_arg {
assert_eq!(htlc.payment_hash, payment_hash_calc);
- if htlc.state != InboundHTLCState::Committed {
+ if let InboundHTLCState::Committed = htlc.state {
+ } else {
debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to");
// Don't return in release mode here so that we can update channel_monitor
}
{
let htlc = &mut self.pending_inbound_htlcs[pending_idx];
- if htlc.state != InboundHTLCState::Committed {
+ if let InboundHTLCState::Committed = htlc.state {
+ } else {
debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to");
return Ok((None, Some(self.channel_monitor.clone())));
}
- htlc.state = InboundHTLCState::LocalRemoved;
- htlc.local_removed_fulfilled = true;
+ htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(payment_preimage_arg.clone()));
}
Ok((Some(msgs::UpdateFulfillHTLC {
let mut pending_idx = std::usize::MAX;
for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() {
if htlc.htlc_id == htlc_id_arg {
- if htlc.state != InboundHTLCState::Committed {
+ if let InboundHTLCState::Committed = htlc.state {
+ } else {
debug_assert!(false, "Have an inbound HTLC we tried to fail before it was fully committed to");
return Err(HandleError{err: "Unable to find a pending HTLC which matched the given HTLC ID", action: Some(msgs::ErrorAction::IgnoreError)});
}
{
let htlc = &mut self.pending_inbound_htlcs[pending_idx];
- htlc.state = InboundHTLCState::LocalRemoved;
- htlc.local_removed_fulfilled = false;
+ htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone()));
}
Ok(Some(msgs::UpdateFailHTLC {
amount_msat: msg.amount_msat,
payment_hash: msg.payment_hash,
cltv_expiry: msg.cltv_expiry,
- state: InboundHTLCState::RemoteAnnounced,
- local_removed_fulfilled: false,
- pending_forward_state: Some(pending_forward_state),
+ state: InboundHTLCState::RemoteAnnounced(pending_forward_state),
});
Ok(())
self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
for htlc in self.pending_inbound_htlcs.iter_mut() {
- if htlc.state == InboundHTLCState::RemoteAnnounced {
- htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce;
+ let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
+ Some(forward_info.clone())
+ } else { None };
+ if let Some(forward_info) = new_forward {
+ htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info);
need_our_commitment = true;
}
}
let mut value_to_self_msat_diff: i64 = 0;
// We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug)
self.pending_inbound_htlcs.retain(|htlc| {
- if htlc.state == InboundHTLCState::LocalRemoved {
- if htlc.local_removed_fulfilled {
+ if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state {
+ if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
value_to_self_msat_diff += htlc.amount_msat as i64;
}
false
} else { true }
});
for htlc in self.pending_inbound_htlcs.iter_mut() {
- if htlc.state == InboundHTLCState::AwaitingRemoteRevokeToAnnounce {
- htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke;
- require_commitment = true;
- } else if htlc.state == InboundHTLCState::AwaitingAnnouncedRemoteRevoke {
- match htlc.pending_forward_state.take().unwrap() {
- PendingHTLCStatus::Fail(fail_msg) => {
- htlc.state = InboundHTLCState::LocalRemoved;
- require_commitment = true;
- match fail_msg {
- HTLCFailureMsg::Relay(msg) => update_fail_htlcs.push(msg),
- HTLCFailureMsg::Malformed(msg) => update_fail_malformed_htlcs.push(msg),
+ let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state {
+ true
+ } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state {
+ true
+ } else { false };
+ if swap {
+ let mut state = InboundHTLCState::Committed;
+ mem::swap(&mut state, &mut htlc.state);
+
+ if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state {
+ htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info);
+ require_commitment = true;
+ } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state {
+ match forward_info {
+ PendingHTLCStatus::Fail(fail_msg) => {
+ require_commitment = true;
+ match fail_msg {
+ HTLCFailureMsg::Relay(msg) => {
+ htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
+ update_fail_htlcs.push(msg)
+ },
+ HTLCFailureMsg::Malformed(msg) => {
+ htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
+ update_fail_malformed_htlcs.push(msg)
+ },
+ }
+ },
+ PendingHTLCStatus::Forward(forward_info) => {
+ to_forward_infos.push((forward_info, htlc.htlc_id));
+ htlc.state = InboundHTLCState::Committed;
}
- },
- PendingHTLCStatus::Forward(forward_info) => {
- to_forward_infos.push((forward_info, htlc.htlc_id));
- htlc.state = InboundHTLCState::Committed;
}
}
}
let mut inbound_drop_count = 0;
self.pending_inbound_htlcs.retain(|htlc| {
match htlc.state {
- InboundHTLCState::RemoteAnnounced => {
+ InboundHTLCState::RemoteAnnounced(_) => {
// They sent us an update_add_htlc but we never got the commitment_signed.
// We'll tell them what commitment_signed we're expecting next and they'll drop
// this HTLC accordingly
inbound_drop_count += 1;
false
},
- InboundHTLCState::AwaitingRemoteRevokeToAnnounce|InboundHTLCState::AwaitingAnnouncedRemoteRevoke => {
- // Same goes for AwaitingRemoteRevokeToRemove and AwaitingRemovedRemoteRevoke
+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_)|InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => {
// We received a commitment_signed updating this HTLC and (at least hopefully)
// sent a revoke_and_ack (which we can re-transmit) and have heard nothing
// in response to it yet, so don't touch it.
true
},
InboundHTLCState::Committed => true,
- InboundHTLCState::LocalRemoved => { // Same goes for LocalAnnounced
+ InboundHTLCState::LocalRemoved(_) => {
// We (hopefully) sent a commitment_signed updating this HTLC (which we can
// re-transmit if needed) and they may have even sent a revoke_and_ack back
// (that we missed). Keep this around for now and if they tell us they missed
return Ok((None, None, Vec::new()));
}
for htlc in self.pending_inbound_htlcs.iter() {
- if htlc.state == InboundHTLCState::RemoteAnnounced {
+ if let InboundHTLCState::RemoteAnnounced(_) = htlc.state {
return Err(HandleError{err: "Got shutdown with remote pending HTLCs", action: None});
}
}
// fail to generate this, we still are at least at a position where upgrading their status
// is acceptable.
for htlc in self.pending_inbound_htlcs.iter_mut() {
- if htlc.state == InboundHTLCState::AwaitingRemoteRevokeToAnnounce {
- htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke;
+ let new_state = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref forward_info) = &htlc.state {
+ Some(InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info.clone()))
+ } else { None };
+ if let Some(state) = new_state {
+ htlc.state = state;
}
}
for htlc in self.pending_outbound_htlcs.iter_mut() {
cltv_expiry: 500,
payment_hash: [0; 32],
state: InboundHTLCState::Committed,
- local_removed_fulfilled: false,
- pending_forward_state: None,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
cltv_expiry: 501,
payment_hash: [0; 32],
state: InboundHTLCState::Committed,
- local_removed_fulfilled: false,
- pending_forward_state: None,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
cltv_expiry: 504,
payment_hash: [0; 32],
state: InboundHTLCState::Committed,
- local_removed_fulfilled: false,
- pending_forward_state: None,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap());