diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index e460df25e54..4f422ee2c9b 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -523,6 +523,9 @@ mod tests { fn handle_update_fulfill_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFulfillHTLC) {} fn handle_update_fail_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFailHTLC) {} fn handle_update_fail_malformed_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFailMalformedHTLC) {} + fn handle_update_add_dlc(&self, _their_node_id: &PublicKey, _msg: &UpdateAddDLC) {} + fn handle_update_countersign_dlc(&self, _their_node_id: &PublicKey, _msg: &UpdateCounterSignDLC) {} + fn handle_update_fulfill_dlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFulfillDLC) {} fn handle_commitment_signed(&self, _their_node_id: &PublicKey, _msg: &CommitmentSigned) {} fn handle_revoke_and_ack(&self, _their_node_id: &PublicKey, _msg: &RevokeAndACK) {} fn handle_update_fee(&self, _their_node_id: &PublicKey, _msg: &UpdateFee) {} diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 92428a09d0e..0846fe15161 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -90,6 +90,125 @@ struct InboundHTLCOutput { state: InboundHTLCState, } +impl Writeable for InboundHTLCOutput { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + self.htlc_id.write(writer)?; + self.amount_msat.write(writer)?; + self.cltv_expiry.write(writer)?; + self.payment_hash.write(writer)?; + match &self.state { + &InboundHTLCState::RemoteAnnounced(_) => unreachable!(), + &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_state) => { + 1u8.write(writer)?; + htlc_state.write(writer)?; + }, + &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_state) => { + 2u8.write(writer)?; + htlc_state.write(writer)?; + }, + &InboundHTLCState::Committed => { + 3u8.write(writer)?; + }, + &InboundHTLCState::LocalRemoved(ref removal_reason) => { + 4u8.write(writer)?; + removal_reason.write(writer)?; + }, + } + + Ok(()) + } +} + +impl Readable for InboundHTLCOutput { + fn read(reader: &mut R) -> Result { + let htlc_id = Readable::read(reader)?; + let amount_msat = Readable::read(reader)?; + let cltv_expiry = Readable::read(reader)?; + let payment_hash = Readable::read(reader)?; + let state = match ::read(reader)? { + 1 => InboundHTLCState::AwaitingRemoteRevokeToAnnounce(Readable::read(reader)?), + 2 => InboundHTLCState::AwaitingAnnouncedRemoteRevoke(Readable::read(reader)?), + 3 => InboundHTLCState::Committed, + 4 => InboundHTLCState::LocalRemoved(Readable::read(reader)?), + _ => return Err(DecodeError::InvalidValue), + }; + + Ok(InboundHTLCOutput { + htlc_id, + amount_msat, + cltv_expiry, + payment_hash, + state + }) + } +} + +struct InboundCETOutput { + cet_id: u64, + amount_msat: u64, + maturity: u32, + identifier: PaymentHash, + state: InboundHTLCState, +} + +/// A generic trait to ascribe state transition to any kind of output +trait InboundGenericOutput: Send { + fn update_state(&mut self, state: InboundHTLCState); + fn state(&self) -> &InboundHTLCState; + fn value(&self) -> u64; + fn timelock(&self) -> u32; + fn hash(&self) -> PaymentHash; + fn id(&self) -> u64; + fn log(&self); +} + +impl InboundGenericOutput for InboundHTLCOutput { + fn update_state(&mut self, state: InboundHTLCState) { + self.state = state; + } + fn state(&self) -> &InboundHTLCState { + &self.state + } + fn value(&self) -> u64 { + self.amount_msat + } + fn timelock(&self) -> u32 { + self.cltv_expiry + } + fn hash(&self) -> PaymentHash { + self.payment_hash + } + fn id(&self) -> u64 { + self.htlc_id + } + fn log(&self) { + log_bytes!(self.payment_hash.0); + } +} + +impl InboundGenericOutput for InboundCETOutput { + fn update_state(&mut self, state: InboundHTLCState) { + self.state = state; + } + fn state(&self) -> &InboundHTLCState { + &self.state + } + fn value(&self) -> u64 { + self.amount_msat + } + fn timelock(&self) -> u32 { + self.maturity + } + fn hash(&self) -> PaymentHash { + //XXX + PaymentHash([0; 32]) + } + fn id(&self) -> u64 { + self.cet_id + } + fn log(&self) {} +} + enum OutboundHTLCState { /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we /// created it we would have put it in the holding cell instead). When they next revoke_and_ack @@ -131,6 +250,48 @@ struct OutboundHTLCOutput { source: HTLCSource, } +/// A generic trait to ascribe state transaition to any kind of outbound payload +/// output +trait OutboundGenericOutput: Send { + fn update_state(&mut self, state: OutboundHTLCState); + fn mut_state(&mut self) -> &mut OutboundHTLCState; + fn state(&self) -> &OutboundHTLCState; + fn value(&self) -> u64; + fn timelock(&self) -> u32; + fn hash(&self) -> PaymentHash; + fn id(&self) -> u64; + fn routing_source(&self) -> &HTLCSource; + fn log(&self); +} + +impl OutboundGenericOutput for OutboundHTLCOutput { + fn update_state(&mut self, state: OutboundHTLCState) { + self.state = state; + } + fn mut_state(&mut self) -> &mut OutboundHTLCState { + &mut self.state + } + fn state(&self) -> &OutboundHTLCState { + &self.state + } + fn value(&self) -> u64 { + self.amount_msat + } + fn timelock(&self) -> u32 { + self.cltv_expiry + } + fn hash(&self) -> PaymentHash { + self.payment_hash + } + fn id(&self) -> u64 { + self.htlc_id + } + fn routing_source(&self) -> &HTLCSource { + &self.source + } + fn log(&self) {} +} + /// See AwaitingRemoteRevoke ChannelState for more info enum HTLCUpdateAwaitingACK { AddHTLC { // TODO: Time out if we're getting close to cltv_expiry @@ -256,8 +417,8 @@ pub(super) struct Channel { cur_local_commitment_transaction_number: u64, cur_remote_commitment_transaction_number: u64, value_to_self_msat: u64, // Excluding all pending_htlcs, excluding fees - pending_inbound_htlcs: Vec, - pending_outbound_htlcs: Vec, + pending_inbound_htlcs: Vec>, + pending_outbound_htlcs: Vec>, holding_cell_htlc_updates: Vec, /// When resending CS/RAA messages on channel monitor restoration or on reconnect, we always @@ -836,41 +997,41 @@ impl Channel { log_trace!(self, "Building commitment transaction number {} (really {} xor {}) for {}, generated by {} with fee {}...", commitment_number, (INITIAL_COMMITMENT_NUMBER - commitment_number), self.get_commitment_transaction_number_obscure_factor(), if local { "us" } else { "remote" }, if generated_by_local { "us" } else { "remote" }, feerate_per_kw); macro_rules! get_htlc_in_commitment { - ($htlc: expr, $offered: expr) => { + ($htlc: expr, $offered: expr, $value: expr, $timelock: expr, $hash: expr) => { HTLCOutputInCommitment { offered: $offered, - amount_msat: $htlc.amount_msat, - cltv_expiry: $htlc.cltv_expiry, - payment_hash: $htlc.payment_hash, + amount_msat: $value, + cltv_expiry: $timelock, + payment_hash: $hash, transaction_output_index: None } } } macro_rules! add_htlc_output { - ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => { + ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr, $value: expr, $timelock: expr, $hash: expr) => { if $outbound == local { // "offered HTLC output" - let htlc_in_tx = get_htlc_in_commitment!($htlc, true); - if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) { - log_trace!(self, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); + let htlc_in_tx = get_htlc_in_commitment!($htlc, true, $value, $timelock, $hash); + if $value / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) { + //log_trace!(self, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); txouts.push((TxOut { script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(), - value: $htlc.amount_msat / 1000 + value: $value / 1000 }, Some((htlc_in_tx, $source)))); } else { - log_trace!(self, " ...including {} {} dust HTLC {} (hash {}) with value {} due to dust limit", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); + //log_trace!(self, " ...including {} {} dust HTLC {} (hash {}) with value {} due to dust limit", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); included_dust_htlcs.push((htlc_in_tx, $source)); } } else { - let htlc_in_tx = get_htlc_in_commitment!($htlc, false); - if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) { - log_trace!(self, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); + let htlc_in_tx = get_htlc_in_commitment!($htlc, false, $value, $timelock, $hash); + if $value / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) { + //log_trace!(self, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); txouts.push((TxOut { // "received HTLC output" script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(), - value: $htlc.amount_msat / 1000 + value: $value / 1000 }, Some((htlc_in_tx, $source)))); } else { - log_trace!(self, " ...including {} {} dust HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); + //log_trace!(self, " ...including {} {} dust HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); included_dust_htlcs.push((htlc_in_tx, $source)); } } @@ -878,7 +1039,7 @@ impl Channel { } for ref htlc in self.pending_inbound_htlcs.iter() { - let (include, state_name) = match htlc.state { + let (include, state_name) = match htlc.state() { InboundHTLCState::RemoteAnnounced(_) => (!generated_by_local, "RemoteAnnounced"), InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => (!generated_by_local, "AwaitingRemoteRevokeToAnnounce"), InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => (true, "AwaitingAnnouncedRemoteRevoke"), @@ -887,15 +1048,15 @@ impl Channel { }; if include { - add_htlc_output!(htlc, false, None, state_name); - remote_htlc_total_msat += htlc.amount_msat; + add_htlc_output!(htlc, false, None, state_name, htlc.value(), htlc.timelock(), htlc.hash()); + remote_htlc_total_msat += htlc.value(); } else { - log_trace!(self, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); - match &htlc.state { + //log_trace!(self, " ...not including inbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); + 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; + value_to_self_msat_offset += htlc.value() as i64; } } }, @@ -905,7 +1066,7 @@ impl Channel { } for ref htlc in self.pending_outbound_htlcs.iter() { - let (include, state_name) = match htlc.state { + let (include, state_name) = match htlc.state() { OutboundHTLCState::LocalAnnounced(_) => (generated_by_local, "LocalAnnounced"), OutboundHTLCState::Committed => (true, "Committed"), OutboundHTLCState::RemoteRemoved(_) => (generated_by_local, "RemoteRemoved"), @@ -914,17 +1075,17 @@ impl Channel { }; if include { - add_htlc_output!(htlc, true, Some(&htlc.source), state_name); - local_htlc_total_msat += htlc.amount_msat; + add_htlc_output!(htlc, true, Some(htlc.routing_source()), state_name, htlc.value(), htlc.timelock(), htlc.hash()); + local_htlc_total_msat += htlc.value(); } else { - log_trace!(self, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); - match htlc.state { + //log_trace!(self, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); + match htlc.state() { OutboundHTLCState::AwaitingRemoteRevokeToRemove(None)|OutboundHTLCState::AwaitingRemovedRemoteRevoke(None) => { - value_to_self_msat_offset -= htlc.amount_msat as i64; + value_to_self_msat_offset -= htlc.value() as i64; }, OutboundHTLCState::RemoteRemoved(None) => { if !generated_by_local { - value_to_self_msat_offset -= htlc.amount_msat as i64; + value_to_self_msat_offset -= htlc.value() as i64; } }, _ => {}, @@ -1162,14 +1323,15 @@ impl Channel { let mut pending_idx = std::usize::MAX; 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); - match htlc.state { + if htlc.id() == htlc_id_arg { + //XXX: assert() + //assert_eq!(htlc.payment_hash, payment_hash_calc); + match htlc.state() { InboundHTLCState::Committed => {}, InboundHTLCState::LocalRemoved(ref reason) => { if let &InboundHTLCRemovalReason::Fulfill(_) = reason { } else { - log_warn!(self, "Have preimage and want to fulfill HTLC with payment hash {} we already failed against channel {}", log_bytes!(htlc.payment_hash.0), log_bytes!(self.channel_id())); + //log_warn!(self, "Have preimage and want to fulfill HTLC with payment hash {} we already failed against channel {}", log_bytes!(htlc.payment_hash.0), log_bytes!(self.channel_id())); } debug_assert!(false, "Tried to fulfill an HTLC that was already fail/fulfilled"); return Ok((None, None)); @@ -1232,13 +1394,13 @@ impl Channel { { let htlc = &mut self.pending_inbound_htlcs[pending_idx]; - if let InboundHTLCState::Committed = htlc.state { + 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(monitor_update))); } - log_trace!(self, "Upgrading HTLC {} to LocalRemoved with a Fulfill!", log_bytes!(htlc.payment_hash.0)); - htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(payment_preimage_arg.clone())); + //log_trace!(self, "Upgrading HTLC {} to LocalRemoved with a Fulfill!", log_bytes!(htlc.payment_hash.0)); + htlc.update_state(InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(payment_preimage_arg.clone()))); } Ok((Some(msgs::UpdateFulfillHTLC { @@ -1285,8 +1447,8 @@ impl Channel { let mut pending_idx = std::usize::MAX; for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() { - if htlc.htlc_id == htlc_id_arg { - match htlc.state { + if htlc.id() == htlc_id_arg { + match htlc.state() { InboundHTLCState::Committed => {}, InboundHTLCState::LocalRemoved(_) => { debug_assert!(false, "Tried to fail an HTLC that was already fail/fulfilled"); @@ -1332,7 +1494,7 @@ impl Channel { { let htlc = &mut self.pending_inbound_htlcs[pending_idx]; - htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone())); + htlc.update_state(InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone()))); } Ok(Some(msgs::UpdateFailHTLC { @@ -1640,7 +1802,7 @@ impl Channel { fn get_inbound_pending_htlc_stats(&self) -> (u32, u64) { let mut htlc_inbound_value_msat = 0; for ref htlc in self.pending_inbound_htlcs.iter() { - htlc_inbound_value_msat += htlc.amount_msat; + htlc_inbound_value_msat += htlc.value(); } (self.pending_inbound_htlcs.len() as u32, htlc_inbound_value_msat) } @@ -1650,7 +1812,7 @@ impl Channel { fn get_outbound_pending_htlc_stats(&self) -> (u32, u64) { let mut htlc_outbound_value_msat = 0; for ref htlc in self.pending_outbound_htlcs.iter() { - htlc_outbound_value_msat += htlc.amount_msat; + htlc_outbound_value_msat += htlc.value(); } let mut htlc_outbound_count = self.pending_outbound_htlcs.len(); @@ -1713,10 +1875,10 @@ impl Channel { // transaction). let mut removed_outbound_total_msat = 0; for ref htlc in self.pending_outbound_htlcs.iter() { - if let OutboundHTLCState::AwaitingRemoteRevokeToRemove(None) = htlc.state { - removed_outbound_total_msat += htlc.amount_msat; - } else if let OutboundHTLCState::AwaitingRemovedRemoteRevoke(None) = htlc.state { - removed_outbound_total_msat += htlc.amount_msat; + if let OutboundHTLCState::AwaitingRemoteRevokeToRemove(None) = htlc.state() { + removed_outbound_total_msat += htlc.value(); + } else if let OutboundHTLCState::AwaitingRemovedRemoteRevoke(None) = htlc.state() { + removed_outbound_total_msat += htlc.value(); } } if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::::get_remote_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 + removed_outbound_total_msat { @@ -1737,13 +1899,31 @@ impl Channel { // Now update local state: self.next_remote_htlc_id += 1; - self.pending_inbound_htlcs.push(InboundHTLCOutput { + self.pending_inbound_htlcs.push(Box::new(InboundHTLCOutput { htlc_id: msg.htlc_id, amount_msat: msg.amount_msat, payment_hash: msg.payment_hash, cltv_expiry: msg.cltv_expiry, state: InboundHTLCState::RemoteAnnounced(pending_forward_state), - }); + })); + Ok(()) + } + + pub fn update_add_dlc(&mut self, msg: &msgs::UpdateAddDLC, pending_forward_state: PendingHTLCStatus) -> Result<(), ChannelError> { + if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) { + return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state")); + } + if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { + return Err(ChannelError::Close("Peer sent update_add_htlc when we needed a channel_reestablish")); + } + self.next_remote_htlc_id += 1; + self.pending_inbound_htlcs.push(Box::new(InboundCETOutput { + cet_id: msg.event_id, + amount_msat: msg.amount_msat, + maturity: msg.maturity, + identifier: PaymentHash([0; 32]), + state: InboundHTLCState::RemoteAnnounced(pending_forward_state), + })); Ok(()) } @@ -1751,24 +1931,24 @@ impl Channel { #[inline] fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option, fail_reason: Option) -> Result<&HTLCSource, ChannelError> { for htlc in self.pending_outbound_htlcs.iter_mut() { - if htlc.htlc_id == htlc_id { + if htlc.id() == htlc_id { match check_preimage { None => {}, Some(payment_hash) => - if payment_hash != htlc.payment_hash { + if payment_hash != htlc.hash() { return Err(ChannelError::Close("Remote tried to fulfill HTLC with an incorrect preimage")); } }; - match htlc.state { + match htlc.state() { OutboundHTLCState::LocalAnnounced(_) => return Err(ChannelError::Close("Remote tried to fulfill/fail HTLC before it had been committed")), OutboundHTLCState::Committed => { - htlc.state = OutboundHTLCState::RemoteRemoved(fail_reason); + htlc.update_state(OutboundHTLCState::RemoteRemoved(fail_reason)); }, OutboundHTLCState::AwaitingRemoteRevokeToRemove(_) | OutboundHTLCState::AwaitingRemovedRemoteRevoke(_) | OutboundHTLCState::RemoteRemoved(_) => return Err(ChannelError::Close("Remote tried to fulfill/fail HTLC that they'd already fulfilled/failed")), } - return Ok(&htlc.source); + return Ok(htlc.routing_source()); } } Err(ChannelError::Close("Remote tried to fulfill/fail an HTLC we couldn't find")) @@ -1912,19 +2092,19 @@ impl Channel { self.channel_monitor.as_mut().unwrap().update_monitor_ooo(monitor_update.clone()).unwrap(); for htlc in self.pending_inbound_htlcs.iter_mut() { - let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state { + 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); + htlc.update_state(InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info)); need_our_commitment = true; } } for htlc in self.pending_outbound_htlcs.iter_mut() { - if let Some(fail_reason) = if let &mut OutboundHTLCState::RemoteRemoved(ref mut fail_reason) = &mut htlc.state { + if let Some(fail_reason) = if let &mut OutboundHTLCState::RemoteRemoved(ref mut fail_reason) = &mut htlc.mut_state() { Some(fail_reason.take()) } else { None } { - htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove(fail_reason); + htlc.update_state(OutboundHTLCState::AwaitingRemoteRevokeToRemove(fail_reason)); need_our_commitment = true; } } @@ -2088,6 +2268,8 @@ impl Channel { update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs: Vec::new(), + update_add_dlcs: Vec::new(), + update_countersign_dlcs: Vec::new(), update_fee: update_fee, commitment_signed, }, monitor_update))) @@ -2171,40 +2353,40 @@ impl Channel { // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug) pending_inbound_htlcs.retain(|htlc| { - if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state { - log_trace!(logger, " ...removing inbound LocalRemoved {}", log_bytes!(htlc.payment_hash.0)); + if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state() { + //log_trace!(logger, " ...removing inbound LocalRemoved {}", log_bytes!(htlc.payment_hash.0)); if let &InboundHTLCRemovalReason::Fulfill(_) = reason { - value_to_self_msat_diff += htlc.amount_msat as i64; + value_to_self_msat_diff += htlc.value() as i64; } false } else { true } }); pending_outbound_htlcs.retain(|htlc| { - if let &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref fail_reason) = &htlc.state { - log_trace!(logger, " ...removing outbound AwaitingRemovedRemoteRevoke {}", log_bytes!(htlc.payment_hash.0)); + if let &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref fail_reason) = &htlc.state() { + //log_trace!(logger, " ...removing outbound AwaitingRemovedRemoteRevoke {}", log_bytes!(htlc.payment_hash.0)); if let Some(reason) = fail_reason.clone() { // We really want take() here, but, again, non-mut ref :( - revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason)); + revoked_htlcs.push((htlc.routing_source().clone(), htlc.hash(), reason)); } else { // They fulfilled, so we sent them money - value_to_self_msat_diff -= htlc.amount_msat as i64; + value_to_self_msat_diff -= htlc.value() as i64; } false } else { true } }); for htlc in pending_inbound_htlcs.iter_mut() { - let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state { - log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce {} to Committed", log_bytes!(htlc.payment_hash.0)); + let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state() { + //log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce {} to Committed", log_bytes!(htlc.payment_hash.0)); true - } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state { - log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", log_bytes!(htlc.payment_hash.0)); + } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state() { + //log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", log_bytes!(htlc.payment_hash.0)); true } else { false }; if swap { - let mut state = InboundHTLCState::Committed; - mem::swap(&mut state, &mut htlc.state); + let state = InboundHTLCState::Committed; + htlc.update_state(InboundHTLCState::Committed); if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state { - htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info); + htlc.update_state(InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info)); require_commitment = true; } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state { match forward_info { @@ -2212,33 +2394,34 @@ impl Channel { require_commitment = true; match fail_msg { HTLCFailureMsg::Relay(msg) => { - htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone())); + htlc.update_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))); + htlc.update_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; + to_forward_infos.push((forward_info, htlc.id())); + htlc.update_state(InboundHTLCState::Committed); } + _ => {} } } } } for htlc in pending_outbound_htlcs.iter_mut() { - if let OutboundHTLCState::LocalAnnounced(_) = htlc.state { - log_trace!(logger, " ...promoting outbound LocalAnnounced {} to Committed", log_bytes!(htlc.payment_hash.0)); - htlc.state = OutboundHTLCState::Committed; + if let OutboundHTLCState::LocalAnnounced(_) = htlc.state() { + //log_trace!(logger, " ...promoting outbound LocalAnnounced {} to Committed", log_bytes!(htlc.payment_hash.0)); + htlc.update_state(OutboundHTLCState::Committed); } - if let Some(fail_reason) = if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut fail_reason) = &mut htlc.state { + if let Some(fail_reason) = if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut fail_reason) = &mut htlc.mut_state() { Some(fail_reason.take()) } else { None } { - log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", log_bytes!(htlc.payment_hash.0)); - htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(fail_reason); + //log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", log_bytes!(htlc.payment_hash.0)); + htlc.update_state(OutboundHTLCState::AwaitingRemovedRemoteRevoke(fail_reason)); require_commitment = true; } } @@ -2314,6 +2497,8 @@ impl Channel { update_fulfill_htlcs: Vec::new(), update_fail_htlcs, update_fail_malformed_htlcs, + update_add_dlcs: Vec::new(), + update_countersign_dlcs: Vec::new(), update_fee: None, commitment_signed }), to_forward_infos, revoked_htlcs, None, monitor_update)) @@ -2383,7 +2568,7 @@ impl Channel { let mut inbound_drop_count = 0; self.pending_inbound_htlcs.retain(|htlc| { - match htlc.state { + match htlc.state() { 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 @@ -2410,11 +2595,11 @@ impl Channel { self.next_remote_htlc_id -= inbound_drop_count; for htlc in self.pending_outbound_htlcs.iter_mut() { - if let OutboundHTLCState::RemoteRemoved(_) = htlc.state { + if let OutboundHTLCState::RemoteRemoved(_) = htlc.state() { // They sent us an update to remove this but haven't yet sent the corresponding // commitment_signed, we need to move it back to Committed and they can re-send // the update upon reconnection. - htlc.state = OutboundHTLCState::Committed; + htlc.update_state(OutboundHTLCState::Committed); } } @@ -2534,34 +2719,37 @@ impl Channel { let mut update_fulfill_htlcs = Vec::new(); let mut update_fail_htlcs = Vec::new(); let mut update_fail_malformed_htlcs = Vec::new(); + let mut update_add_dlcs = Vec::new(); + let mut update_countersign_dlcs = Vec::new(); + //XXX: support generic payload support for htlc in self.pending_outbound_htlcs.iter() { - if let &OutboundHTLCState::LocalAnnounced(ref onion_packet) = &htlc.state { + if let &OutboundHTLCState::LocalAnnounced(ref onion_packet) = &htlc.state() { update_add_htlcs.push(msgs::UpdateAddHTLC { channel_id: self.channel_id(), - htlc_id: htlc.htlc_id, - amount_msat: htlc.amount_msat, - payment_hash: htlc.payment_hash, - cltv_expiry: htlc.cltv_expiry, + htlc_id: htlc.id(), + amount_msat: htlc.value(), + payment_hash: htlc.hash(), + cltv_expiry: htlc.timelock(), onion_routing_packet: (**onion_packet).clone(), }); } } for htlc in self.pending_inbound_htlcs.iter() { - if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state { + if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state() { match reason { &InboundHTLCRemovalReason::FailRelay(ref err_packet) => { update_fail_htlcs.push(msgs::UpdateFailHTLC { channel_id: self.channel_id(), - htlc_id: htlc.htlc_id, + htlc_id: htlc.id(), reason: err_packet.clone() }); }, &InboundHTLCRemovalReason::FailMalformed((ref sha256_of_onion, ref failure_code)) => { update_fail_malformed_htlcs.push(msgs::UpdateFailMalformedHTLC { channel_id: self.channel_id(), - htlc_id: htlc.htlc_id, + htlc_id: htlc.id(), sha256_of_onion: sha256_of_onion.clone(), failure_code: failure_code.clone(), }); @@ -2569,7 +2757,7 @@ impl Channel { &InboundHTLCRemovalReason::Fulfill(ref payment_preimage) => { update_fulfill_htlcs.push(msgs::UpdateFulfillHTLC { channel_id: self.channel_id(), - htlc_id: htlc.htlc_id, + htlc_id: htlc.id(), payment_preimage: payment_preimage.clone(), }); }, @@ -2580,7 +2768,7 @@ impl Channel { log_trace!(self, "Regenerated latest commitment update with {} update_adds, {} update_fulfills, {} update_fails, and {} update_fail_malformeds", update_add_htlcs.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len(), update_fail_malformed_htlcs.len()); msgs::CommitmentUpdate { - update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs, + update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs, update_add_dlcs, update_countersign_dlcs, update_fee: None, commitment_signed: self.send_commitment_no_state_update().expect("It looks like we failed to re-generate a commitment_signed we had previously sent?").0, } @@ -2761,7 +2949,7 @@ impl Channel { return Err(ChannelError::Close("Peer sent shutdown pre-funding generation")); } for htlc in self.pending_inbound_htlcs.iter() { - if let InboundHTLCState::RemoteAnnounced(_) = htlc.state { + if let InboundHTLCState::RemoteAnnounced(_) = htlc.state() { return Err(ChannelError::Close("Got shutdown with remote pending HTLCs")); } } @@ -3571,14 +3759,14 @@ impl Channel { return Ok(None); } - self.pending_outbound_htlcs.push(OutboundHTLCOutput { + self.pending_outbound_htlcs.push(Box::new(OutboundHTLCOutput { htlc_id: self.next_local_htlc_id, amount_msat: amount_msat, payment_hash: payment_hash.clone(), cltv_expiry: cltv_expiry, state: OutboundHTLCState::LocalAnnounced(Box::new(onion_routing_packet.clone())), source, - }); + })); let res = msgs::UpdateAddHTLC { channel_id: self.channel_id, @@ -3612,13 +3800,13 @@ impl Channel { } let mut have_updates = self.pending_update_fee.is_some(); for htlc in self.pending_outbound_htlcs.iter() { - if let OutboundHTLCState::LocalAnnounced(_) = htlc.state { + if let OutboundHTLCState::LocalAnnounced(_) = htlc.state() { have_updates = true; } if have_updates { break; } } for htlc in self.pending_inbound_htlcs.iter() { - if let InboundHTLCState::LocalRemoved(_) = htlc.state { + if let InboundHTLCState::LocalRemoved(_) = htlc.state() { have_updates = true; } if have_updates { break; } @@ -3634,18 +3822,18 @@ impl Channel { // 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() { - let new_state = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref forward_info) = &htlc.state { + 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; + htlc.update_state(state); } } for htlc in self.pending_outbound_htlcs.iter_mut() { - if let Some(fail_reason) = if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut fail_reason) = &mut htlc.state { + if let Some(fail_reason) = if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut fail_reason) = &mut htlc.mut_state() { Some(fail_reason.take()) } else { None } { - htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(fail_reason); + htlc.update_state(OutboundHTLCState::AwaitingRemovedRemoteRevoke(fail_reason)); } } self.resend_order = RAACommitmentOrder::RevokeAndACKFirst; @@ -3739,7 +3927,7 @@ impl Channel { /// holding cell HTLCs for payment failure. pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<(HTLCSource, PaymentHash)>), APIError> { for htlc in self.pending_outbound_htlcs.iter() { - if let OutboundHTLCState::LocalAnnounced(_) = htlc.state { + if let OutboundHTLCState::LocalAnnounced(_) = htlc.state() { return Err(APIError::APIMisuseError{err: "Cannot begin shutdown with pending HTLCs. Process pending events first"}); } } @@ -3885,67 +4073,23 @@ impl Writeable for Channel { let mut dropped_inbound_htlcs = 0; for htlc in self.pending_inbound_htlcs.iter() { - if let InboundHTLCState::RemoteAnnounced(_) = htlc.state { + if let InboundHTLCState::RemoteAnnounced(_) = htlc.state() { dropped_inbound_htlcs += 1; } } (self.pending_inbound_htlcs.len() as u64 - dropped_inbound_htlcs).write(writer)?; for htlc in self.pending_inbound_htlcs.iter() { - if let &InboundHTLCState::RemoteAnnounced(_) = &htlc.state { + if let &InboundHTLCState::RemoteAnnounced(_) = &htlc.state() { continue; // Drop } - htlc.htlc_id.write(writer)?; - htlc.amount_msat.write(writer)?; - htlc.cltv_expiry.write(writer)?; - htlc.payment_hash.write(writer)?; - match &htlc.state { - &InboundHTLCState::RemoteAnnounced(_) => unreachable!(), - &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_state) => { - 1u8.write(writer)?; - htlc_state.write(writer)?; - }, - &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(ref htlc_state) => { - 2u8.write(writer)?; - htlc_state.write(writer)?; - }, - &InboundHTLCState::Committed => { - 3u8.write(writer)?; - }, - &InboundHTLCState::LocalRemoved(ref removal_reason) => { - 4u8.write(writer)?; - removal_reason.write(writer)?; - }, - } + //XXX + //htlc.write(writer)?; } (self.pending_outbound_htlcs.len() as u64).write(writer)?; for htlc in self.pending_outbound_htlcs.iter() { - htlc.htlc_id.write(writer)?; - htlc.amount_msat.write(writer)?; - htlc.cltv_expiry.write(writer)?; - htlc.payment_hash.write(writer)?; - htlc.source.write(writer)?; - match &htlc.state { - &OutboundHTLCState::LocalAnnounced(ref onion_packet) => { - 0u8.write(writer)?; - onion_packet.write(writer)?; - }, - &OutboundHTLCState::Committed => { - 1u8.write(writer)?; - }, - &OutboundHTLCState::RemoteRemoved(ref fail_reason) => { - 2u8.write(writer)?; - fail_reason.write(writer)?; - }, - &OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref fail_reason) => { - 3u8.write(writer)?; - fail_reason.write(writer)?; - }, - &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref fail_reason) => { - 4u8.write(writer)?; - fail_reason.write(writer)?; - }, - } + //XXX + //htlc.write(writer)?; } (self.holding_cell_htlc_updates.len() as u64).write(writer)?; @@ -4074,39 +4218,17 @@ impl ReadableArgs> for Channel::read(reader)? { - 1 => InboundHTLCState::AwaitingRemoteRevokeToAnnounce(Readable::read(reader)?), - 2 => InboundHTLCState::AwaitingAnnouncedRemoteRevoke(Readable::read(reader)?), - 3 => InboundHTLCState::Committed, - 4 => InboundHTLCState::LocalRemoved(Readable::read(reader)?), - _ => return Err(DecodeError::InvalidValue), - }, - }); + //XXX + //let htlc = Readable::read(reader)?; + //pending_inbound_htlcs.push(htlc); } let pending_outbound_htlc_count: u64 = Readable::read(reader)?; let mut pending_outbound_htlcs = Vec::with_capacity(cmp::min(pending_outbound_htlc_count as usize, OUR_MAX_HTLCS as usize)); for _ in 0..pending_outbound_htlc_count { - pending_outbound_htlcs.push(OutboundHTLCOutput { - htlc_id: Readable::read(reader)?, - amount_msat: Readable::read(reader)?, - cltv_expiry: Readable::read(reader)?, - payment_hash: Readable::read(reader)?, - source: Readable::read(reader)?, - state: match ::read(reader)? { - 0 => OutboundHTLCState::LocalAnnounced(Box::new(Readable::read(reader)?)), - 1 => OutboundHTLCState::Committed, - 2 => OutboundHTLCState::RemoteRemoved(Readable::read(reader)?), - 3 => OutboundHTLCState::AwaitingRemoteRevokeToRemove(Readable::read(reader)?), - 4 => OutboundHTLCState::AwaitingRemovedRemoteRevoke(Readable::read(reader)?), - _ => return Err(DecodeError::InvalidValue), - }, - }); + //XXX + //let htlc = Readable::read(reader)?; + //pending_outbound_htlcs.push(htlc); } let holding_cell_htlc_update_count: u64 = Readable::read(reader)?; diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index bbb7ea300a5..143acd0904e 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -101,6 +101,7 @@ pub(super) enum HTLCFailureMsg { pub(super) enum PendingHTLCStatus { Forward(PendingHTLCInfo), Fail(HTLCFailureMsg), + Dummy, //non-routed payload (aka DLC) } pub(super) enum HTLCForwardInfo { @@ -1283,6 +1284,8 @@ impl ChannelMan update_fulfill_htlcs: Vec::new(), update_fail_htlcs: Vec::new(), update_fail_malformed_htlcs: Vec::new(), + update_add_dlcs: Vec::new(), + update_countersign_dlcs: Vec::new(), update_fee: None, commitment_signed, }, @@ -1673,6 +1676,8 @@ impl ChannelMan update_fulfill_htlcs: Vec::new(), update_fail_htlcs: fail_htlc_msgs, update_fail_malformed_htlcs: Vec::new(), + update_add_dlcs: Vec::new(), + update_countersign_dlcs: Vec::new(), update_fee: None, commitment_signed: commitment_msg, }, @@ -2050,6 +2055,8 @@ impl ChannelMan update_fulfill_htlcs: vec![msg], update_fail_htlcs: Vec::new(), update_fail_malformed_htlcs: Vec::new(), + update_add_dlcs: Vec::new(), + update_countersign_dlcs: Vec::new(), update_fee: None, commitment_signed, } @@ -2571,6 +2578,29 @@ impl ChannelMan } } + fn internal_update_add_dlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateAddDLC) -> Result<(), MsgHandleErrInternal> { + let mut channel_lock = self.channel_state.lock().unwrap(); + let channel_state = &mut *channel_lock; + match channel_state.by_id.entry(msg.channel_id) { + hash_map::Entry::Occupied(mut chan) => { + if chan.get().get_their_node_id() != *their_node_id { + return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!", msg.channel_id)); + } + try_chan_entry!(self, chan.get_mut().update_add_dlc(&msg, PendingHTLCStatus::Dummy), channel_state, chan); + }, + hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel", msg.channel_id)) + } + Ok(()) + } + + fn internal_update_countersign_dlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateCounterSignDLC) -> Result<(), MsgHandleErrInternal> { + Ok(()) + } + + fn internal_update_fulfill_dlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFulfillDLC) -> Result<(), MsgHandleErrInternal> { + Ok(()) + } + fn internal_commitment_signed(&self, their_node_id: &PublicKey, msg: &msgs::CommitmentSigned) -> Result<(), MsgHandleErrInternal> { let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_state_lock; @@ -2606,6 +2636,8 @@ impl ChannelMan update_fulfill_htlcs: Vec::new(), update_fail_htlcs: Vec::new(), update_fail_malformed_htlcs: Vec::new(), + update_add_dlcs: Vec::new(), + update_countersign_dlcs: Vec::new(), update_fee: None, commitment_signed: msg, }, @@ -2869,6 +2901,8 @@ impl ChannelMan update_fulfill_htlcs: Vec::new(), update_fail_htlcs: Vec::new(), update_fail_malformed_htlcs: Vec::new(), + update_add_dlcs: Vec::new(), + update_countersign_dlcs: Vec::new(), update_fee: Some(update_fee), commitment_signed, }, @@ -3175,6 +3209,21 @@ impl { + 2u8.write(writer)?; + } } Ok(()) } @@ -3436,6 +3488,7 @@ impl Readable for PendingHTLCStatus { match ::read(reader)? { 0 => Ok(PendingHTLCStatus::Forward(Readable::read(reader)?)), 1 => Ok(PendingHTLCStatus::Fail(Readable::read(reader)?)), + 2 => Ok(PendingHTLCStatus::Dummy), _ => Err(DecodeError::InvalidValue), } } diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index af498958311..549b723c990 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -7685,3 +7685,59 @@ fn test_update_err_monitor_lockdown() { let events = nodes[0].node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); } + +#[test] +fn test_send_dlc() { + // Create a channel and send a basic DLC through the following flow + // + // update_add_dlc + // -------------------------------> + // + // update_countersign_dlc + // <------------------------------- + // + // commitment_signed (+cet_sigs) + // -------------------------------> + // + // update_countersign_dlc + // -------------------------------> + // + // revoke_and_ack + // <------------------------------- + // + // commitment_signed (+cet_sigs) + // <------------------------------- + // + // revoke_and_ack + // -------------------------------> + // + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]); + let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); + create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::nown()); + // Create a dlc payload on Alice + let dlc_offer = make_dummy_dlc(); + let mut dlc_event = nodes[0].node.send_dlc(dlc_offer).unwrap(); + + // Bob receives dlc payload + nodes[1].node.handle_update_add_dlc(&nodes[1].node.get_our_node_id(), &dlc_event.msgs[0]); + let mut bob_events = nodes[1].node.get_and_clear_pending_msg_events(); + + // Alice receives dlc counter-sig and sends back commitment_signed + counter_sig + nodes[0].node.handle_update_countersign_dlc(&nodes[1].node.get_our_node_id(), &bob_event.msgs[0]); + //XXX fetch oracle ? + + nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &alice_events.msg[0]); + nodes[1].node.handle_update_countersign_dlc(&nodes[0].node.get_our_node_id(), &alice_events.msgs[0]); + + // Bob sends back revoke_and_ack+commitment_signed + nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bob_revoke_and_ack); + nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bob_cs); + + // Alice sends back her revoke_and_ack + nodes[1].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &alice_revoke_and_ack); + + + //XXX add events fetching accordingly +} diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 43005ad1d65..8eed3d70520 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -200,6 +200,33 @@ pub struct UpdateFailMalformedHTLC { pub(crate) failure_code: u16, } +/// An update_add_dlc message to be sent or received from a peer +#[derive(Clone, PartialEq)] +pub struct UpdateAddDLC { + pub(crate) channel_id: [u8; 32], + pub(crate) event_id: u64, + pub(crate) amount_msat: u64, + pub(crate) payment_hash: PaymentHash, + pub(crate) maturity: u32, + pub(crate) cet_sigs: Vec, +} + +/// An update_countersign_dlc message to be sent or received from a peer +#[derive(Clone, PartialEq)] +pub struct UpdateCounterSignDLC { + pub(crate) channel_id: [u8; 32], + pub(crate) event_id: u64, + pub(crate) cet_sigs: Vec +} + +/// An update_fulfill_dlc message to be sent or received from a peer +#[derive(Clone, PartialEq)] +pub struct UpdateFulfillDLC { + pub(crate) channel_id: [u8; 32], + pub(crate) event_id: u64, + pub(crate) oracle_sig: u64, +} + /// A commitment_signed message to be sent or received from a peer #[derive(Clone, PartialEq)] pub struct CommitmentSigned { @@ -479,6 +506,10 @@ pub struct CommitmentUpdate { pub update_fail_htlcs: Vec, /// update_fail_malformed_htlc messages which should be sent pub update_fail_malformed_htlcs: Vec, + /// update_add_dlc messages which should be sent + pub update_add_dlcs: Vec, + /// update_countersign_dlc messages which should be sent + pub update_countersign_dlcs: Vec, /// An update_fee message which should be sent pub update_fee: Option, /// Finally, the commitment_signed message which should be sent @@ -558,6 +589,12 @@ pub trait ChannelMessageHandler : events::MessageSendEventsProvider + Send + Syn fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailHTLC); /// Handle an incoming update_fail_malformed_htlc message from the given peer. fn handle_update_fail_malformed_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailMalformedHTLC); + /// Handle an incoming update_add_dlc message from the given peer. + fn handle_update_add_dlc(&self, their_node_id: &PublicKey, msg: &UpdateAddDLC); + /// Handle an incoming update_countersign_dlc message from the given peer. + fn handle_update_countersign_dlc(&self, their_node_id: &PublicKey, msg: &UpdateCounterSignDLC); + /// Handle an incoming update_fulfill_dlc message from the given peer. + fn handle_update_fulfill_dlc(&self, their_node_id: &PublicKey, msg: &UpdateFulfillDLC); /// Handle an incoming commitment_signed message from the given peer. fn handle_commitment_signed(&self, their_node_id: &PublicKey, msg: &CommitmentSigned); /// Handle an incoming revoke_and_ack message from the given peer. @@ -931,6 +968,27 @@ impl_writeable!(UpdateFulfillHTLC, 32+8+32, { payment_preimage }); +impl_writeable!(UpdateAddDLC, 32+8+288, { + channel_id, + event_id, + amount_msat, + payment_hash, + maturity, + cet_sigs +}); + +impl_writeable!(UpdateCounterSignDLC, 32+8+72, { + channel_id, + event_id, + cet_sigs +}); + +impl_writeable!(UpdateFulfillDLC, 32+8+72, { + channel_id, + event_id, + oracle_sig +}); + impl_writeable_len_match!(OnionErrorPacket, { { OnionErrorPacket { ref data, .. }, 2 + data.len() } }, { diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 36c9bf5e9ac..bd5adf40d25 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -766,7 +766,15 @@ impl PeerManager where // TODO: forward msg along to all our other peers! } }, - + wire::Message::UpdateAddDLC(msg) => { + self.message_handler.chan_handler.handle_update_add_dlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateCounterSignDLC(msg) => { + self.message_handler.chan_handler.handle_update_countersign_dlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFulfillDLC(msg) => { + self.message_handler.chan_handler.handle_update_fulfill_dlc(&peer.their_node_id.unwrap(), &msg); + }, // Unknown messages: wire::Message::Unknown(msg_type) if msg_type.is_even() => { log_debug!(self, "Received unknown even message of type {}, disconnecting peer!", msg_type); @@ -896,7 +904,7 @@ impl PeerManager where peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); self.do_attempt_write_data(&mut descriptor, peer); }, - MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed, ref update_add_dlcs, ref update_countersign_dlcs } } => { log_trace!(self, "Handling UpdateHTLCs event in peer_handler for node {} with {} adds, {} fulfills, {} fails for channel {}", log_pubkey!(node_id), update_add_htlcs.len(), diff --git a/lightning/src/ln/wire.rs b/lightning/src/ln/wire.rs index 15a218060e6..adb1dc59e00 100644 --- a/lightning/src/ln/wire.rs +++ b/lightning/src/ln/wire.rs @@ -38,6 +38,9 @@ pub enum Message { UpdateFulfillHTLC(msgs::UpdateFulfillHTLC), UpdateFailHTLC(msgs::UpdateFailHTLC), UpdateFailMalformedHTLC(msgs::UpdateFailMalformedHTLC), + UpdateAddDLC(msgs::UpdateAddDLC), + UpdateCounterSignDLC(msgs::UpdateCounterSignDLC), + UpdateFulfillDLC(msgs::UpdateFulfillDLC), CommitmentSigned(msgs::CommitmentSigned), RevokeAndACK(msgs::RevokeAndACK), UpdateFee(msgs::UpdateFee), @@ -73,6 +76,9 @@ impl Message { &Message::UpdateFulfillHTLC(ref msg) => msg.type_id(), &Message::UpdateFailHTLC(ref msg) => msg.type_id(), &Message::UpdateFailMalformedHTLC(ref msg) => msg.type_id(), + &Message::UpdateAddDLC(ref msg) => msg.type_id(), + &Message::UpdateCounterSignDLC(ref msg) => msg.type_id(), + &Message::UpdateFulfillDLC(ref msg) => msg.type_id(), &Message::CommitmentSigned(ref msg) => msg.type_id(), &Message::RevokeAndACK(ref msg) => msg.type_id(), &Message::UpdateFee(ref msg) => msg.type_id(), @@ -153,6 +159,15 @@ pub fn read(buffer: &mut R) -> Result { Ok(Message::UpdateFailMalformedHTLC(Readable::read(buffer)?)) }, + msgs::UpdateAddDLC::TYPE => { + Ok(Message::UpdateAddDLC(Readable::read(buffer)?)) + }, + msgs::UpdateCounterSignDLC::TYPE => { + Ok(Message::UpdateCounterSignDLC(Readable::read(buffer)?)) + }, + msgs::UpdateFulfillDLC::TYPE => { + Ok(Message::UpdateFulfillDLC(Readable::read(buffer)?)) + }, msgs::CommitmentSigned::TYPE => { Ok(Message::CommitmentSigned(Readable::read(buffer)?)) }, @@ -271,6 +286,18 @@ impl Encode for msgs::UpdateFailMalformedHTLC { const TYPE: u16 = 135; } +impl Encode for msgs::UpdateAddDLC { + const TYPE: u16 = 0xeffe; +} + +impl Encode for msgs::UpdateCounterSignDLC { + const TYPE: u16 = 0xfeef; +} + +impl Encode for msgs::UpdateFulfillDLC { + const TYPE: u16 = 0xfefe; +} + impl Encode for msgs::CommitmentSigned { const TYPE: u16 = 132; } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 6a652aa6b39..4b6f3bfecc7 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -151,6 +151,9 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler { fn handle_update_fulfill_htlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateFulfillHTLC) {} fn handle_update_fail_htlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateFailHTLC) {} fn handle_update_fail_malformed_htlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateFailMalformedHTLC) {} + fn handle_update_add_dlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateAddDLC) {} + fn handle_update_countersign_dlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateCounterSignDLC) {} + fn handle_update_fulfill_dlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateFulfillDLC) {} fn handle_commitment_signed(&self, _their_node_id: &PublicKey, _msg: &msgs::CommitmentSigned) {} fn handle_revoke_and_ack(&self, _their_node_id: &PublicKey, _msg: &msgs::RevokeAndACK) {} fn handle_update_fee(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateFee) {}