pub(super) our_dust_limit_satoshis: u64,
#[cfg(not(test))]
our_dust_limit_satoshis: u64,
+ #[cfg(test)]
+ pub(super) their_max_htlc_value_in_flight_msat: u64,
+ #[cfg(not(test))]
their_max_htlc_value_in_flight_msat: u64,
//get_our_max_htlc_value_in_flight_msat(): u64,
/// minimum channel reserve for **self** to maintain - set by them.
our_htlc_minimum_msat: u64,
their_to_self_delay: u16,
//implied by BREAKDOWN_TIMEOUT: our_to_self_delay: u16,
+ #[cfg(test)]
+ pub their_max_accepted_htlcs: u16,
+ #[cfg(not(test))]
their_max_accepted_htlcs: u16,
//implied by OUR_MAX_HTLCS: our_max_accepted_htlcs: u16,
minimum_depth: u32,
logger: Arc<Logger>,
}
-const OUR_MAX_HTLCS: u16 = 50; //TODO
+pub const OUR_MAX_HTLCS: u16 = 50; //TODO
/// Confirmation count threshold at which we close a channel. Ideally we'd keep the channel around
/// on ice until the funding transaction gets more confirmations, but the LN protocol doesn't
/// really allow for this, so instead we're stuck closing it out at that point.
/// have not yet committed it. Such HTLCs will only be included in transactions which are being
/// 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.
+ /// Returns (the transaction built, the number of HTLC outputs which were present in the
+ /// transaction, the list of HTLCs which were not ignored when building the transaction).
+ /// Note that below-dust HTLCs are included in the third return value, but not the second, and
+ /// sources are provided only for outbound HTLCs in the third return value.
#[inline]
- fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec<HTLCOutputInCommitment>, Vec<(PaymentHash, &HTLCSource, Option<u32>)>) {
+ fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) {
let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
let txins = {
transaction_utils::sort_outputs(&mut txouts);
let mut outputs: Vec<TxOut> = Vec::with_capacity(txouts.len());
- let mut htlcs_included: Vec<HTLCOutputInCommitment> = Vec::with_capacity(txouts.len());
- let mut htlc_sources: Vec<(PaymentHash, &HTLCSource, Option<u32>)> = Vec::with_capacity(txouts.len() + included_dust_htlcs.len());
- for (idx, out) in txouts.drain(..).enumerate() {
+ let mut htlcs_included: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(txouts.len() + included_dust_htlcs.len());
+ for (idx, mut out) in txouts.drain(..).enumerate() {
outputs.push(out.0);
- if let Some((mut htlc, source_option)) = out.1 {
+ if let Some((mut htlc, source_option)) = out.1.take() {
htlc.transaction_output_index = Some(idx as u32);
- if let Some(source) = source_option {
- htlc_sources.push((htlc.payment_hash, source, Some(idx as u32)));
- }
- htlcs_included.push(htlc);
- }
- }
- for (htlc, source_option) in included_dust_htlcs.drain(..) {
- if let Some(source) = source_option {
- htlc_sources.push((htlc.payment_hash, source, None));
+ htlcs_included.push((htlc, source_option));
}
}
+ let non_dust_htlc_count = htlcs_included.len();
+ htlcs_included.append(&mut included_dust_htlcs);
(Transaction {
version: 2,
lock_time: ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32),
input: txins,
output: outputs,
- }, htlcs_included, htlc_sources)
+ }, non_dust_htlc_count, htlcs_included)
}
#[inline]
// 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(), 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(), 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(), Vec::new());
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, 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(), Vec::new());
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, 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;
cltv_expiry: msg.cltv_expiry,
state: InboundHTLCState::RemoteAnnounced(pending_forward_state),
});
-
Ok(())
}
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();
+ let htlcs_cloned: Vec<_> = commitment_tx.2.drain(..).map(|htlc| (htlc.0, htlc.1.map(|h| h.clone()))).collect();
(commitment_tx.0, commitment_tx.1, htlcs_cloned)
};
let local_commitment_txid = local_commitment_tx.0.txid();
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
if update_fee {
- let num_htlcs = local_commitment_tx.1.len();
+ let num_htlcs = local_commitment_tx.1;
let total_fee: u64 = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + self.their_channel_reserve_satoshis {
}
}
- if msg.htlc_signatures.len() != local_commitment_tx.1.len() {
+ if msg.htlc_signatures.len() != local_commitment_tx.1 {
return Err(ChannelError::Close("Got wrong number of HTLC signatures from remote"));
}
- let mut new_local_commitment_txn = Vec::with_capacity(local_commitment_tx.1.len() + 1);
+ let mut new_local_commitment_txn = Vec::with_capacity(local_commitment_tx.1 + 1);
self.sign_commitment_transaction(&mut local_commitment_tx.0, &msg.signature);
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, htlc) in local_commitment_tx.1.drain(..).enumerate() {
+ let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.2.len());
+ for (idx, (htlc, source)) in local_commitment_tx.2.drain(..).enumerate() {
if let Some(_) = htlc.transaction_output_index {
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);
} else {
self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1
};
- htlcs_and_sigs.push((htlc, msg.htlc_signatures[idx], htlc_sig));
+ htlcs_and_sigs.push((htlc, Some((msg.htlc_signatures[idx], htlc_sig)), source));
+ } else {
+ htlcs_and_sigs.push((htlc, None, source));
}
}
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, local_commitment_tx.2);
+ self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
for htlc in self.pending_inbound_htlcs.iter_mut() {
let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
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(), 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(), 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;
}
}
- let (res, remote_commitment_tx, htlcs, htlc_sources) = match self.send_commitment_no_state_update() {
- Ok((res, (remote_commitment_tx, htlcs, mut htlc_sources))) => {
+ let (res, remote_commitment_tx, htlcs) = match self.send_commitment_no_state_update() {
+ Ok((res, (remote_commitment_tx, mut htlcs))) => {
// Update state now that we've passed all the can-fail calls...
- 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)
+ let htlcs_no_ref = htlcs.drain(..).map(|(htlc, htlc_source)| (htlc, htlc_source.map(|source_ref| Box::new(source_ref.clone())))).collect();
+ (res, remote_commitment_tx, htlcs_no_ref)
},
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_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx, htlcs, 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>, Vec<(PaymentHash, &HTLCSource, Option<u32>)>)), ChannelError> {
+ fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>)), ChannelError> {
let funding_script = self.get_funding_redeemscript();
let mut feerate_per_kw = self.feerate_per_kw;
let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
let our_sig = self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key);
- let mut htlc_sigs = Vec::new();
-
- for ref htlc in remote_commitment_tx.1.iter() {
+ let mut htlc_sigs = Vec::with_capacity(remote_commitment_tx.1);
+ for &(ref htlc, _) in remote_commitment_tx.2.iter() {
if let Some(_) = htlc.transaction_output_index {
let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
channel_id: self.channel_id,
signature: our_sig,
htlc_signatures: htlc_sigs,
- }, remote_commitment_tx))
+ }, (remote_commitment_tx.0, remote_commitment_tx.2)))
}
/// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction
macro_rules! test_commitment {
( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => {
unsigned_tx = {
- let res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
- (res.0, res.1)
+ let mut res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw);
+ let htlcs = res.2.drain(..)
+ .filter_map(|(htlc, _)| if htlc.transaction_output_index.is_some() { Some(htlc) } else { None })
+ .collect();
+ (res.0, htlcs)
};
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();