mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 07:17:40 +01:00
Merge tracking of HTLCs-in-commitment with outbound-HTLCs
This simplifies a few things, deduplicates a some small memory overhead, and, most importantly, is a first step to fixing would_broadcast_at_height.
This commit is contained in:
parent
09919d2af0
commit
92424ebbfe
2 changed files with 173 additions and 204 deletions
|
@ -747,8 +747,12 @@ impl Channel {
|
|||
/// 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 = {
|
||||
|
@ -915,30 +919,23 @@ impl Channel {
|
|||
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]
|
||||
|
@ -1451,9 +1448,9 @@ impl Channel {
|
|||
|
||||
// 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;
|
||||
|
@ -1490,7 +1487,7 @@ impl Channel {
|
|||
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;
|
||||
|
@ -1693,7 +1690,7 @@ impl Channel {
|
|||
|
||||
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();
|
||||
|
@ -1702,7 +1699,7 @@ impl Channel {
|
|||
|
||||
//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 {
|
||||
|
@ -1710,16 +1707,16 @@ impl Channel {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -1732,7 +1729,9 @@ impl Channel {
|
|||
} 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1760,7 +1759,7 @@ impl Channel {
|
|||
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 {
|
||||
|
@ -3030,7 +3029,7 @@ impl 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(), 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;
|
||||
|
@ -3262,23 +3261,23 @@ impl Channel {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -3294,9 +3293,8 @@ impl Channel {
|
|||
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);
|
||||
|
@ -3310,7 +3308,7 @@ impl Channel {
|
|||
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
|
||||
|
@ -4024,8 +4022,11 @@ mod tests {
|
|||
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();
|
||||
|
|
|
@ -332,8 +332,7 @@ struct LocalSignedTx {
|
|||
b_htlc_key: PublicKey,
|
||||
delayed_payment_key: PublicKey,
|
||||
feerate_per_kw: u64,
|
||||
htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>,
|
||||
htlc_sources: Vec<(PaymentHash, HTLCSource, Option<u32>)>,
|
||||
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<(Signature, Signature)>, Option<HTLCSource>)>,
|
||||
}
|
||||
|
||||
const SERIALIZATION_VERSION: u8 = 1;
|
||||
|
@ -358,7 +357,7 @@ pub struct ChannelMonitor {
|
|||
their_to_self_delay: Option<u16>,
|
||||
|
||||
old_secrets: [([u8; 32], u64); 49],
|
||||
remote_claimable_outpoints: HashMap<Sha256dHash, (Vec<HTLCOutputInCommitment>, Vec<(PaymentHash, HTLCSource, Option<u32>)>)>,
|
||||
remote_claimable_outpoints: HashMap<Sha256dHash, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
|
||||
/// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain.
|
||||
/// Nor can we figure out their commitment numbers without the commitment transaction they are
|
||||
/// spending. Thus, in order to claim them via revocation key, we track all the remote
|
||||
|
@ -515,7 +514,9 @@ impl ChannelMonitor {
|
|||
// TODO: We should probably consider whether we're really getting the next secret here.
|
||||
if let Storage::Local { ref mut prev_remote_commitment_txid, .. } = self.key_storage {
|
||||
if let Some(txid) = prev_remote_commitment_txid.take() {
|
||||
self.remote_claimable_outpoints.get_mut(&txid).unwrap().1 = Vec::new();
|
||||
for &mut (_, ref mut source) in self.remote_claimable_outpoints.get_mut(&txid).unwrap() {
|
||||
*source = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,12 +559,12 @@ impl ChannelMonitor {
|
|||
/// The monitor watches for it to be broadcasted and then uses the HTLC information (and
|
||||
/// possibly future revocation/preimage information) to claim outputs where possible.
|
||||
/// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers.
|
||||
pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<HTLCOutputInCommitment>, htlc_sources: Vec<(PaymentHash, HTLCSource, Option<u32>)>, commitment_number: u64, their_revocation_point: PublicKey) {
|
||||
pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>, commitment_number: u64, their_revocation_point: PublicKey) {
|
||||
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
|
||||
// so that a remote monitor doesn't learn anything unless there is a malicious close.
|
||||
// (only maybe, sadly we cant do the same for local info, as we need to be aware of
|
||||
// timeouts)
|
||||
for ref htlc in &htlc_outputs {
|
||||
for &(ref htlc, _) in &htlc_outputs {
|
||||
self.remote_hash_commitment_number.insert(htlc.payment_hash, commitment_number);
|
||||
}
|
||||
|
||||
|
@ -574,7 +575,7 @@ impl ChannelMonitor {
|
|||
*prev_remote_commitment_txid = current_remote_commitment_txid.take();
|
||||
*current_remote_commitment_txid = Some(new_txid);
|
||||
}
|
||||
self.remote_claimable_outpoints.insert(new_txid, (htlc_outputs, htlc_sources));
|
||||
self.remote_claimable_outpoints.insert(new_txid, htlc_outputs);
|
||||
self.current_remote_commitment_number = commitment_number;
|
||||
//TODO: Merge this into the other per-remote-transaction output storage stuff
|
||||
match self.their_cur_revocation_points {
|
||||
|
@ -604,7 +605,7 @@ impl ChannelMonitor {
|
|||
/// Panics if set_their_to_self_delay has never been called.
|
||||
/// Also update Storage with latest local per_commitment_point to derive local_delayedkey in
|
||||
/// case of onchain HTLC tx
|
||||
pub(super) fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>, htlc_sources: Vec<(PaymentHash, HTLCSource, Option<u32>)>) {
|
||||
pub(super) fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<(Signature, Signature)>, Option<HTLCSource>)>) {
|
||||
assert!(self.their_to_self_delay.is_some());
|
||||
self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take();
|
||||
self.current_local_signed_commitment_tx = Some(LocalSignedTx {
|
||||
|
@ -616,7 +617,6 @@ impl ChannelMonitor {
|
|||
delayed_payment_key: local_keys.a_delayed_payment_key,
|
||||
feerate_per_kw,
|
||||
htlc_outputs,
|
||||
htlc_sources,
|
||||
});
|
||||
|
||||
if let Storage::Local { ref mut latest_per_commitment_point, .. } = self.key_storage {
|
||||
|
@ -863,30 +863,13 @@ impl ChannelMonitor {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! serialize_htlc_source {
|
||||
($htlc_source: expr) => {
|
||||
$htlc_source.0.write(writer)?;
|
||||
$htlc_source.1.write(writer)?;
|
||||
if let &Some(ref txo) = &$htlc_source.2 {
|
||||
writer.write_all(&[1; 1])?;
|
||||
txo.write(writer)?;
|
||||
} else {
|
||||
writer.write_all(&[0; 1])?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
writer.write_all(&byte_utils::be64_to_array(self.remote_claimable_outpoints.len() as u64))?;
|
||||
for (ref txid, &(ref htlc_infos, ref htlc_sources)) in self.remote_claimable_outpoints.iter() {
|
||||
for (ref txid, ref htlc_infos) in self.remote_claimable_outpoints.iter() {
|
||||
writer.write_all(&txid[..])?;
|
||||
writer.write_all(&byte_utils::be64_to_array(htlc_infos.len() as u64))?;
|
||||
for ref htlc_output in htlc_infos.iter() {
|
||||
for &(ref htlc_output, ref htlc_source) in htlc_infos.iter() {
|
||||
serialize_htlc_in_commitment!(htlc_output);
|
||||
}
|
||||
writer.write_all(&byte_utils::be64_to_array(htlc_sources.len() as u64))?;
|
||||
for ref htlc_source in htlc_sources.iter() {
|
||||
serialize_htlc_source!(htlc_source);
|
||||
write_option!(htlc_source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -926,14 +909,16 @@ impl ChannelMonitor {
|
|||
|
||||
writer.write_all(&byte_utils::be64_to_array($local_tx.feerate_per_kw))?;
|
||||
writer.write_all(&byte_utils::be64_to_array($local_tx.htlc_outputs.len() as u64))?;
|
||||
for &(ref htlc_output, ref their_sig, ref our_sig) in $local_tx.htlc_outputs.iter() {
|
||||
for &(ref htlc_output, ref sigs, ref htlc_source) in $local_tx.htlc_outputs.iter() {
|
||||
serialize_htlc_in_commitment!(htlc_output);
|
||||
writer.write_all(&their_sig.serialize_compact(&self.secp_ctx))?;
|
||||
writer.write_all(&our_sig.serialize_compact(&self.secp_ctx))?;
|
||||
}
|
||||
writer.write_all(&byte_utils::be64_to_array($local_tx.htlc_sources.len() as u64))?;
|
||||
for ref htlc_source in $local_tx.htlc_sources.iter() {
|
||||
serialize_htlc_source!(htlc_source);
|
||||
if let &Some((ref their_sig, ref our_sig)) = sigs {
|
||||
1u8.write(writer)?;
|
||||
writer.write_all(&their_sig.serialize_compact(&self.secp_ctx))?;
|
||||
writer.write_all(&our_sig.serialize_compact(&self.secp_ctx))?;
|
||||
} else {
|
||||
0u8.write(writer)?;
|
||||
}
|
||||
write_option!(htlc_source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1117,7 +1102,7 @@ impl ChannelMonitor {
|
|||
let (sig, redeemscript) = match self.key_storage {
|
||||
Storage::Local { ref revocation_base_key, .. } => {
|
||||
let redeemscript = if $htlc_idx.is_none() { revokeable_redeemscript.clone() } else {
|
||||
let htlc = &per_commitment_option.unwrap().0[$htlc_idx.unwrap()];
|
||||
let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()].0;
|
||||
chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey)
|
||||
};
|
||||
let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
|
||||
|
@ -1140,10 +1125,10 @@ impl ChannelMonitor {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(&(ref per_commitment_data, _)) = per_commitment_option {
|
||||
if let Some(ref per_commitment_data) = per_commitment_option {
|
||||
inputs.reserve_exact(per_commitment_data.len());
|
||||
|
||||
for (idx, ref htlc) in per_commitment_data.iter().enumerate() {
|
||||
for (idx, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
|
||||
if let Some(transaction_output_index) = htlc.transaction_output_index {
|
||||
let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
|
||||
if transaction_output_index as usize >= tx.output.len() ||
|
||||
|
@ -1194,10 +1179,12 @@ impl ChannelMonitor {
|
|||
// on-chain claims, so we can do that at the same time.
|
||||
macro_rules! check_htlc_fails {
|
||||
($txid: expr, $commitment_tx: expr) => {
|
||||
if let Some(&(_, ref outpoints)) = self.remote_claimable_outpoints.get(&$txid) {
|
||||
for &(ref payment_hash, ref source, _) in outpoints.iter() {
|
||||
log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of revoked remote commitment transaction", log_bytes!(payment_hash.0), $commitment_tx);
|
||||
htlc_updated.push(((*source).clone(), None, payment_hash.clone()));
|
||||
if let Some(ref outpoints) = self.remote_claimable_outpoints.get(&$txid) {
|
||||
for &(ref htlc, ref source_option) in outpoints.iter() {
|
||||
if let &Some(ref source) = source_option {
|
||||
log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of revoked remote commitment transaction", log_bytes!(htlc.payment_hash.0), $commitment_tx);
|
||||
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1256,24 +1243,26 @@ impl ChannelMonitor {
|
|||
// on-chain claims, so we can do that at the same time.
|
||||
macro_rules! check_htlc_fails {
|
||||
($txid: expr, $commitment_tx: expr, $id: tt) => {
|
||||
if let Some(&(_, ref latest_outpoints)) = self.remote_claimable_outpoints.get(&$txid) {
|
||||
$id: for &(ref payment_hash, ref source, _) in latest_outpoints.iter() {
|
||||
// Check if the HTLC is present in the commitment transaction that was
|
||||
// broadcast, but not if it was below the dust limit, which we should
|
||||
// fail backwards immediately as there is no way for us to learn the
|
||||
// payment_preimage.
|
||||
// Note that if the dust limit were allowed to change between
|
||||
// commitment transactions we'd want to be check whether *any*
|
||||
// broadcastable commitment transaction has the HTLC in it, but it
|
||||
// cannot currently change after channel initialization, so we don't
|
||||
// need to here.
|
||||
for &(_, ref broadcast_source, ref output_idx) in per_commitment_data.1.iter() {
|
||||
if output_idx.is_some() && source == broadcast_source {
|
||||
continue $id;
|
||||
if let Some(ref latest_outpoints) = self.remote_claimable_outpoints.get(&$txid) {
|
||||
$id: for &(ref htlc, ref source_option) in latest_outpoints.iter() {
|
||||
if let &Some(ref source) = source_option {
|
||||
// Check if the HTLC is present in the commitment transaction that was
|
||||
// broadcast, but not if it was below the dust limit, which we should
|
||||
// fail backwards immediately as there is no way for us to learn the
|
||||
// payment_preimage.
|
||||
// Note that if the dust limit were allowed to change between
|
||||
// commitment transactions we'd want to be check whether *any*
|
||||
// broadcastable commitment transaction has the HTLC in it, but it
|
||||
// cannot currently change after channel initialization, so we don't
|
||||
// need to here.
|
||||
for &(ref broadcast_htlc, ref broadcast_source) in per_commitment_data.iter() {
|
||||
if broadcast_htlc.transaction_output_index.is_some() && Some(source) == broadcast_source.as_ref() {
|
||||
continue $id;
|
||||
}
|
||||
}
|
||||
log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of remote commitment transaction", log_bytes!(htlc.payment_hash.0), $commitment_tx);
|
||||
htlc_updated.push(((**source).clone(), None, htlc.payment_hash.clone()));
|
||||
}
|
||||
log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of remote commitment transaction", log_bytes!(payment_hash.0), $commitment_tx);
|
||||
htlc_updated.push(((*source).clone(), None, payment_hash.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1336,7 +1325,7 @@ impl ChannelMonitor {
|
|||
{
|
||||
let (sig, redeemscript) = match self.key_storage {
|
||||
Storage::Local { ref htlc_base_key, .. } => {
|
||||
let htlc = &per_commitment_option.unwrap().0[$input.sequence as usize];
|
||||
let htlc = &per_commitment_option.unwrap()[$input.sequence as usize].0;
|
||||
let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
|
||||
let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
|
||||
let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key));
|
||||
|
@ -1354,7 +1343,7 @@ impl ChannelMonitor {
|
|||
}
|
||||
}
|
||||
|
||||
for (idx, ref htlc) in per_commitment_data.0.iter().enumerate() {
|
||||
for (idx, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
|
||||
if let Some(transaction_output_index) = htlc.transaction_output_index {
|
||||
let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
|
||||
if transaction_output_index as usize >= tx.output.len() ||
|
||||
|
@ -1575,42 +1564,44 @@ impl ChannelMonitor {
|
|||
}
|
||||
}
|
||||
|
||||
for &(ref htlc, ref their_sig, ref our_sig) in local_tx.htlc_outputs.iter() {
|
||||
for &(ref htlc, ref sigs, _) in local_tx.htlc_outputs.iter() {
|
||||
if let Some(transaction_output_index) = htlc.transaction_output_index {
|
||||
if htlc.offered {
|
||||
let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
|
||||
if let &Some((ref their_sig, ref our_sig)) = sigs {
|
||||
if htlc.offered {
|
||||
let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
|
||||
|
||||
htlc_timeout_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
|
||||
htlc_timeout_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
|
||||
|
||||
htlc_timeout_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_timeout_tx.input[0].witness[1].push(SigHashType::All as u8);
|
||||
htlc_timeout_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8);
|
||||
htlc_timeout_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_timeout_tx.input[0].witness[1].push(SigHashType::All as u8);
|
||||
htlc_timeout_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8);
|
||||
|
||||
htlc_timeout_tx.input[0].witness.push(Vec::new());
|
||||
htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
|
||||
htlc_timeout_tx.input[0].witness.push(Vec::new());
|
||||
htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
|
||||
|
||||
add_dynamic_output!(htlc_timeout_tx, 0);
|
||||
res.push(htlc_timeout_tx);
|
||||
} else {
|
||||
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
|
||||
let mut htlc_success_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
|
||||
add_dynamic_output!(htlc_timeout_tx, 0);
|
||||
res.push(htlc_timeout_tx);
|
||||
} else {
|
||||
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
|
||||
let mut htlc_success_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
|
||||
|
||||
htlc_success_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
|
||||
htlc_success_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
|
||||
|
||||
htlc_success_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_success_tx.input[0].witness[1].push(SigHashType::All as u8);
|
||||
htlc_success_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_success_tx.input[0].witness[2].push(SigHashType::All as u8);
|
||||
htlc_success_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_success_tx.input[0].witness[1].push(SigHashType::All as u8);
|
||||
htlc_success_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec());
|
||||
htlc_success_tx.input[0].witness[2].push(SigHashType::All as u8);
|
||||
|
||||
htlc_success_tx.input[0].witness.push(payment_preimage.0.to_vec());
|
||||
htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
|
||||
htlc_success_tx.input[0].witness.push(payment_preimage.0.to_vec());
|
||||
htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
|
||||
|
||||
add_dynamic_output!(htlc_success_tx, 0);
|
||||
res.push(htlc_success_tx);
|
||||
add_dynamic_output!(htlc_success_tx, 0);
|
||||
res.push(htlc_success_tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
watch_outputs.push(local_tx.tx.output[transaction_output_index as usize].clone());
|
||||
watch_outputs.push(local_tx.tx.output[transaction_output_index as usize].clone());
|
||||
} else { panic!("Should have sigs for non-dust local tx outputs!") }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1801,11 +1792,12 @@ impl ChannelMonitor {
|
|||
// needs to use the same logic as the revoked-tx-announe logic - checking the last two
|
||||
// remote commitment transactions. This probably has implications for what data we need to
|
||||
// store in local commitment transactions.
|
||||
// TODO: We need to consider HTLCs which were below dust threshold here - while they don't
|
||||
// Note that we consider HTLCs which were below dust threshold here - while they don't
|
||||
// strictly imply that we need to fail the channel, we need to go ahead and fail them back
|
||||
// to the source, and if we don't fail the channel we will have to ensure that the next
|
||||
// updates that peer sends us are update_fails, failing the channel if not. It's probably
|
||||
// easier to just fail the channel as this case should be rare enough anyway.
|
||||
// TODO: Test below dust HTLC channel failing
|
||||
if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
|
||||
for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() {
|
||||
// For inbound HTLCs which we know the preimage for, we have to ensure we hit the
|
||||
|
@ -1850,42 +1842,40 @@ impl ChannelMonitor {
|
|||
let offered_preimage_claim = input.witness.len() == 3 && input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT;
|
||||
|
||||
macro_rules! log_claim {
|
||||
($source: expr, $local_tx: expr, $outbound_htlc: expr, $payment_hash: expr, $source_avail: expr) => {
|
||||
($tx_info: expr, $local_tx: expr, $htlc: expr, $source_avail: expr) => {
|
||||
// We found the output in question, but aren't failing it backwards
|
||||
// as we have no corresponding source. This implies either it is an
|
||||
// inbound HTLC or an outbound HTLC on a revoked transaction.
|
||||
let outbound_htlc = $local_tx == $htlc.offered;
|
||||
if ($local_tx && revocation_sig_claim) ||
|
||||
($outbound_htlc && !$source_avail && (accepted_preimage_claim || offered_preimage_claim)) {
|
||||
(outbound_htlc && !$source_avail && (accepted_preimage_claim || offered_preimage_claim)) {
|
||||
log_error!(self, "Input spending {} ({}:{}) in {} resolves {} HTLC with payment hash {} with {}!",
|
||||
$source, input.previous_output.txid, input.previous_output.vout, tx.txid(),
|
||||
if $outbound_htlc { "outbound" } else { "inbound" }, log_bytes!($payment_hash.0),
|
||||
$tx_info, input.previous_output.txid, input.previous_output.vout, tx.txid(),
|
||||
if outbound_htlc { "outbound" } else { "inbound" }, log_bytes!($htlc.payment_hash.0),
|
||||
if revocation_sig_claim { "revocation sig" } else { "preimage claim after we'd passed the HTLC resolution back" });
|
||||
} else {
|
||||
log_info!(self, "Input spending {} ({}:{}) in {} resolves {} HTLC with payment hash {} with {}",
|
||||
$source, input.previous_output.txid, input.previous_output.vout, tx.txid(),
|
||||
if $outbound_htlc { "outbound" } else { "inbound" }, log_bytes!($payment_hash.0),
|
||||
$tx_info, input.previous_output.txid, input.previous_output.vout, tx.txid(),
|
||||
if outbound_htlc { "outbound" } else { "inbound" }, log_bytes!($htlc.payment_hash.0),
|
||||
if revocation_sig_claim { "revocation sig" } else if accepted_preimage_claim || offered_preimage_claim { "preimage" } else { "timeout" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! scan_commitment {
|
||||
($htlc_outputs: expr, $htlc_sources: expr, $source: expr, $local_tx: expr) => {
|
||||
for &(ref payment_hash, ref source, ref vout) in $htlc_sources.iter() {
|
||||
if &Some(input.previous_output.vout) == vout {
|
||||
log_claim!($source, $local_tx, true, payment_hash, true);
|
||||
// We have a resolution of an HTLC either from one of our latest
|
||||
// local commitment transactions or an unrevoked remote commitment
|
||||
// transaction. This implies we either learned a preimage, the HTLC
|
||||
// has timed out, or we screwed up. In any case, we should now
|
||||
// resolve the source HTLC with the original sender.
|
||||
payment_data = Some((source.clone(), *payment_hash));
|
||||
}
|
||||
}
|
||||
if payment_data.is_none() {
|
||||
for htlc_output in $htlc_outputs {
|
||||
if Some(input.previous_output.vout) == htlc_output.transaction_output_index {
|
||||
log_claim!($source, $local_tx, $local_tx == htlc_output.offered, htlc_output.payment_hash, false);
|
||||
($htlcs: expr, $tx_info: expr, $local_tx: expr) => {
|
||||
for (ref htlc_output, source_option) in $htlcs {
|
||||
if Some(input.previous_output.vout) == htlc_output.transaction_output_index {
|
||||
if let Some(ref source) = source_option {
|
||||
log_claim!($tx_info, $local_tx, htlc_output, true);
|
||||
// We have a resolution of an HTLC either from one of our latest
|
||||
// local commitment transactions or an unrevoked remote commitment
|
||||
// transaction. This implies we either learned a preimage, the HTLC
|
||||
// has timed out, or we screwed up. In any case, we should now
|
||||
// resolve the source HTLC with the original sender.
|
||||
payment_data = Some(((*source).clone(), htlc_output.payment_hash));
|
||||
} else {
|
||||
log_claim!($tx_info, $local_tx, htlc_output, false);
|
||||
continue 'outer_loop;
|
||||
}
|
||||
}
|
||||
|
@ -1895,20 +1885,19 @@ impl ChannelMonitor {
|
|||
|
||||
if let Some(ref current_local_signed_commitment_tx) = self.current_local_signed_commitment_tx {
|
||||
if input.previous_output.txid == current_local_signed_commitment_tx.txid {
|
||||
scan_commitment!(current_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a),
|
||||
current_local_signed_commitment_tx.htlc_sources,
|
||||
scan_commitment!(current_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())),
|
||||
"our latest local commitment tx", true);
|
||||
}
|
||||
}
|
||||
if let Some(ref prev_local_signed_commitment_tx) = self.prev_local_signed_commitment_tx {
|
||||
if input.previous_output.txid == prev_local_signed_commitment_tx.txid {
|
||||
scan_commitment!(prev_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a),
|
||||
prev_local_signed_commitment_tx.htlc_sources,
|
||||
scan_commitment!(prev_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())),
|
||||
"our previous local commitment tx", true);
|
||||
}
|
||||
}
|
||||
if let Some(&(ref htlc_outputs, ref htlc_sources)) = self.remote_claimable_outpoints.get(&input.previous_output.txid) {
|
||||
scan_commitment!(htlc_outputs, htlc_sources, "remote commitment tx", false);
|
||||
if let Some(ref htlc_outputs) = self.remote_claimable_outpoints.get(&input.previous_output.txid) {
|
||||
scan_commitment!(htlc_outputs.iter().map(|&(ref a, ref b)| (a, (b.as_ref().clone()).map(|boxed| &**boxed))),
|
||||
"remote commitment tx", false);
|
||||
}
|
||||
|
||||
// Check that scan_commitment, above, decided there is some source worth relaying an
|
||||
|
@ -2044,35 +2033,16 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! read_htlc_source {
|
||||
() => {
|
||||
{
|
||||
(Readable::read(reader)?, Readable::read(reader)?,
|
||||
match <u8 as Readable<R>>::read(reader)? {
|
||||
0 => None,
|
||||
1 => Some(Readable::read(reader)?),
|
||||
_ => return Err(DecodeError::InvalidValue),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let remote_claimable_outpoints_len: u64 = Readable::read(reader)?;
|
||||
let mut remote_claimable_outpoints = HashMap::with_capacity(cmp::min(remote_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64));
|
||||
for _ in 0..remote_claimable_outpoints_len {
|
||||
let txid: Sha256dHash = Readable::read(reader)?;
|
||||
let outputs_count: u64 = Readable::read(reader)?;
|
||||
let mut outputs = Vec::with_capacity(cmp::min(outputs_count as usize, MAX_ALLOC_SIZE / 32));
|
||||
for _ in 0..outputs_count {
|
||||
outputs.push(read_htlc_in_commitment!());
|
||||
let htlcs_count: u64 = Readable::read(reader)?;
|
||||
let mut htlcs = Vec::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32));
|
||||
for _ in 0..htlcs_count {
|
||||
htlcs.push((read_htlc_in_commitment!(), read_option!().map(|o: HTLCSource| Box::new(o))));
|
||||
}
|
||||
let sources_count: u64 = Readable::read(reader)?;
|
||||
let mut sources = Vec::with_capacity(cmp::min(sources_count as usize, MAX_ALLOC_SIZE / 32));
|
||||
for _ in 0..sources_count {
|
||||
sources.push(read_htlc_source!());
|
||||
}
|
||||
if let Some(_) = remote_claimable_outpoints.insert(txid, (outputs, sources)) {
|
||||
if let Some(_) = remote_claimable_outpoints.insert(txid, htlcs) {
|
||||
return Err(DecodeError::InvalidValue);
|
||||
}
|
||||
}
|
||||
|
@ -2124,23 +2094,22 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
|
|||
let delayed_payment_key = Readable::read(reader)?;
|
||||
let feerate_per_kw: u64 = Readable::read(reader)?;
|
||||
|
||||
let htlc_outputs_len: u64 = Readable::read(reader)?;
|
||||
let mut htlc_outputs = Vec::with_capacity(cmp::min(htlc_outputs_len as usize, MAX_ALLOC_SIZE / 128));
|
||||
for _ in 0..htlc_outputs_len {
|
||||
let out = read_htlc_in_commitment!();
|
||||
let sigs = (Readable::read(reader)?, Readable::read(reader)?);
|
||||
htlc_outputs.push((out, sigs.0, sigs.1));
|
||||
}
|
||||
|
||||
let htlc_sources_len: u64 = Readable::read(reader)?;
|
||||
let mut htlc_sources = Vec::with_capacity(cmp::min(htlc_outputs_len as usize, MAX_ALLOC_SIZE / 128));
|
||||
for _ in 0..htlc_sources_len {
|
||||
htlc_sources.push(read_htlc_source!());
|
||||
let htlcs_len: u64 = Readable::read(reader)?;
|
||||
let mut htlcs = Vec::with_capacity(cmp::min(htlcs_len as usize, MAX_ALLOC_SIZE / 128));
|
||||
for _ in 0..htlcs_len {
|
||||
let htlc = read_htlc_in_commitment!();
|
||||
let sigs = match <u8 as Readable<R>>::read(reader)? {
|
||||
0 => None,
|
||||
1 => Some((Readable::read(reader)?, Readable::read(reader)?)),
|
||||
_ => return Err(DecodeError::InvalidValue),
|
||||
};
|
||||
htlcs.push((htlc, sigs, read_option!()));
|
||||
}
|
||||
|
||||
LocalSignedTx {
|
||||
txid: tx.txid(),
|
||||
tx, revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, feerate_per_kw, htlc_outputs, htlc_sources
|
||||
tx, revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, feerate_per_kw,
|
||||
htlc_outputs: htlcs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2220,7 +2189,7 @@ mod tests {
|
|||
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys};
|
||||
use util::test_utils::TestLogger;
|
||||
use secp256k1::key::{SecretKey,PublicKey};
|
||||
use secp256k1::{Secp256k1, Signature};
|
||||
use secp256k1::Secp256k1;
|
||||
use rand::{thread_rng,Rng};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -2583,7 +2552,6 @@ mod tests {
|
|||
fn test_prune_preimages() {
|
||||
let secp_ctx = Secp256k1::new();
|
||||
let logger = Arc::new(TestLogger::new());
|
||||
let dummy_sig = Signature::from_der(&secp_ctx, &hex::decode("3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd").unwrap()[..]).unwrap();
|
||||
|
||||
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
|
||||
macro_rules! dummy_keys {
|
||||
|
@ -2618,13 +2586,13 @@ mod tests {
|
|||
{
|
||||
let mut res = Vec::new();
|
||||
for (idx, preimage) in $preimages_slice.iter().enumerate() {
|
||||
res.push(HTLCOutputInCommitment {
|
||||
res.push((HTLCOutputInCommitment {
|
||||
offered: true,
|
||||
amount_msat: 0,
|
||||
cltv_expiry: 0,
|
||||
payment_hash: preimage.1.clone(),
|
||||
transaction_output_index: Some(idx as u32),
|
||||
});
|
||||
}, None));
|
||||
}
|
||||
res
|
||||
}
|
||||
|
@ -2634,7 +2602,7 @@ mod tests {
|
|||
($preimages_slice: expr) => {
|
||||
{
|
||||
let mut inp = preimages_slice_to_htlc_outputs!($preimages_slice);
|
||||
let res: Vec<_> = inp.drain(..).map(|e| { (e, dummy_sig.clone(), dummy_sig.clone()) }).collect();
|
||||
let res: Vec<_> = inp.drain(..).map(|e| { (e.0, None, e.1) }).collect();
|
||||
res
|
||||
}
|
||||
}
|
||||
|
@ -2653,11 +2621,11 @@ mod tests {
|
|||
let mut monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), &SecretKey::from_slice(&secp_ctx, &[44; 32]).unwrap(), &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[45; 32]).unwrap()), 0, Script::new(), logger.clone());
|
||||
monitor.set_their_to_self_delay(10);
|
||||
|
||||
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..10]), Vec::new());
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[5..15]), Vec::new(), 281474976710655, dummy_key);
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[15..20]), Vec::new(), 281474976710654, dummy_key);
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[17..20]), Vec::new(), 281474976710653, dummy_key);
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[18..20]), Vec::new(), 281474976710652, dummy_key);
|
||||
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..10]));
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key);
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654, dummy_key);
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653, dummy_key);
|
||||
monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652, dummy_key);
|
||||
for &(ref preimage, ref hash) in preimages.iter() {
|
||||
monitor.provide_payment_preimage(hash, preimage);
|
||||
}
|
||||
|
@ -2679,7 +2647,7 @@ mod tests {
|
|||
|
||||
// Now update local commitment tx info, pruning only element 18 as we still care about the
|
||||
// previous commitment tx's preimages too
|
||||
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..5]), Vec::new());
|
||||
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..5]));
|
||||
secret[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
|
||||
monitor.provide_secret(281474976710653, secret.clone()).unwrap();
|
||||
assert_eq!(monitor.payment_preimages.len(), 12);
|
||||
|
@ -2687,7 +2655,7 @@ mod tests {
|
|||
test_preimages_exist!(&preimages[18..20], monitor);
|
||||
|
||||
// But if we do it again, we'll prune 5-10
|
||||
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..3]), Vec::new());
|
||||
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..3]));
|
||||
secret[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
|
||||
monitor.provide_secret(281474976710652, secret.clone()).unwrap();
|
||||
assert_eq!(monitor.payment_preimages.len(), 5);
|
||||
|
|
Loading…
Add table
Reference in a new issue