use crypto::hkdf::{hkdf_extract,hkdf_expand};
use ln::msgs;
-use ln::msgs::{ErrorAction, HandleError, MsgEncodable};
+use ln::msgs::{ErrorAction, HandleError};
use ln::channelmonitor::ChannelMonitor;
-use ln::channelmanager::{PendingHTLCStatus, PendingForwardHTLCInfo, HTLCFailReason, HTLCFailureMsg};
+use ln::channelmanager::{PendingHTLCStatus, HTLCSource, PendingForwardHTLCInfo, HTLCFailReason, HTLCFailureMsg};
use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
use ln::chan_utils;
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
use chain::transaction::OutPoint;
use util::{transaction_utils,rng};
+use util::ser::Writeable;
use util::sha2::Sha256;
use util::logger::Logger;
use util::errors::APIError;
cltv_expiry: u32,
payment_hash: [u8; 32],
state: OutboundHTLCState,
+ source: HTLCSource,
/// If we're in a removed state, set if they failed, otherwise None
fail_reason: Option<HTLCFailReason>,
}
amount_msat: u64,
cltv_expiry: u32,
payment_hash: [u8; 32],
+ source: HTLCSource,
onion_routing_packet: msgs::OnionPacket,
time_created: Instant, //TODO: Some kind of timeout thing-a-majig
},
ClaimHTLC {
payment_preimage: [u8; 32],
- payment_hash: [u8; 32], // Only here for effecient duplicate detection
+ htlc_id: u64,
},
FailHTLC {
- payment_hash: [u8; 32],
+ htlc_id: u64,
err_packet: msgs::OnionErrorPacket,
},
}
+/// There are a few "states" and then a number of flags which can be applied:
+/// We first move through init with OurInitSent -> TheirInitSent -> FundingCreated -> FundingSent.
+/// TheirFundingLocked and OurFundingLocked then get set on FundingSent, and when both are set we
+/// move on to ChannelFunded.
+/// Note that PeerDisconnected can be set on both ChannelFunded and FundingSent.
+/// ChannelFunded can then get all remaining flags set on it, until we finish shutdown, then we
+/// move on to ShutdownComplete, at which point most calls into this channel are disallowed.
enum ChannelState {
/// Implies we have (or are prepared to) send our open_channel/accept_channel message
OurInitSent = (1 << 0),
/// Once both TheirFundingLocked and OurFundingLocked are set, state moves on to ChannelFunded.
OurFundingLocked = (1 << 5),
ChannelFunded = 64,
+ /// Flag which is set on ChannelFunded and FundingSent indicating remote side is considered
+ /// "disconnected" and no updates are allowed until after we've done a channel_reestablish
+ /// dance.
+ PeerDisconnected = (1 << 7),
/// Flag which implies that we have sent a commitment_signed but are awaiting the responding
/// revoke_and_ack message. During this time period, we can't generate new commitment_signed
/// messages as then we will be unable to determine which HTLCs they included in their
/// revoke_and_ack implicit ACK, so instead we have to hold them away temporarily to be sent
/// later.
/// Flag is set on ChannelFunded.
- AwaitingRemoteRevoke = (1 << 7),
+ AwaitingRemoteRevoke = (1 << 8),
/// Flag which is set on ChannelFunded or FundingSent after receiving a shutdown message from
/// the remote end. If set, they may not add any new HTLCs to the channel, and we are expected
/// to respond with our own shutdown message when possible.
- RemoteShutdownSent = (1 << 8),
+ RemoteShutdownSent = (1 << 9),
/// Flag which is set on ChannelFunded or FundingSent after sending a shutdown message. At this
/// point, we may not add any new HTLCs to the channel.
/// TODO: Investigate some kind of timeout mechanism by which point the remote end must provide
/// us their shutdown.
- LocalShutdownSent = (1 << 9),
+ LocalShutdownSent = (1 << 10),
/// We've successfully negotiated a closing_signed dance. At this point ChannelManager is about
/// to drop us, but we store this anyway.
- ShutdownComplete = (1 << 10),
+ ShutdownComplete = 2048,
}
const BOTH_SIDES_SHUTDOWN_MASK: u32 = (ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32);
+const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
+
// TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
// has been completed, and then turn into a Channel to get compiler-time enforcement of things like
// calling channel_id() before we're set up or things like get_outbound_funding_signed on an
// inbound channel.
-pub struct Channel {
+pub(super) struct Channel {
user_id: u64,
channel_id: [u8; 32],
channel_value_satoshis: channel_value_satoshis,
local_keys: chan_keys,
- cur_local_commitment_transaction_number: (1 << 48) - 1,
- cur_remote_commitment_transaction_number: (1 << 48) - 1,
+ cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
+ cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat: channel_value_satoshis * 1000 - push_msat,
pending_inbound_htlcs: Vec::new(),
pending_outbound_htlcs: Vec::new(),
&PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key),
&chan_keys.htlc_base_key,
BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script);
- channel_monitor.set_their_htlc_base_key(&msg.htlc_basepoint);
+ channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
channel_monitor.set_their_to_self_delay(msg.to_self_delay);
let mut chan = Channel {
announce_publicly: their_announce,
local_keys: chan_keys,
- cur_local_commitment_transaction_number: (1 << 48) - 1,
- cur_remote_commitment_transaction_number: (1 << 48) - 1,
+ cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
+ cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER,
value_to_self_msat: msg.push_msat,
pending_inbound_htlcs: Vec::new(),
pending_outbound_htlcs: Vec::new(),
/// which peer generated this transaction and "to whom" this transaction flows.
#[inline]
fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool) -> (Transaction, Vec<HTLCOutputInCommitment>) {
- let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (0xffffffffffff - commitment_number);
+ let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
let txins = {
let mut ins: Vec<TxIn> = Vec::new();
Ok(our_sig)
}
- fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result<(Option<msgs::UpdateFulfillHTLC>, Option<ChannelMonitor>), HandleError> {
+ /// May return an IgnoreError, but should not, and will always return Ok(_) when
+ /// debug_assertions are turned on
+ fn get_update_fulfill_htlc(&mut self, htlc_id_arg: u64, payment_preimage_arg: [u8; 32]) -> Result<(Option<msgs::UpdateFulfillHTLC>, Option<ChannelMonitor>), HandleError> {
// Either ChannelFunded got set (which means it wont bet unset) or there is no way any
// caller thought we could have something claimed (cause we wouldn't have accepted in an
// incoming HTLC anyway). If we got to ShutdownComplete, callers aren't allowed to call us,
let mut pending_idx = std::usize::MAX;
for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() {
- if htlc.payment_hash == payment_hash_calc &&
- htlc.state != InboundHTLCState::LocalRemoved {
- if let Some(PendingHTLCStatus::Fail(_)) = htlc.pending_forward_state {
- } else {
- if pending_idx != std::usize::MAX {
- panic!("Duplicate HTLC payment_hash, ChannelManager should have prevented this!");
- }
- pending_idx = idx;
+ if htlc.htlc_id == htlc_id_arg {
+ assert_eq!(htlc.payment_hash, payment_hash_calc);
+ if htlc.state != InboundHTLCState::Committed {
+ 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
}
+ pending_idx = idx;
+ break;
}
}
if pending_idx == std::usize::MAX {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+ debug_assert!(false, "Unable to find a pending HTLC which matched the given HTLC ID");
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given HTLC ID", action: Some(msgs::ErrorAction::IgnoreError)});
}
// Now update local state:
// can claim it even if the channel hits the chain before we see their next commitment.
self.channel_monitor.provide_payment_preimage(&payment_hash_calc, &payment_preimage_arg);
- if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
+ if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::PeerDisconnected as u32)) != 0 {
for pending_update in self.holding_cell_htlc_updates.iter() {
match pending_update {
- &HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, .. } => {
- if payment_preimage_arg == *payment_preimage {
+ &HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
+ if htlc_id_arg == htlc_id {
+ debug_assert!(false, "Tried to fulfill an HTLC we already had a pending fulfill for");
return Ok((None, None));
}
},
- &HTLCUpdateAwaitingACK::FailHTLC { ref payment_hash, .. } => {
- if payment_hash_calc == *payment_hash {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+ &HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
+ if htlc_id_arg == htlc_id {
+ debug_assert!(false, "Tried to fulfill an HTLC we already had a holding-cell failure on");
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given HTLC ID", action: Some(msgs::ErrorAction::IgnoreError)});
}
},
_ => {}
}
}
self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::ClaimHTLC {
- payment_preimage: payment_preimage_arg, payment_hash: payment_hash_calc,
+ payment_preimage: payment_preimage_arg, htlc_id: htlc_id_arg,
});
return Ok((None, Some(self.channel_monitor.clone())));
}
- let htlc_id = {
+ {
let htlc = &mut self.pending_inbound_htlcs[pending_idx];
- if htlc.state == InboundHTLCState::Committed {
- htlc.state = InboundHTLCState::LocalRemoved;
- htlc.local_removed_fulfilled = true;
- } else if htlc.state == InboundHTLCState::RemoteAnnounced || htlc.state == InboundHTLCState::AwaitingRemoteRevokeToAnnounce || htlc.state == InboundHTLCState::AwaitingAnnouncedRemoteRevoke {
- // Theoretically we can hit this if we get the preimage on an HTLC prior to us
- // having forwarded it to anyone. This implies that the sender is busted as someone
- // else knows the preimage, but handling this case and implementing the logic to
- // take their money would be a lot of (never-tested) code to handle a case that
- // hopefully never happens. Instead, we make sure we get the preimage into the
- // channel_monitor and pretend we didn't just see the preimage.
+ if htlc.state != InboundHTLCState::Committed {
+ 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())));
- } else {
- // LocalRemoved handled in the search loop
- panic!("Have an inbound HTLC when not awaiting remote revoke that had a garbage state");
}
- htlc.htlc_id
- };
+ htlc.state = InboundHTLCState::LocalRemoved;
+ htlc.local_removed_fulfilled = true;
+ }
Ok((Some(msgs::UpdateFulfillHTLC {
channel_id: self.channel_id(),
- htlc_id: htlc_id,
+ htlc_id: htlc_id_arg,
payment_preimage: payment_preimage_arg,
}), Some(self.channel_monitor.clone())))
}
- pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result<(Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)>, Option<ChannelMonitor>), HandleError> {
- match self.get_update_fulfill_htlc(payment_preimage)? {
+ pub fn get_update_fulfill_htlc_and_commit(&mut self, htlc_id: u64, payment_preimage: [u8; 32]) -> Result<(Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)>, Option<ChannelMonitor>), HandleError> {
+ match self.get_update_fulfill_htlc(htlc_id, payment_preimage)? {
(Some(update_fulfill_htlc), _) => {
let (commitment, monitor_update) = self.send_commitment_no_status_check()?;
Ok((Some((update_fulfill_htlc, commitment)), Some(monitor_update)))
}
}
- pub fn get_update_fail_htlc(&mut self, payment_hash_arg: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result<Option<msgs::UpdateFailHTLC>, HandleError> {
+ /// May return an IgnoreError, but should not, and will always return Ok(_) when
+ /// debug_assertions are turned on
+ pub fn get_update_fail_htlc(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket) -> Result<Option<msgs::UpdateFailHTLC>, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
panic!("Was asked to fail an HTLC when channel was not in an operational state");
}
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+ 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 {
+ 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)});
+ }
+ pending_idx = idx;
+ }
+ }
+ if pending_idx == std::usize::MAX {
+ debug_assert!(false, "Unable to find a pending HTLC which matched the given HTLC ID");
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given HTLC ID", action: Some(msgs::ErrorAction::IgnoreError)});
+ }
+
// Now update local state:
- if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
+ if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::PeerDisconnected as u32)) != 0 {
for pending_update in self.holding_cell_htlc_updates.iter() {
match pending_update {
- &HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_hash, .. } => {
- if *payment_hash_arg == *payment_hash {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+ &HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
+ if htlc_id_arg == htlc_id {
+ debug_assert!(false, "Unable to find a pending HTLC which matched the given HTLC ID");
+ return Err(HandleError{err: "Unable to find a pending HTLC which matched the given HTLC ID", action: Some(msgs::ErrorAction::IgnoreError)});
}
},
- &HTLCUpdateAwaitingACK::FailHTLC { ref payment_hash, .. } => {
- if *payment_hash_arg == *payment_hash {
+ &HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
+ if htlc_id_arg == htlc_id {
+ debug_assert!(false, "Tried to fail an HTLC that we already had a pending failure for");
return Ok(None);
}
},
}
}
self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::FailHTLC {
- payment_hash: payment_hash_arg.clone(),
+ htlc_id: htlc_id_arg,
err_packet,
});
return Ok(None);
}
- let mut htlc_id = 0;
- let mut htlc_amount_msat = 0;
- for htlc in self.pending_inbound_htlcs.iter_mut() {
- if htlc.payment_hash == *payment_hash_arg {
- if htlc.state == InboundHTLCState::Committed {
- htlc.state = InboundHTLCState::LocalRemoved;
- } else if htlc.state == InboundHTLCState::RemoteAnnounced {
- if let Some(PendingHTLCStatus::Forward(_)) = htlc.pending_forward_state {
- panic!("Somehow forwarded HTLC prior to remote revocation!");
- } else {
- // We have to pretend this isn't here - we're probably a duplicate with the
- // same payment_hash as some other HTLC, and the other is getting failed,
- // we'll fail this one as soon as remote commits to it.
- continue;
- }
- } else if htlc.state == InboundHTLCState::LocalRemoved {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
- } else {
- panic!("Have an inbound HTLC when not awaiting remote revoke that had a garbage state");
- }
- if htlc_id != 0 {
- panic!("Duplicate HTLC payment_hash, you probably re-used payment preimages, NEVER DO THIS!");
- }
- htlc_id = htlc.htlc_id;
- htlc_amount_msat += htlc.amount_msat;
- }
- }
- if htlc_amount_msat == 0 {
- return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+ {
+ let htlc = &mut self.pending_inbound_htlcs[pending_idx];
+ htlc.state = InboundHTLCState::LocalRemoved;
+ htlc.local_removed_fulfilled = false;
}
Ok(Some(msgs::UpdateFailHTLC {
channel_id: self.channel_id(),
- htlc_id,
+ htlc_id: htlc_id_arg,
reason: err_packet
}))
}
- pub fn get_update_fail_htlc_and_commit(&mut self, payment_hash: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result<Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
- match self.get_update_fail_htlc(payment_hash, err_packet)? {
+ pub fn get_update_fail_htlc_and_commit(&mut self, htlc_id: u64, err_packet: msgs::OnionErrorPacket) -> Result<Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
+ match self.get_update_fail_htlc(htlc_id, err_packet)? {
Some(update_fail_htlc) => {
let (commitment, monitor_update) = self.send_commitment_no_status_check()?;
Ok(Some((update_fail_htlc, commitment, monitor_update)))
// max_accepted_htlcs too small
// dust_limit_satoshis too small
- self.channel_monitor.set_their_htlc_base_key(&msg.htlc_basepoint);
+ self.channel_monitor.set_their_base_keys(&msg.htlc_basepoint, &msg.delayed_payment_basepoint);
self.their_dust_limit_satoshis = msg.dust_limit_satoshis;
self.their_max_htlc_value_in_flight_msat = cmp::min(msg.max_htlc_value_in_flight_msat, self.channel_value_satoshis * 1000);
fn funding_created_signature(&mut self, sig: &Signature) -> Result<(Transaction, Signature), HandleError> {
let funding_script = self.get_funding_redeemscript();
- let remote_keys = self.build_remote_transaction_keys()?;
- let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false).0;
- let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
-
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false).0;
let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
// They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish.
secp_call!(self.secp_ctx.verify(&local_sighash, &sig, &self.their_funding_pubkey.unwrap()), "Invalid funding_created signature from peer", self.channel_id());
+ let remote_keys = self.build_remote_transaction_keys()?;
+ let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false).0;
+ let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
+
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
Ok((remote_initial_commitment_tx, self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key)))
}
// channel.
return Err(HandleError{err: "Received funding_created after we got the channel!", action: Some(msgs::ErrorAction::SendErrorMessage {msg: msgs::ErrorMessage {channel_id: self.channel_id, data: "Received funding_created after we got the channel!".to_string()}})});
}
- if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 1 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
+ if self.channel_monitor.get_min_seen_secret() != (1 << 48) ||
+ self.cur_remote_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
+ self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
if self.channel_state != ChannelState::FundingCreated as u32 {
return Err(HandleError{err: "Received funding_signed in strange state!", action: None});
}
- if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 2 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
+ if self.channel_monitor.get_min_seen_secret() != (1 << 48) ||
+ self.cur_remote_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER - 1 ||
+ self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
}
pub fn funding_locked(&mut self, msg: &msgs::FundingLocked) -> Result<(), HandleError> {
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent funding_locked when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent funding_locked when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK);
if non_shutdown_state == ChannelState::FundingSent as u32 {
self.channel_state |= ChannelState::TheirFundingLocked as u32;
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
self.channel_update_count += 1;
+ } else if self.channel_state & (ChannelState::ChannelFunded as u32) != 0 &&
+ // Note that funding_signed/funding_created will have decremented both by 1!
+ self.cur_local_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 &&
+ self.cur_remote_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 {
+ if self.their_cur_commitment_point != Some(msg.next_per_commitment_point) {
+ return Err(HandleError{err: "Peer sent a reconnect funding_locked with a different point", action: None});
+ }
+ // They probably disconnected/reconnected and re-sent the funding_locked, which is required
+ return Ok(());
} else {
return Err(HandleError{err: "Peer sent a funding_locked at a strange time", action: None});
}
if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent update_add_htlc when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent update_add_htlc when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
if msg.amount_msat > self.channel_value_satoshis * 1000 {
return Err(HandleError{err: "Remote side tried to send more than the total value of the channel", action: None});
}
/// Removes an outbound HTLC which has been commitment_signed by the remote end
#[inline]
- fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>, fail_reason: Option<HTLCFailReason>) -> Result<[u8; 32], HandleError> {
+ fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>, fail_reason: Option<HTLCFailReason>) -> Result<&HTLCSource, HandleError> {
for htlc in self.pending_outbound_htlcs.iter_mut() {
if htlc.htlc_id == htlc_id {
match check_preimage {
OutboundHTLCState::AwaitingRemoteRevokeToRemove | OutboundHTLCState::AwaitingRemovedRemoteRevoke | OutboundHTLCState::RemoteRemoved =>
return Err(HandleError{err: "Remote tried to fulfill HTLC that they'd already fulfilled", action: None}),
}
- return Ok(htlc.payment_hash.clone());
+ return Ok(&htlc.source);
}
}
Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", action: None})
}
- pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(), HandleError> {
+ pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<&HTLCSource, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent update_fulfill_htlc when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent update_fulfill_htlc when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
let mut sha = Sha256::new();
sha.input(&msg.payment_preimage);
let mut payment_hash = [0; 32];
sha.result(&mut payment_hash);
- self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)?;
- Ok(())
+ self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)
}
- pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<[u8; 32], HandleError> {
+ pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<&HTLCSource, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent update_fail_htlc when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent update_fail_htlc when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))
}
- pub fn update_fail_malformed_htlc(&mut self, msg: &msgs::UpdateFailMalformedHTLC, fail_reason: HTLCFailReason) -> Result<(), HandleError> {
+ pub fn update_fail_malformed_htlc<'a>(&mut self, msg: &msgs::UpdateFailMalformedHTLC, fail_reason: HTLCFailReason) -> Result<&HTLCSource, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent update_fail_malformed_htlc when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent update_fail_malformed_htlc when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
- self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?;
- Ok(())
+ self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))
}
pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option<msgs::CommitmentSigned>, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got commitment signed message when channel was not in an operational state", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent commitment_signed when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent commitment_signed when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
let funding_script = self.get_funding_redeemscript();
self.holding_cell_htlc_updates.push(htlc_update);
} else {
match &htlc_update {
- &HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, payment_hash, ref onion_routing_packet, ..} => {
- match self.send_htlc(amount_msat, payment_hash, cltv_expiry, onion_routing_packet.clone()) {
+ &HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, payment_hash, ref source, ref onion_routing_packet, ..} => {
+ match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone()) {
Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()),
Err(e) => {
err = Some(e);
}
}
},
- &HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage, .. } => {
- match self.get_update_fulfill_htlc(payment_preimage) {
+ &HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage, htlc_id, .. } => {
+ match self.get_update_fulfill_htlc(htlc_id, payment_preimage) {
Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.0.unwrap()),
Err(e) => {
- err = Some(e);
+ if let Some(msgs::ErrorAction::IgnoreError) = e.action {}
+ else {
+ panic!("Got a non-IgnoreError action trying to fulfill holding cell HTLC");
+ }
}
}
},
- &HTLCUpdateAwaitingACK::FailHTLC { payment_hash, ref err_packet } => {
- match self.get_update_fail_htlc(&payment_hash, err_packet.clone()) {
+ &HTLCUpdateAwaitingACK::FailHTLC { htlc_id, ref err_packet } => {
+ match self.get_update_fail_htlc(htlc_id, err_packet.clone()) {
Ok(update_fail_msg_option) => update_fail_htlcs.push(update_fail_msg_option.unwrap()),
Err(e) => {
- err = Some(e);
+ if let Some(msgs::ErrorAction::IgnoreError) = e.action {}
+ else {
+ panic!("Got a non-IgnoreError action trying to fail holding cell HTLC");
+ }
}
}
},
//fail it back the route, if its a temporary issue we can ignore it...
match err {
None => {
+ if update_add_htlcs.is_empty() && update_fulfill_htlcs.is_empty() && update_fail_htlcs.is_empty() {
+ // This should never actually happen and indicates we got some Errs back
+ // from update_fulfill_htlc/update_fail_htlc, but we handle it anyway in
+ // case there is some strange way to hit duplicate HTLC removes.
+ return Ok(None);
+ }
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?;
Ok(Some((msgs::CommitmentUpdate {
update_add_htlcs,
/// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail,
/// generating an appropriate error *after* the channel state has been updated based on the
/// revoke_and_ack message.
- pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK) -> Result<(Option<msgs::CommitmentUpdate>, Vec<PendingForwardHTLCInfo>, Vec<([u8; 32], HTLCFailReason)>, ChannelMonitor), HandleError> {
+ pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK) -> Result<(Option<msgs::CommitmentUpdate>, Vec<(PendingForwardHTLCInfo, u64)>, Vec<(HTLCSource, [u8; 32], HTLCFailReason)>, ChannelMonitor), HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Got revoke/ACK message when channel was not in an operational state", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent revoke_and_ack when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent revoke_and_ack when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
if let Some(their_prev_commitment_point) = self.their_prev_commitment_point {
if PublicKey::from_secret_key(&self.secp_ctx, &secp_call!(SecretKey::from_slice(&self.secp_ctx, &msg.per_commitment_secret), "Peer provided an invalid per_commitment_secret", self.channel_id())) != their_prev_commitment_point {
return Err(HandleError{err: "Got a revoke commitment secret which didn't correspond to their current pubkey", action: None});
self.pending_outbound_htlcs.retain(|htlc| {
if htlc.state == OutboundHTLCState::AwaitingRemovedRemoteRevoke {
if let Some(reason) = htlc.fail_reason.clone() { // We really want take() here, but, again, non-mut ref :(
- revoked_htlcs.push((htlc.payment_hash, reason));
+ revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
} else {
// They fulfilled, so we sent them money
value_to_self_msat_diff -= htlc.amount_msat as i64;
}
},
PendingHTLCStatus::Forward(forward_info) => {
- to_forward_infos.push(forward_info);
+ to_forward_infos.push((forward_info, htlc.htlc_id));
htlc.state = InboundHTLCState::Committed;
}
}
}
}
+ /// Removes any uncommitted HTLCs, to be used on peer disconnection, including any pending
+ /// HTLCs that we intended to add but haven't as we were waiting on a remote revoke.
+ /// Returns the set of PendingHTLCStatuses from remote uncommitted HTLCs (which we're
+ /// implicitly dropping) and the payment_hashes of HTLCs we tried to add but are dropping.
+ /// No further message handling calls may be made until a channel_reestablish dance has
+ /// completed.
+ pub fn remove_uncommitted_htlcs_and_mark_paused(&mut self) -> Vec<(HTLCSource, [u8; 32])> {
+ let mut outbound_drops = Vec::new();
+
+ assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+ if self.channel_state < ChannelState::FundingSent as u32 {
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ return outbound_drops;
+ }
+
+ let mut inbound_drop_count = 0;
+ self.pending_inbound_htlcs.retain(|htlc| {
+ 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
+ // this HTLC accordingly
+ inbound_drop_count += 1;
+ false
+ },
+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce|InboundHTLCState::AwaitingAnnouncedRemoteRevoke => {
+ // Same goes for AwaitingRemoteRevokeToRemove and AwaitingRemovedRemoteRevoke
+ // 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
+ // 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
+ // the commitment_signed we can re-transmit the update then.
+ true
+ },
+ }
+ });
+
+ for htlc in self.pending_outbound_htlcs.iter_mut() {
+ if htlc.state == OutboundHTLCState::RemoteRemoved {
+ // 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;
+ }
+ }
+
+ self.holding_cell_htlc_updates.retain(|htlc_update| {
+ match htlc_update {
+ &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, .. } => {
+ outbound_drops.push((source.clone(), payment_hash.clone()));
+ false
+ },
+ &HTLCUpdateAwaitingACK::ClaimHTLC {..} | &HTLCUpdateAwaitingACK::FailHTLC {..} => true,
+ }
+ });
+ self.channel_state |= ChannelState::PeerDisconnected as u32;
+ log_debug!(self, "Peer disconnection resulted in {} remote-announced HTLC drops and {} waiting-to-locally-announced HTLC drops on channel {}", outbound_drops.len(), inbound_drop_count, log_bytes!(self.channel_id()));
+ outbound_drops
+ }
+
pub fn update_fee(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::UpdateFee) -> Result<(), HandleError> {
if self.channel_outbound {
return Err(HandleError{err: "Non-funding remote tried to update channel fee", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent update_fee when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent update_fee when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
self.channel_update_count += 1;
self.feerate_per_kw = msg.feerate_per_kw as u64;
Ok(())
}
- pub fn shutdown(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::Shutdown) -> Result<(Option<msgs::Shutdown>, Option<msgs::ClosingSigned>, Vec<[u8; 32]>), HandleError> {
+ /// May panic if some calls other than message-handling calls (which will all Err immediately)
+ /// have been called between remove_uncommitted_htlcs_and_mark_paused and this call.
+ pub fn channel_reestablish(&mut self, msg: &msgs::ChannelReestablish) -> Result<(Option<msgs::FundingLocked>, Option<msgs::RevokeAndACK>, Option<msgs::CommitmentUpdate>, Option<ChannelMonitor>), HandleError> {
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == 0 {
+ return Err(HandleError{err: "Peer sent a loose channel_reestablish not after reconnect", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent a loose channel_reestablish not after reconnect".to_string(), channel_id: msg.channel_id}})});
+ }
+
+ if msg.next_local_commitment_number == 0 || msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER ||
+ msg.next_remote_commitment_number == 0 || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER {
+ return Err(HandleError{err: "Peer send garbage channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer send garbage channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
+
+ // Go ahead and unmark PeerDisconnected as various calls we may make check for it (and all
+ // remaining cases either succeed or ErrorMessage-fail).
+ self.channel_state &= !(ChannelState::PeerDisconnected as u32);
+
+ let mut required_revoke = None;
+ if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number {
+ // Remote isn't waiting on any RevokeAndACK from us!
+ // Note that if we need to repeat our FundingLocked we'll do that in the next if block.
+ } else if msg.next_remote_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_local_commitment_transaction_number {
+ let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number));
+ let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number + 2);
+ required_revoke = Some(msgs::RevokeAndACK {
+ channel_id: self.channel_id,
+ per_commitment_secret,
+ next_per_commitment_point,
+ });
+ } else {
+ return Err(HandleError{err: "Peer attempted to reestablish channel with a very old local commitment transaction", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer attempted to reestablish channel with a very old remote commitment transaction".to_string(), channel_id: msg.channel_id}})});
+ }
+
+ if msg.next_local_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number {
+ if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number {
+ log_debug!(self, "Reconnected channel {} with no lost commitment txn", log_bytes!(self.channel_id()));
+ if msg.next_local_commitment_number == 1 && msg.next_remote_commitment_number == 1 {
+ let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
+ let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret);
+ return Ok((Some(msgs::FundingLocked {
+ channel_id: self.channel_id(),
+ next_per_commitment_point: next_per_commitment_point,
+ }), None, None, None));
+ }
+ }
+
+ if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 {
+ // We're up-to-date and not waiting on a remote revoke (if we are our
+ // channel_reestablish should result in them sending a revoke_and_ack), but we may
+ // have received some updates while we were disconnected. Free the holding cell
+ // now!
+ match self.free_holding_cell_htlcs() {
+ Err(e) => {
+ if let &Some(msgs::ErrorAction::DisconnectPeer{msg: Some(_)}) = &e.action {
+ } else if let &Some(msgs::ErrorAction::SendErrorMessage{msg: _}) = &e.action {
+ } else {
+ panic!("Got non-channel-failing result from free_holding_cell_htlcs");
+ }
+ return Err(e);
+ },
+ Ok(Some((commitment_update, channel_monitor))) => return Ok((None, required_revoke, Some(commitment_update), Some(channel_monitor))),
+ Ok(None) => return Ok((None, required_revoke, None, None)),
+ }
+ } else {
+ return Ok((None, required_revoke, None, None));
+ }
+ } else if msg.next_local_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_remote_commitment_transaction_number {
+ return Ok((None, required_revoke,
+ Some(msgs::CommitmentUpdate {
+ update_add_htlcs: Vec::new(),
+ update_fulfill_htlcs: Vec::new(),
+ update_fail_htlcs: Vec::new(),
+ update_fail_malformed_htlcs: Vec::new(),
+ 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,
+ }), None));
+ } else {
+ return Err(HandleError{err: "Peer attempted to reestablish channel with a very old remote commitment transaction", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer attempted to reestablish channel with a very old remote commitment transaction".to_string(), channel_id: msg.channel_id}})});
+ }
+ }
+
+ pub fn shutdown(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::Shutdown) -> Result<(Option<msgs::Shutdown>, Option<msgs::ClosingSigned>, Vec<(HTLCSource, [u8; 32])>), HandleError> {
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent shutdown when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent shutdown when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
if self.channel_state < ChannelState::FundingSent as u32 {
self.channel_state = ChannelState::ShutdownComplete as u32;
self.channel_update_count += 1;
let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
self.holding_cell_htlc_updates.retain(|htlc_update| {
match htlc_update {
- &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, .. } => {
- dropped_outbound_htlcs.push(payment_hash.clone());
+ &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, .. } => {
+ dropped_outbound_htlcs.push((source.clone(), payment_hash.clone()));
false
},
_ => true
if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != BOTH_SIDES_SHUTDOWN_MASK {
return Err(HandleError{err: "Remote end sent us a closing_signed before both sides provided a shutdown", action: None});
}
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Peer sent closing_signed when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent closing_signed when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})});
+ }
if !self.pending_inbound_htlcs.is_empty() || !self.pending_outbound_htlcs.is_empty() {
return Err(HandleError{err: "Remote end sent us a closing_signed while there were still pending HTLCs", action: None});
}
res as u32
}
+ /// Returns true if we've ever received a message from the remote end for this Channel
+ pub fn have_received_message(&self) -> bool {
+ self.channel_state > (ChannelState::OurInitSent as u32)
+ }
+
/// Returns true if this channel is fully established and not known to be closing.
/// Allowed in any state (including after shutdown)
pub fn is_usable(&self) -> bool {
/// is_usable() and considers things like the channel being temporarily disabled.
/// Allowed in any state (including after shutdown)
pub fn is_live(&self) -> bool {
- self.is_usable()
+ self.is_usable() && (self.channel_state & (ChannelState::PeerDisconnected as u32) == 0)
}
/// Returns true if funding_created was sent/received.
// Methods to get unprompted messages to send to the remote end (or where we already returned
// something in the handler for the message that prompted this message):
- pub fn get_open_channel(&self, chain_hash: Sha256dHash, fee_estimator: &FeeEstimator) -> Result<msgs::OpenChannel, APIError> {
+ pub fn get_open_channel(&self, chain_hash: Sha256dHash, fee_estimator: &FeeEstimator) -> msgs::OpenChannel {
if !self.channel_outbound {
panic!("Tried to open a channel for an inbound channel?");
}
panic!("Cannot generate an open_channel after we've moved forward");
}
- if self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
+ if self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
panic!("Tried to send an open_channel for a channel that has already advanced");
}
let local_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
- Ok(msgs::OpenChannel {
+ msgs::OpenChannel {
chain_hash: chain_hash,
temporary_channel_id: self.channel_id,
funding_satoshis: self.channel_value_satoshis,
first_per_commitment_point: PublicKey::from_secret_key(&self.secp_ctx, &local_commitment_secret),
channel_flags: if self.announce_publicly {1} else {0},
shutdown_scriptpubkey: None,
- })
+ }
}
pub fn get_accept_channel(&self) -> msgs::AcceptChannel {
if self.channel_state != (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32) {
panic!("Tried to send accept_channel after channel had moved forward");
}
- if self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
+ if self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
panic!("Tried to send an accept_channel for a channel that has already advanced");
}
if self.channel_state != (ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32) {
panic!("Tried to get a funding_created messsage at a time other than immediately after initial handshake completion (or tried to get funding_created twice)");
}
- if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 1 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 {
+ if self.channel_monitor.get_min_seen_secret() != (1 << 48) ||
+ self.cur_remote_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER ||
+ self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
Ok((msg, sig))
}
+ /// May panic if called on a channel that wasn't immediately-previously
+ /// self.remove_uncommitted_htlcs_and_mark_paused()'d
+ pub fn get_channel_reestablish(&self) -> msgs::ChannelReestablish {
+ assert_eq!(self.channel_state & ChannelState::PeerDisconnected as u32, ChannelState::PeerDisconnected as u32);
+ msgs::ChannelReestablish {
+ channel_id: self.channel_id(),
+ next_local_commitment_number: INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number,
+ next_remote_commitment_number: INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number,
+ data_loss_protect: None,
+ }
+ }
+
// Send stuff to our remote peers:
/// waiting on the remote peer to send us a revoke_and_ack during which time we cannot add new
/// HTLCs on the wire or we wouldn't be able to determine what they actually ACK'ed.
/// You MUST call send_commitment prior to any other calls on this Channel
- pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result<Option<msgs::UpdateAddHTLC>, HandleError> {
+ pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result<Option<msgs::UpdateAddHTLC>, HandleError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) {
return Err(HandleError{err: "Cannot send HTLC until channel is fully established and we haven't started shutting down", action: None});
}
return Err(HandleError{err: "Cannot send less than their minimum HTLC value", action: None});
}
+ if (self.channel_state & (ChannelState::PeerDisconnected as u32)) == (ChannelState::PeerDisconnected as u32) {
+ // Note that this should never really happen, if we're !is_live() on receipt of an
+ // incoming HTLC for relay will result in us rejecting the HTLC and we won't allow
+ // the user to send directly into a !is_live() channel. However, if we
+ // disconnected during the time the previous hop was doing the commitment dance we may
+ // end up getting here after the forwarding delay. In any case, returning an
+ // IgnoreError will get ChannelManager to do the right thing and fail backwards now.
+ return Err(HandleError{err: "Cannot send an HTLC while disconnected", action: Some(ErrorAction::IgnoreError)});
+ }
+
let (_, outbound_htlc_count, htlc_outbound_value_msat, htlc_inbound_value_msat) = self.get_pending_htlc_stats(false);
if outbound_htlc_count + 1 > self.their_max_accepted_htlcs as u32 {
return Err(HandleError{err: "Cannot push more than their max accepted HTLCs", action: None});
amount_msat: amount_msat,
payment_hash: payment_hash,
cltv_expiry: cltv_expiry,
+ source,
onion_routing_packet: onion_routing_packet,
time_created: Instant::now(),
});
payment_hash: payment_hash.clone(),
cltv_expiry: cltv_expiry,
state: OutboundHTLCState::LocalAnnounced,
+ source,
fail_reason: None,
});
if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
panic!("Cannot create commitment tx until remote revokes their previous commitment");
}
+ if (self.channel_state & (ChannelState::PeerDisconnected as u32)) == (ChannelState::PeerDisconnected as u32) {
+ panic!("Cannot create commitment tx while disconnected, as send_htlc will have returned an Err so a send_commitment precondition has been violated");
+ }
let mut have_updates = false; // TODO initialize with "have we sent a fee update?"
for htlc in self.pending_outbound_htlcs.iter() {
if htlc.state == OutboundHTLCState::LocalAnnounced {
}
/// Only fails in case of bad keys
fn send_commitment_no_status_check(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), HandleError> {
- let funding_script = self.get_funding_redeemscript();
-
// We can upgrade the status of some HTLCs that are waiting on a commitment, even if we
// fail to generate this, we still are at least at a position where upgrading their status
// is acceptable.
}
}
+ match self.send_commitment_no_state_update() {
+ Ok((res, remote_commitment_tx)) => {
+ // Update state now that we've passed all the can-fail calls...
+ self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx.0, remote_commitment_tx.1, self.cur_remote_commitment_transaction_number);
+ self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32;
+ Ok((res, self.channel_monitor.clone()))
+ },
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Only fails in case of bad keys. Used for channel_reestablish commitment_signed generation
+ /// when we shouldn't change HTLC/channel state.
+ fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<HTLCOutputInCommitment>)), HandleError> {
+ let funding_script = self.get_funding_redeemscript();
+
let remote_keys = self.build_remote_transaction_keys()?;
let remote_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true);
let remote_commitment_txid = remote_commitment_tx.0.txid();
htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key));
}
- // Update state now that we've passed all the can-fail calls...
- self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx.0, remote_commitment_tx.1, self.cur_remote_commitment_transaction_number);
- self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32;
-
Ok((msgs::CommitmentSigned {
channel_id: self.channel_id,
signature: our_sig,
htlc_signatures: htlc_sigs,
- }, self.channel_monitor.clone()))
+ }, remote_commitment_tx))
}
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
/// to send to the remote peer in one go.
/// Shorthand for calling send_htlc() followed by send_commitment(), see docs on those for
/// more info.
- pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result<Option<(msgs::UpdateAddHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
- match self.send_htlc(amount_msat, payment_hash, cltv_expiry, onion_routing_packet)? {
+ pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result<Option<(msgs::UpdateAddHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
+ match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet)? {
Some(update_add_htlc) => {
let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?;
Ok(Some((update_add_htlc, commitment_signed, monitor_update)))
/// Begins the shutdown process, getting a message for the remote peer and returning all
/// holding cell HTLCs for payment failure.
- pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<[u8; 32]>), HandleError> {
+ pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<(HTLCSource, [u8; 32])>), HandleError> {
for htlc in self.pending_outbound_htlcs.iter() {
if htlc.state == OutboundHTLCState::LocalAnnounced {
return Err(HandleError{err: "Cannot begin shutdown with pending HTLCs, call send_commitment first", action: None});
return Err(HandleError{err: "Shutdown already in progress", action: None});
}
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+ if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
+ return Err(HandleError{err: "Cannot begin shutdown while peer is disconnected, maybe force-close instead?", action: None});
+ }
let our_closing_script = self.get_closing_scriptpubkey();
let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
self.holding_cell_htlc_updates.retain(|htlc_update| {
match htlc_update {
- &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, .. } => {
- dropped_outbound_htlcs.push(payment_hash.clone());
+ &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, .. } => {
+ dropped_outbound_htlcs.push((source.clone(), payment_hash.clone()));
false
},
_ => true
/// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
/// Also returns the list of payment_hashes for channels which we can safely fail backwards
/// immediately (others we will have to allow to time out).
- pub fn force_shutdown(&mut self) -> (Vec<Transaction>, Vec<[u8; 32]>) {
+ pub fn force_shutdown(&mut self) -> (Vec<Transaction>, Vec<(HTLCSource, [u8; 32])>) {
assert!(self.channel_state != ChannelState::ShutdownComplete as u32);
// We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and
let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
for htlc_update in self.holding_cell_htlc_updates.drain(..) {
match htlc_update {
- HTLCUpdateAwaitingACK::AddHTLC { payment_hash, .. } => {
- dropped_outbound_htlcs.push(payment_hash);
+ HTLCUpdateAwaitingACK::AddHTLC { source, payment_hash, .. } => {
+ dropped_outbound_htlcs.push((source, payment_hash));
},
_ => {}
}
}
- for htlc in self.pending_outbound_htlcs.drain(..) {
- if htlc.state == OutboundHTLCState::LocalAnnounced {
- dropped_outbound_htlcs.push(htlc.payment_hash);
- }
+ for _htlc in self.pending_outbound_htlcs.drain(..) {
//TODO: Do something with the remaining HTLCs
//(we need to have the ChannelManager monitor them so we can claim the inbound HTLCs
//which correspond)
use bitcoin::blockdata::script::Script;
use bitcoin::blockdata::transaction::Transaction;
use hex;
+ use ln::channelmanager::HTLCSource;
use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys};
use ln::channel::MAX_FUNDING_SATOSHIS;
use ln::chan_utils;
cltv_expiry: 502,
payment_hash: [0; 32],
state: OutboundHTLCState::Committed,
+ source: HTLCSource::dummy(),
fail_reason: None,
};
let mut sha = Sha256::new();
cltv_expiry: 503,
payment_hash: [0; 32],
state: OutboundHTLCState::Committed,
+ source: HTLCSource::dummy(),
fail_reason: None,
};
let mut sha = Sha256::new();