mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 15:20:24 +01:00
Store per-state HTLC data in the state enum itself (and store more)
This commit is contained in:
parent
1479b38759
commit
4b231d5e6d
1 changed files with 75 additions and 59 deletions
|
@ -98,22 +98,27 @@ impl ChannelKeys {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
enum InboundHTLCRemovalReason {
|
||||||
|
FailRelay(msgs::OnionErrorPacket),
|
||||||
|
FailMalformed(([u8; 32], u16)),
|
||||||
|
Fulfill([u8; 32]),
|
||||||
|
}
|
||||||
|
|
||||||
enum InboundHTLCState {
|
enum InboundHTLCState {
|
||||||
/// Added by remote, to be included in next local commitment tx.
|
/// 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
|
/// 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
|
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
|
||||||
/// accept this HTLC. Implies AwaitingRemoteRevoke.
|
/// accept this HTLC. Implies AwaitingRemoteRevoke.
|
||||||
/// We also have not yet included this HTLC in a commitment_signed message, and are waiting on
|
/// 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.
|
/// 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
|
/// 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
|
/// the remote side hasn't yet revoked their previous state, which we need them to do before we
|
||||||
/// accept this HTLC. Implies AwaitingRemoteRevoke.
|
/// accept this HTLC. Implies AwaitingRemoteRevoke.
|
||||||
/// We have included this HTLC in our latest commitment_signed and are now just waiting on a
|
/// We have included this HTLC in our latest commitment_signed and are now just waiting on a
|
||||||
/// revoke_and_ack.
|
/// revoke_and_ack.
|
||||||
AwaitingAnnouncedRemoteRevoke,
|
AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus),
|
||||||
Committed,
|
Committed,
|
||||||
/// Removed by us and a new commitment_signed was sent (if we were AwaitingRemoteRevoke when we
|
/// 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
|
/// created it we would have put it in the holding cell instead). When they next revoke_and_ack
|
||||||
|
@ -125,7 +130,7 @@ enum InboundHTLCState {
|
||||||
/// ChannelMonitor::would_broadcast_at_height) so we actually remove the HTLC from our own
|
/// 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
|
/// 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.
|
/// ChannelMonitor::provide_latest_local_commitment_tx_info will not include this HTLC.
|
||||||
LocalRemoved,
|
LocalRemoved(InboundHTLCRemovalReason),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InboundHTLCOutput {
|
struct InboundHTLCOutput {
|
||||||
|
@ -134,10 +139,6 @@ struct InboundHTLCOutput {
|
||||||
cltv_expiry: u32,
|
cltv_expiry: u32,
|
||||||
payment_hash: [u8; 32],
|
payment_hash: [u8; 32],
|
||||||
state: InboundHTLCState,
|
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)]
|
#[derive(PartialEq)]
|
||||||
|
@ -791,21 +792,23 @@ impl Channel {
|
||||||
|
|
||||||
for ref htlc in self.pending_inbound_htlcs.iter() {
|
for ref htlc in self.pending_inbound_htlcs.iter() {
|
||||||
let include = match htlc.state {
|
let include = match htlc.state {
|
||||||
InboundHTLCState::RemoteAnnounced => !generated_by_local,
|
InboundHTLCState::RemoteAnnounced(_) => !generated_by_local,
|
||||||
InboundHTLCState::AwaitingRemoteRevokeToAnnounce => !generated_by_local,
|
InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => !generated_by_local,
|
||||||
InboundHTLCState::AwaitingAnnouncedRemoteRevoke => true,
|
InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => true,
|
||||||
InboundHTLCState::Committed => true,
|
InboundHTLCState::Committed => true,
|
||||||
InboundHTLCState::LocalRemoved => !generated_by_local,
|
InboundHTLCState::LocalRemoved(_) => !generated_by_local,
|
||||||
};
|
};
|
||||||
|
|
||||||
if include {
|
if include {
|
||||||
add_htlc_output!(htlc, false);
|
add_htlc_output!(htlc, false);
|
||||||
remote_htlc_total_msat += htlc.amount_msat;
|
remote_htlc_total_msat += htlc.amount_msat;
|
||||||
} else {
|
} else {
|
||||||
match htlc.state {
|
match &htlc.state {
|
||||||
InboundHTLCState::LocalRemoved => {
|
&InboundHTLCState::LocalRemoved(ref reason) => {
|
||||||
if generated_by_local && htlc.local_removed_fulfilled {
|
if generated_by_local {
|
||||||
value_to_self_msat_offset += htlc.amount_msat as i64;
|
if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
|
||||||
|
value_to_self_msat_offset += htlc.amount_msat as i64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
|
@ -1131,7 +1134,8 @@ impl Channel {
|
||||||
for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() {
|
for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() {
|
||||||
if htlc.htlc_id == htlc_id_arg {
|
if htlc.htlc_id == htlc_id_arg {
|
||||||
assert_eq!(htlc.payment_hash, payment_hash_calc);
|
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");
|
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
|
// Don't return in release mode here so that we can update channel_monitor
|
||||||
}
|
}
|
||||||
|
@ -1176,12 +1180,12 @@ impl Channel {
|
||||||
|
|
||||||
{
|
{
|
||||||
let htlc = &mut self.pending_inbound_htlcs[pending_idx];
|
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");
|
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())));
|
return Ok((None, Some(self.channel_monitor.clone())));
|
||||||
}
|
}
|
||||||
htlc.state = InboundHTLCState::LocalRemoved;
|
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(payment_preimage_arg.clone()));
|
||||||
htlc.local_removed_fulfilled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((Some(msgs::UpdateFulfillHTLC {
|
Ok((Some(msgs::UpdateFulfillHTLC {
|
||||||
|
@ -1213,7 +1217,8 @@ impl Channel {
|
||||||
let mut pending_idx = std::usize::MAX;
|
let mut pending_idx = std::usize::MAX;
|
||||||
for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() {
|
for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() {
|
||||||
if htlc.htlc_id == htlc_id_arg {
|
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");
|
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)});
|
return Err(HandleError{err: "Unable to find a pending HTLC which matched the given HTLC ID", action: Some(msgs::ErrorAction::IgnoreError)});
|
||||||
}
|
}
|
||||||
|
@ -1253,8 +1258,7 @@ impl Channel {
|
||||||
|
|
||||||
{
|
{
|
||||||
let htlc = &mut self.pending_inbound_htlcs[pending_idx];
|
let htlc = &mut self.pending_inbound_htlcs[pending_idx];
|
||||||
htlc.state = InboundHTLCState::LocalRemoved;
|
htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone()));
|
||||||
htlc.local_removed_fulfilled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(msgs::UpdateFailHTLC {
|
Ok(Some(msgs::UpdateFailHTLC {
|
||||||
|
@ -1533,9 +1537,7 @@ impl Channel {
|
||||||
amount_msat: msg.amount_msat,
|
amount_msat: msg.amount_msat,
|
||||||
payment_hash: msg.payment_hash,
|
payment_hash: msg.payment_hash,
|
||||||
cltv_expiry: msg.cltv_expiry,
|
cltv_expiry: msg.cltv_expiry,
|
||||||
state: InboundHTLCState::RemoteAnnounced,
|
state: InboundHTLCState::RemoteAnnounced(pending_forward_state),
|
||||||
local_removed_fulfilled: false,
|
|
||||||
pending_forward_state: Some(pending_forward_state),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1675,8 +1677,11 @@ impl Channel {
|
||||||
self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
|
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() {
|
for htlc in self.pending_inbound_htlcs.iter_mut() {
|
||||||
if htlc.state == InboundHTLCState::RemoteAnnounced {
|
let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
|
||||||
htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce;
|
Some(forward_info.clone())
|
||||||
|
} else { None };
|
||||||
|
if let Some(forward_info) = new_forward {
|
||||||
|
htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info);
|
||||||
need_our_commitment = true;
|
need_our_commitment = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1833,8 +1838,8 @@ impl Channel {
|
||||||
let mut value_to_self_msat_diff: i64 = 0;
|
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)
|
// We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug)
|
||||||
self.pending_inbound_htlcs.retain(|htlc| {
|
self.pending_inbound_htlcs.retain(|htlc| {
|
||||||
if htlc.state == InboundHTLCState::LocalRemoved {
|
if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state {
|
||||||
if htlc.local_removed_fulfilled {
|
if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
|
||||||
value_to_self_msat_diff += htlc.amount_msat as i64;
|
value_to_self_msat_diff += htlc.amount_msat as i64;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -1852,22 +1857,37 @@ impl Channel {
|
||||||
} else { true }
|
} else { true }
|
||||||
});
|
});
|
||||||
for htlc in self.pending_inbound_htlcs.iter_mut() {
|
for htlc in self.pending_inbound_htlcs.iter_mut() {
|
||||||
if htlc.state == InboundHTLCState::AwaitingRemoteRevokeToAnnounce {
|
let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state {
|
||||||
htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke;
|
true
|
||||||
require_commitment = true;
|
} else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state {
|
||||||
} else if htlc.state == InboundHTLCState::AwaitingAnnouncedRemoteRevoke {
|
true
|
||||||
match htlc.pending_forward_state.take().unwrap() {
|
} else { false };
|
||||||
PendingHTLCStatus::Fail(fail_msg) => {
|
if swap {
|
||||||
htlc.state = InboundHTLCState::LocalRemoved;
|
let mut state = InboundHTLCState::Committed;
|
||||||
require_commitment = true;
|
mem::swap(&mut state, &mut htlc.state);
|
||||||
match fail_msg {
|
|
||||||
HTLCFailureMsg::Relay(msg) => update_fail_htlcs.push(msg),
|
if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state {
|
||||||
HTLCFailureMsg::Malformed(msg) => update_fail_malformed_htlcs.push(msg),
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1985,22 +2005,21 @@ impl Channel {
|
||||||
let mut inbound_drop_count = 0;
|
let mut inbound_drop_count = 0;
|
||||||
self.pending_inbound_htlcs.retain(|htlc| {
|
self.pending_inbound_htlcs.retain(|htlc| {
|
||||||
match htlc.state {
|
match htlc.state {
|
||||||
InboundHTLCState::RemoteAnnounced => {
|
InboundHTLCState::RemoteAnnounced(_) => {
|
||||||
// They sent us an update_add_htlc but we never got the commitment_signed.
|
// 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
|
// We'll tell them what commitment_signed we're expecting next and they'll drop
|
||||||
// this HTLC accordingly
|
// this HTLC accordingly
|
||||||
inbound_drop_count += 1;
|
inbound_drop_count += 1;
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
InboundHTLCState::AwaitingRemoteRevokeToAnnounce|InboundHTLCState::AwaitingAnnouncedRemoteRevoke => {
|
InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_)|InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => {
|
||||||
// Same goes for AwaitingRemoteRevokeToRemove and AwaitingRemovedRemoteRevoke
|
|
||||||
// We received a commitment_signed updating this HTLC and (at least hopefully)
|
// 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
|
// sent a revoke_and_ack (which we can re-transmit) and have heard nothing
|
||||||
// in response to it yet, so don't touch it.
|
// in response to it yet, so don't touch it.
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
InboundHTLCState::Committed => true,
|
InboundHTLCState::Committed => true,
|
||||||
InboundHTLCState::LocalRemoved => { // Same goes for LocalAnnounced
|
InboundHTLCState::LocalRemoved(_) => {
|
||||||
// We (hopefully) sent a commitment_signed updating this HTLC (which we can
|
// 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
|
// 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
|
// (that we missed). Keep this around for now and if they tell us they missed
|
||||||
|
@ -2141,7 +2160,7 @@ impl Channel {
|
||||||
return Ok((None, None, Vec::new()));
|
return Ok((None, None, Vec::new()));
|
||||||
}
|
}
|
||||||
for htlc in self.pending_inbound_htlcs.iter() {
|
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});
|
return Err(HandleError{err: "Got shutdown with remote pending HTLCs", action: None});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2878,8 +2897,11 @@ impl Channel {
|
||||||
// fail to generate this, we still are at least at a position where upgrading their status
|
// fail to generate this, we still are at least at a position where upgrading their status
|
||||||
// is acceptable.
|
// is acceptable.
|
||||||
for htlc in self.pending_inbound_htlcs.iter_mut() {
|
for htlc in self.pending_inbound_htlcs.iter_mut() {
|
||||||
if htlc.state == InboundHTLCState::AwaitingRemoteRevokeToAnnounce {
|
let new_state = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref forward_info) = &htlc.state {
|
||||||
htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke;
|
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() {
|
for htlc in self.pending_outbound_htlcs.iter_mut() {
|
||||||
|
@ -3188,8 +3210,6 @@ mod tests {
|
||||||
cltv_expiry: 500,
|
cltv_expiry: 500,
|
||||||
payment_hash: [0; 32],
|
payment_hash: [0; 32],
|
||||||
state: InboundHTLCState::Committed,
|
state: InboundHTLCState::Committed,
|
||||||
local_removed_fulfilled: false,
|
|
||||||
pending_forward_state: None,
|
|
||||||
};
|
};
|
||||||
let mut sha = Sha256::new();
|
let mut sha = Sha256::new();
|
||||||
sha.input(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
sha.input(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
|
||||||
|
@ -3203,8 +3223,6 @@ mod tests {
|
||||||
cltv_expiry: 501,
|
cltv_expiry: 501,
|
||||||
payment_hash: [0; 32],
|
payment_hash: [0; 32],
|
||||||
state: InboundHTLCState::Committed,
|
state: InboundHTLCState::Committed,
|
||||||
local_removed_fulfilled: false,
|
|
||||||
pending_forward_state: None,
|
|
||||||
};
|
};
|
||||||
let mut sha = Sha256::new();
|
let mut sha = Sha256::new();
|
||||||
sha.input(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
|
sha.input(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
|
||||||
|
@ -3248,8 +3266,6 @@ mod tests {
|
||||||
cltv_expiry: 504,
|
cltv_expiry: 504,
|
||||||
payment_hash: [0; 32],
|
payment_hash: [0; 32],
|
||||||
state: InboundHTLCState::Committed,
|
state: InboundHTLCState::Committed,
|
||||||
local_removed_fulfilled: false,
|
|
||||||
pending_forward_state: None,
|
|
||||||
};
|
};
|
||||||
let mut sha = Sha256::new();
|
let mut sha = Sha256::new();
|
||||||
sha.input(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap());
|
sha.input(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap());
|
||||||
|
|
Loading…
Add table
Reference in a new issue