use crypto::digest::Digest;
use ln::msgs;
-use ln::msgs::{DecodeError, ErrorAction, HandleError};
+use ln::msgs::DecodeError;
use ln::channelmonitor::ChannelMonitor;
use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder};
use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
Close(&'static str),
}
-macro_rules! secp_call {
- ( $res: expr, $err: expr, $chan_id: expr ) => {
- match $res {
- Ok(key) => key,
- Err(_) => return Err(HandleError {err: $err, action: Some(msgs::ErrorAction::SendErrorMessage {msg: msgs::ErrorMessage {channel_id: $chan_id, data: $err.to_string()}})})
- }
- };
-}
-
macro_rules! secp_check {
($res: expr, $err: expr) => {
match $res {
/// generated by the peer which proposed adding the HTLCs, and thus we need to understand both
/// 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, feerate_per_kw: u64) -> (Transaction, Vec<HTLCOutputInCommitment>) {
+ fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec<HTLCOutputInCommitment>, Vec<([u8; 32], &HTLCSource, Option<u32>)>) {
let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
let txins = {
ins
};
- let mut txouts: Vec<(TxOut, Option<HTLCOutputInCommitment>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
+ let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option<&HTLCSource>)>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
+ let mut unincluded_htlc_sources: Vec<([u8; 32], &HTLCSource, Option<u32>)> = Vec::new();
let dust_limit_satoshis = if local { self.our_dust_limit_satoshis } else { self.their_dust_limit_satoshis };
let mut remote_htlc_total_msat = 0;
let mut value_to_self_msat_offset = 0;
macro_rules! add_htlc_output {
- ($htlc: expr, $outbound: expr) => {
+ ($htlc: expr, $outbound: expr, $source: expr) => {
if $outbound == local { // "offered HTLC output"
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
txouts.push((TxOut {
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
value: $htlc.amount_msat / 1000
- }, Some(htlc_in_tx)));
+ }, Some((htlc_in_tx, $source))));
+ } else {
+ if let Some(source) = $source {
+ unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
+ }
}
} else {
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
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
- }, Some(htlc_in_tx)));
+ }, Some((htlc_in_tx, $source))));
+ } else {
+ if let Some(source) = $source {
+ unincluded_htlc_sources.push(($htlc.payment_hash, source, None));
+ }
}
}
}
};
if include {
- add_htlc_output!(htlc, false);
+ add_htlc_output!(htlc, false, None);
remote_htlc_total_msat += htlc.amount_msat;
} else {
match &htlc.state {
};
if include {
- add_htlc_output!(htlc, true);
+ add_htlc_output!(htlc, true, Some(&htlc.source));
local_htlc_total_msat += htlc.amount_msat;
} else {
match htlc.state {
transaction_utils::sort_outputs(&mut txouts);
let mut outputs: Vec<TxOut> = Vec::with_capacity(txouts.len());
- let mut htlcs_used: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txouts.len());
+ let mut htlcs_included: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txouts.len());
+ let mut htlc_sources: Vec<([u8; 32], &HTLCSource, Option<u32>)> = Vec::with_capacity(txouts.len() + unincluded_htlc_sources.len());
for (idx, out) in txouts.drain(..).enumerate() {
outputs.push(out.0);
- if let Some(out_htlc) = out.1 {
- htlcs_used.push(out_htlc);
- htlcs_used.last_mut().unwrap().transaction_output_index = idx as u32;
+ if let Some((mut htlc, source_option)) = out.1 {
+ htlc.transaction_output_index = idx as u32;
+ if let Some(source) = source_option {
+ htlc_sources.push((htlc.payment_hash, source, Some(idx as u32)));
+ }
+ htlcs_included.push(htlc);
}
}
+ htlc_sources.append(&mut unincluded_htlc_sources);
(Transaction {
version: 2,
lock_time: ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32),
input: txins,
output: outputs,
- }, htlcs_used)
+ }, htlcs_included, htlc_sources)
}
#[inline]
#[inline]
/// Creates a set of keys for build_commitment_transaction to generate a transaction which we
/// will sign and send to our counterparty.
+ /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
fn build_remote_transaction_keys(&self) -> Result<TxCreationKeys, ChannelError> {
//TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we
//may see payments to it!
let mut payment_hash_calc = [0; 32];
sha.result(&mut payment_hash_calc);
+ // ChannelManager may generate duplicate claims/fails due to HTLC update events from
+ // on-chain ChannelsMonitors during block rescan. Ideally we'd figure out a way to drop
+ // these, but for now we just have to treat them as normal.
+
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);
- if let InboundHTLCState::Committed = htlc.state {
- } else {
- debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to");
- // Don't return in release mode here so that we can update channel_monitor
+ 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), log_bytes!(self.channel_id()));
+ }
+ return Ok((None, None));
+ },
+ _ => {
+ 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 {
- debug_assert!(false, "Unable to find a pending HTLC which matched the given HTLC ID");
return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID"));
}
match pending_update {
&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 { 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 the new channel monitor in a last-ditch effort to hit the
- // chain and claim the funds
+ log_warn!(self, "Have preimage and want to fulfill HTLC with pending failure against channel {}", log_bytes!(self.channel_id()));
+ // TODO: We may actually be able to switch to a fulfill here, though its
+ // rare enough it may not be worth the complexity burden.
return Ok((None, Some(self.channel_monitor.clone())));
}
},
}
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+ // ChannelManager may generate duplicate claims/fails due to HTLC update events from
+ // on-chain ChannelsMonitors during block rescan. Ideally we'd figure out a way to drop
+ // these, but for now we just have to treat them as normal.
+
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 let InboundHTLCState::Committed = htlc.state {
- } else {
- debug_assert!(false, "Have an inbound HTLC we tried to fail before it was fully committed to");
- return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID"));
+ match htlc.state {
+ InboundHTLCState::Committed => {},
+ InboundHTLCState::LocalRemoved(_) => {
+ return Ok(None);
+ },
+ _ => {
+ debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to");
+ return Err(ChannelError::Ignore("Unable to find a pending HTLC which matchd the given HTLC ID"));
+ }
}
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(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID"));
}
match pending_update {
&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(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID"));
}
},
&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);
+ return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID"));
}
},
_ => {}
// Now that we're past error-generating stuff, update our local state:
- self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_initial_commitment_tx, Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
+ self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_initial_commitment_tx, Vec::new(), Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
self.last_local_commitment_txn = vec![local_initial_commitment_tx.clone()];
- self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, Vec::new());
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, Vec::new(), Vec::new());
self.channel_state = ChannelState::FundingSent as u32;
self.channel_id = funding_txo.to_channel_id();
self.cur_remote_commitment_transaction_number -= 1;
secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid funding_signed signature from peer");
self.sign_commitment_transaction(&mut local_initial_commitment_tx, &msg.signature);
- self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new());
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new(), Vec::new());
self.last_local_commitment_txn = vec![local_initial_commitment_tx];
self.channel_state = ChannelState::FundingSent as u32;
self.cur_local_commitment_transaction_number -= 1;
(self.pending_outbound_htlcs.len() as u32, htlc_outbound_value_msat)
}
- pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), HandleError> {
+ pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), ChannelError> {
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});
+ 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(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}})});
+ return Err(ChannelError::Close("Peer sent update_add_htlc when we needed a channel_reestablish"));
}
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});
+ return Err(ChannelError::Close("Remote side tried to send more than the total value of the channel"));
}
if msg.amount_msat < self.our_htlc_minimum_msat {
- return Err(HandleError{err: "Remote side tried to send less than our minimum HTLC value", action: None});
+ return Err(ChannelError::Close("Remote side tried to send less than our minimum HTLC value"));
}
let (inbound_htlc_count, htlc_inbound_value_msat) = self.get_inbound_pending_htlc_stats();
if inbound_htlc_count + 1 > OUR_MAX_HTLCS as u32 {
- return Err(HandleError{err: "Remote tried to push more than our max accepted HTLCs", action: None});
+ return Err(ChannelError::Close("Remote tried to push more than our max accepted HTLCs"));
}
//TODO: Spec is unclear if this is per-direction or in total (I assume per direction):
// Check our_max_htlc_value_in_flight_msat
if htlc_inbound_value_msat + msg.amount_msat > Channel::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis) {
- return Err(HandleError{err: "Remote HTLC add would put them over their max HTLC value in flight", action: None});
+ return Err(ChannelError::Close("Remote HTLC add would put them over their max HTLC value in flight"));
}
// Check our_channel_reserve_satoshis (we're getting paid, so they have to at least meet
// the reserve_satoshis we told them to always have as direct payment so that they lose
// something if we punish them for broadcasting an old state).
if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 {
- return Err(HandleError{err: "Remote HTLC add would put them over their reserve value", action: None});
+ return Err(ChannelError::Close("Remote HTLC add would put them over their reserve value"));
}
if self.next_remote_htlc_id != msg.htlc_id {
- return Err(HandleError{err: "Remote skipped HTLC ID", action: None});
+ return Err(ChannelError::Close("Remote skipped HTLC ID"));
}
if msg.cltv_expiry >= 500000000 {
- return Err(HandleError{err: "Remote provided CLTV expiry in seconds instead of block height", action: None});
+ return Err(ChannelError::Close("Remote provided CLTV expiry in seconds instead of block height"));
}
//TODO: Check msg.cltv_expiry further? Do this in channel manager?
Err(ChannelError::Close("Remote tried to fulfill/fail an HTLC we couldn't find"))
}
- pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<&HTLCSource, ChannelError> {
+ pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<HTLCSource, ChannelError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(ChannelError::Close("Got fulfill HTLC message when channel was not in an operational state"));
}
let mut payment_hash = [0; 32];
sha.result(&mut payment_hash);
- self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)
+ self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None).map(|source| source.clone())
}
- pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<&HTLCSource, ChannelError> {
+ pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<(), ChannelError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(ChannelError::Close("Got fail HTLC message when channel was not in an operational state"));
}
return Err(ChannelError::Close("Peer sent update_fail_htlc when we needed a channel_reestablish"));
}
- self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))
+ self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?;
+ Ok(())
}
- pub fn update_fail_malformed_htlc<'a>(&mut self, msg: &msgs::UpdateFailMalformedHTLC, fail_reason: HTLCFailReason) -> Result<&HTLCSource, ChannelError> {
+ pub fn update_fail_malformed_htlc<'a>(&mut self, msg: &msgs::UpdateFailMalformedHTLC, fail_reason: HTLCFailReason) -> Result<(), ChannelError> {
if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
return Err(ChannelError::Close("Got fail malformed HTLC message when channel was not in an operational state"));
}
return Err(ChannelError::Close("Peer sent update_fail_malformed_htlc when we needed a channel_reestablish"));
}
- self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))
+ self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?;
+ Ok(())
}
pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned, fee_estimator: &FeeEstimator) -> Result<(msgs::RevokeAndACK, Option<msgs::CommitmentSigned>, Option<msgs::ClosingSigned>, ChannelMonitor), ChannelError> {
self.feerate_per_kw
};
- let mut local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, feerate_per_kw);
+ let mut local_commitment_tx = {
+ let mut commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, feerate_per_kw);
+ let htlcs_cloned: Vec<_> = commitment_tx.2.drain(..).map(|htlc_source| (htlc_source.0, htlc_source.1.clone(), htlc_source.2)).collect();
+ (commitment_tx.0, commitment_tx.1, htlcs_cloned)
+ };
let local_commitment_txid = local_commitment_tx.0.txid();
let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid commitment tx signature from peer");
new_local_commitment_txn.push(local_commitment_tx.0.clone());
let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.1.len());
- for (idx, ref htlc) in local_commitment_tx.1.iter().enumerate() {
- let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys, feerate_per_kw);
+ for (idx, htlc) in local_commitment_tx.1.drain(..).enumerate() {
+ let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, &htlc, true, &local_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer");
let htlc_sig = if htlc.offered {
- let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, htlc, &local_keys)?;
+ let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, &htlc, &local_keys)?;
new_local_commitment_txn.push(htlc_tx);
htlc_sig
} else {
- self.create_htlc_tx_signature(&htlc_tx, htlc, &local_keys)?.1
+ self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1
};
- htlcs_and_sigs.push(((*htlc).clone(), msg.htlc_signatures[idx], htlc_sig));
+ htlcs_and_sigs.push((htlc, msg.htlc_signatures[idx], htlc_sig));
}
let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1));
self.monitor_pending_order = None;
}
- self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs, local_commitment_tx.2);
for htlc in self.pending_inbound_htlcs.iter_mut() {
let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
/// commitment update or a revoke_and_ack generation). The messages which were generated from
/// that original call must *not* have been sent to the remote end, and must instead have been
/// dropped. They will be regenerated when monitor_updating_restored is called.
- pub fn monitor_update_failed(&mut self, order: RAACommitmentOrder) {
+ pub fn monitor_update_failed(&mut self, order: RAACommitmentOrder, mut pending_forwards: Vec<(PendingForwardHTLCInfo, u64)>, mut pending_fails: Vec<(HTLCSource, [u8; 32], HTLCFailReason)>, raa_first_dropped_cs: bool) {
assert_eq!(self.channel_state & ChannelState::MonitorUpdateFailed as u32, 0);
match order {
RAACommitmentOrder::CommitmentFirst => {
},
RAACommitmentOrder::RevokeAndACKFirst => {
self.monitor_pending_revoke_and_ack = true;
- self.monitor_pending_commitment_signed = false;
+ self.monitor_pending_commitment_signed = raa_first_dropped_cs;
},
}
+ assert!(self.monitor_pending_forwards.is_empty());
+ mem::swap(&mut pending_forwards, &mut self.monitor_pending_forwards);
+ assert!(self.monitor_pending_failures.is_empty());
+ mem::swap(&mut pending_fails, &mut self.monitor_pending_failures);
self.monitor_pending_order = Some(order);
self.channel_state |= ChannelState::MonitorUpdateFailed as u32;
}
return Err(ChannelError::Close("Peer sent a loose channel_reestablish not after reconnect"));
}
- if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER {
+ if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER ||
+ msg.next_local_commitment_number == 0 {
return Err(ChannelError::Close("Peer sent a garbage channel_reestablish"));
}
})
} else { None };
- if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) == ChannelState::FundingSent as u32 {
- // Short circuit the whole handler as there is nothing we can resend them
- return Ok((None, None, None, None, RAACommitmentOrder::CommitmentFirst, shutdown_msg));
- }
-
- if msg.next_local_commitment_number == 0 || msg.next_remote_commitment_number == 0 {
- if self.channel_state & (ChannelState::FundingSent as u32) != ChannelState::FundingSent as u32 {
- return Err(ChannelError::Close("Peer sent a pre-funding channel_reestablish after we exchanged funding_locked"));
+ if self.channel_state & (ChannelState::FundingSent as u32) == ChannelState::FundingSent as u32 {
+ if self.channel_state & ChannelState::OurFundingLocked as u32 == 0 {
+ if msg.next_remote_commitment_number != 0 {
+ return Err(ChannelError::Close("Peer claimed they saw a revoke_and_ack but we haven't sent funding_locked yet"));
+ }
+ // Short circuit the whole handler as there is nothing we can resend them
+ return Ok((None, None, None, None, RAACommitmentOrder::CommitmentFirst, shutdown_msg));
}
+
// We have OurFundingLocked set!
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);
}), None, None, None, RAACommitmentOrder::CommitmentFirst, shutdown_msg));
}
- let required_revoke = if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number {
+ let required_revoke = if msg.next_remote_commitment_number + 1 == 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.
None
- } else if msg.next_remote_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_local_commitment_transaction_number {
+ } else if msg.next_remote_commitment_number + 1 == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_local_commitment_transaction_number {
if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) != 0 {
self.monitor_pending_revoke_and_ack = true;
None
fn maybe_propose_first_closing_signed(&mut self, fee_estimator: &FeeEstimator) -> Option<msgs::ClosingSigned> {
if !self.channel_outbound || !self.pending_inbound_htlcs.is_empty() || !self.pending_outbound_htlcs.is_empty() ||
self.channel_state & (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::AwaitingRemoteRevoke as u32) != BOTH_SIDES_SHUTDOWN_MASK ||
- self.last_sent_closing_fee.is_some() ||
- self.cur_remote_commitment_transaction_number != self.cur_local_commitment_transaction_number{
+ self.last_sent_closing_fee.is_some() || self.pending_update_fee.is_some() {
return None;
}
Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs))
}
- pub fn closing_signed(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::ClosingSigned) -> Result<(Option<msgs::ClosingSigned>, Option<Transaction>), HandleError> {
+ pub fn closing_signed(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::ClosingSigned) -> Result<(Option<msgs::ClosingSigned>, Option<Transaction>), ChannelError> {
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});
+ return Err(ChannelError::Close("Remote end sent us a closing_signed before both sides provided a shutdown"));
}
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}})});
+ return Err(ChannelError::Close("Peer sent closing_signed when we needed a channel_reestablish"));
}
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});
+ return Err(ChannelError::Close("Remote end sent us a closing_signed while there were still pending HTLCs"));
}
if msg.fee_satoshis > 21000000 * 10000000 { //this is required to stop potential overflow in build_closing_transaction
- return Err(HandleError{err: "Remote tried to send us a closing tx with > 21 million BTC fee", action: None});
+ return Err(ChannelError::Close("Remote tried to send us a closing tx with > 21 million BTC fee"));
}
let funding_redeemscript = self.get_funding_redeemscript();
let (mut closing_tx, used_total_fee) = self.build_closing_transaction(msg.fee_satoshis, false);
if used_total_fee != msg.fee_satoshis {
- return Err(HandleError{err: "Remote sent us a closing_signed with a fee greater than the value they can claim", action: None});
+ return Err(ChannelError::Close("Remote sent us a closing_signed with a fee greater than the value they can claim"));
}
let mut sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
// limits, so check for that case by re-checking the signature here.
closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0;
sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
- secp_call!(self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid closing tx signature from peer", self.channel_id());
+ secp_check!(self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid closing tx signature from peer");
},
};
if proposed_sat_per_kw > our_max_feerate {
if let Some((last_feerate, _)) = self.last_sent_closing_fee {
if our_max_feerate <= last_feerate {
- return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate", action: None});
+ return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate"));
}
}
propose_new_feerate!(our_max_feerate);
if proposed_sat_per_kw < our_min_feerate {
if let Some((last_feerate, _)) = self.last_sent_closing_fee {
if our_min_feerate >= last_feerate {
- return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate", action: None});
+ return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate"));
}
}
propose_new_feerate!(our_min_feerate);
/// In case of Err, the channel may have been closed, at which point the standard requirements
/// apply - no calls may be made except those explicitly stated to be allowed post-shutdown.
/// Only returns an ErrorAction of DisconnectPeer, if Err.
- pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, HandleError> {
+ pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, msgs::ErrorMessage> {
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
if header.bitcoin_hash() != self.last_block_connected {
self.last_block_connected = header.bitcoin_hash();
}
self.channel_state = ChannelState::ShutdownComplete as u32;
self.channel_update_count += 1;
- return Err(HandleError{err: "funding tx had wrong script/value", action: Some(ErrorAction::DisconnectPeer{msg: None})});
+ return Err(msgs::ErrorMessage {
+ channel_id: self.channel_id(),
+ data: "funding tx had wrong script/value".to_owned()
+ });
} else {
if self.channel_outbound {
for input in tx.input.iter() {
}
}
+ /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
fn get_outbound_funding_created_signature(&mut self) -> Result<(Signature, Transaction), ChannelError> {
let funding_script = self.get_funding_redeemscript();
/// or if called on an inbound channel.
/// Note that channel_id changes during this call!
/// Do NOT broadcast the funding transaction until after a successful funding_signed call!
+ /// If an Err is returned, it is a ChannelError::Close.
pub fn get_outbound_funding_created(&mut self, funding_txo: OutPoint) -> Result<(msgs::FundingCreated, ChannelMonitor), ChannelError> {
if !self.channel_outbound {
panic!("Tried to create outbound funding_created message on an inbound channel!");
let temporary_channel_id = self.channel_id;
// Now that we're past error-generating stuff, update our local state:
- self.channel_monitor.provide_latest_remote_commitment_tx_info(&commitment_tx, Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
+ self.channel_monitor.provide_latest_remote_commitment_tx_info(&commitment_tx, Vec::new(), Vec::new(), self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
self.channel_state = ChannelState::FundingCreated as u32;
self.channel_id = funding_txo.to_channel_id();
self.cur_remote_commitment_transaction_number -= 1;
/// 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);
+ assert_ne!(self.cur_remote_commitment_transaction_number, INITIAL_COMMITMENT_NUMBER);
msgs::ChannelReestablish {
channel_id: self.channel_id(),
+ // The protocol has two different commitment number concepts - the "commitment
+ // transaction number", which starts from 0 and counts up, and the "revocation key
+ // index" which starts at INITIAL_COMMITMENT_NUMBER and counts down. We track
+ // commitment transaction numbers by the index which will be used to reveal the
+ // revocation key for that commitment transaction, which means we have to convert them
+ // to protocol-level commitment numbers here...
+
+ // next_local_commitment_number is the next commitment_signed number we expect to
+ // receive (indicating if they need to resend one that we missed).
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 -
- if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) == (ChannelState::FundingSent as u32) { 1 } else { 0 },
+ // We have to set next_remote_commitment_number to the next revoke_and_ack we expect to
+ // receive, however we track it by the next commitment number for a remote transaction
+ // (which is one further, as they always revoke previous commitment transaction, not
+ // the one we send) so we have to decrement by 1. Note that if
+ // cur_remote_commitment_transaction_number is INITIAL_COMMITMENT_NUMBER we will have
+ // dropped this channel on disconnect as it hasn't yet reached FundingSent so we can't
+ // overflow here.
+ next_remote_commitment_number: INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number - 1,
data_loss_protect: None,
}
}
}
/// Creates a signed commitment transaction to send to the remote peer.
- /// Always returns a Channel-failing HandleError::action if an immediately-preceding (read: the
+ /// Always returns a ChannelError::Close if an immediately-preceding (read: the
/// last call to this Channel) send_htlc returned Ok(Some(_)) and there is an Err.
/// May panic if called except immediately after a successful, Ok(Some(_))-returning send_htlc.
pub fn send_commitment(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), ChannelError> {
}
}
- match self.send_commitment_no_state_update() {
- Ok((res, remote_commitment_tx)) => {
+ let (res, remote_commitment_tx, htlcs, htlc_sources) = match self.send_commitment_no_state_update() {
+ Ok((res, (remote_commitment_tx, htlcs, mut htlc_sources))) => {
// 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.their_cur_commitment_point.unwrap());
- self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32;
- Ok((res, self.channel_monitor.clone()))
+ let htlc_sources_no_ref = htlc_sources.drain(..).map(|htlc_source| (htlc_source.0, htlc_source.1.clone(), htlc_source.2)).collect();
+ (res, remote_commitment_tx, htlcs, htlc_sources_no_ref)
},
- Err(e) => Err(e),
- }
+ Err(e) => return Err(e),
+ };
+
+ self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx, htlcs, htlc_sources, self.cur_remote_commitment_transaction_number, self.their_cur_commitment_point.unwrap());
+ self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32;
+ Ok((res, self.channel_monitor.clone()))
}
/// 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>)), ChannelError> {
+ fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<HTLCOutputInCommitment>, Vec<([u8; 32], &HTLCSource, Option<u32>)>)), ChannelError> {
let funding_script = self.get_funding_redeemscript();
let mut feerate_per_kw = self.feerate_per_kw;
}
fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys { self.chan_keys.clone() }
+ fn get_session_key(&self) -> SecretKey { panic!(); }
}
#[test]
macro_rules! test_commitment {
( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
- unsigned_tx = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
+ unsigned_tx = {
+ let res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
+ (res.0, res.1)
+ };
let their_signature = Signature::from_der(&secp_ctx, &hex::decode($their_sig_hex).unwrap()[..]).unwrap();
let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &chan.get_funding_redeemscript(), chan.channel_value_satoshis)[..]).unwrap();
secp_ctx.verify(&sighash, &their_signature, &chan.their_funding_pubkey.unwrap()).unwrap();