Sign local HTLC transactions at broadcast-time, instead of generate

This commit is contained in:
Matt Corallo 2019-12-13 14:56:57 -05:00
parent eb97a7534d
commit e2e1628680
3 changed files with 113 additions and 168 deletions

View file

@ -14,7 +14,7 @@ use bitcoin_hashes::ripemd160::Hash as Ripemd160;
use bitcoin_hashes::hash160::Hash as Hash160; use bitcoin_hashes::hash160::Hash as Hash160;
use bitcoin_hashes::sha256d::Hash as Sha256dHash; use bitcoin_hashes::sha256d::Hash as Sha256dHash;
use ln::channelmanager::PaymentHash; use ln::channelmanager::{PaymentHash, PaymentPreimage};
use ln::msgs::DecodeError; use ln::msgs::DecodeError;
use util::ser::{Readable, Writeable, Writer, WriterWriteAdaptor}; use util::ser::{Readable, Writeable, Writer, WriterWriteAdaptor};
@ -63,7 +63,9 @@ pub(super) fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>,
base_point.combine(&hashkey) base_point.combine(&hashkey)
} }
/// Derives a revocation key from its constituent parts /// Derives a revocation key from its constituent parts.
/// Note that this is infallible iff we trust that at least one of the two input keys are randomly
/// generated (ie our own).
pub(super) fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> { pub(super) fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret); let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret);
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
@ -286,6 +288,43 @@ pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_s
} }
} }
/// Signs a transaction created by build_htlc_transaction. If the transaction is an
/// HTLC-Success transaction (ie htlc.offered is false), preimage must be set!
pub(crate) fn sign_htlc_transaction<T: secp256k1::Signing>(tx: &mut Transaction, their_sig: &Signature, preimage: &Option<PaymentPreimage>, htlc: &HTLCOutputInCommitment, a_htlc_key: &PublicKey, b_htlc_key: &PublicKey, revocation_key: &PublicKey, per_commitment_point: &PublicKey, htlc_base_key: &SecretKey, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Script), ()> {
if tx.input.len() != 1 { return Err(()); }
if tx.input[0].witness.len() != 0 { return Err(()); }
let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&htlc, a_htlc_key, b_htlc_key, revocation_key);
let our_htlc_key = derive_private_key(secp_ctx, per_commitment_point, htlc_base_key).map_err(|_| ())?;
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
let local_tx = PublicKey::from_secret_key(&secp_ctx, &our_htlc_key) == *a_htlc_key;
let our_sig = secp_ctx.sign(&sighash, &our_htlc_key);
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
if local_tx { // b, then a
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
} else {
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
}
tx.input[0].witness[1].push(SigHashType::All as u8);
tx.input[0].witness[2].push(SigHashType::All as u8);
if htlc.offered {
tx.input[0].witness.push(Vec::new());
assert!(preimage.is_none());
} else {
tx.input[0].witness.push(preimage.unwrap().0.to_vec());
}
tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec());
Ok((our_sig, htlc_redeemscript))
}
#[derive(Clone)] #[derive(Clone)]
/// We use this to track local commitment transactions and put off signing them until we are ready /// We use this to track local commitment transactions and put off signing them until we are ready
/// to broadcast. Eventually this will require a signer which is possibly external, but for now we /// to broadcast. Eventually this will require a signer which is possibly external, but for now we

View file

@ -1129,56 +1129,6 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
chan_utils::build_htlc_transaction(prev_hash, feerate_per_kw, if local { self.their_to_self_delay } else { self.our_to_self_delay }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key) chan_utils::build_htlc_transaction(prev_hash, feerate_per_kw, if local { self.their_to_self_delay } else { self.our_to_self_delay }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key)
} }
fn create_htlc_tx_signature(&self, tx: &Transaction, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<(Script, Signature, bool), ChannelError> {
if tx.input.len() != 1 {
panic!("Tried to sign HTLC transaction that had input count != 1!");
}
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, self.local_keys.htlc_base_key()), "Derived invalid key, peer is maliciously selecting parameters");
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
let is_local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key) == keys.a_htlc_key;
Ok((htlc_redeemscript, self.secp_ctx.sign(&sighash, &our_htlc_key), is_local_tx))
}
#[cfg(test)]
/// Signs a transaction created by build_htlc_transaction. If the transaction is an
/// HTLC-Success transaction (ie htlc.offered is false), preimage must be set!
/// TODO: Make this a chan_utils, use it in channelmonitor and tests, cause its unused now
fn sign_htlc_transaction(&self, tx: &mut Transaction, their_sig: &Signature, preimage: &Option<PaymentPreimage>, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<Signature, ChannelError> {
if tx.input.len() != 1 {
panic!("Tried to sign HTLC transaction that had input count != 1!");
}
if tx.input[0].witness.len() != 0 {
panic!("Tried to re-sign HTLC transaction");
}
let (htlc_redeemscript, our_sig, local_tx) = self.create_htlc_tx_signature(tx, htlc, keys)?;
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
if local_tx { // b, then a
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
} else {
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
}
tx.input[0].witness[1].push(SigHashType::All as u8);
tx.input[0].witness[2].push(SigHashType::All as u8);
if htlc.offered {
tx.input[0].witness.push(Vec::new());
} else {
tx.input[0].witness.push(preimage.unwrap().0.to_vec());
}
tx.input[0].witness.push(htlc_redeemscript.into_bytes());
Ok(our_sig)
}
/// Per HTLC, only one get_update_fail_htlc or get_update_fulfill_htlc call may be made. /// Per HTLC, only one get_update_fail_htlc or get_update_fulfill_htlc call may be made.
/// In such cases we debug_assert!(false) and return an IgnoreError. Thus, will always return /// In such cases we debug_assert!(false) and return an IgnoreError. Thus, will always return
/// Ok(_) if debug assertions are turned on and preconditions are met. /// Ok(_) if debug assertions are turned on and preconditions are met.
@ -1822,8 +1772,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
log_trace!(self, "Checking HTLC tx signature {} by key {} against tx {} with redeemscript {}", log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(local_keys.b_htlc_key.serialize()), encode::serialize_hex(&htlc_tx), encode::serialize_hex(&htlc_redeemscript)); log_trace!(self, "Checking HTLC tx signature {} by key {} against tx {} with redeemscript {}", log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(local_keys.b_htlc_key.serialize()), encode::serialize_hex(&htlc_tx), encode::serialize_hex(&htlc_redeemscript));
let htlc_sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]); let htlc_sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer"); 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 = self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1; htlcs_and_sigs.push((htlc, Some(msg.htlc_signatures[idx]), source));
htlcs_and_sigs.push((htlc, Some((msg.htlc_signatures[idx], htlc_sig)), source));
} else { } else {
htlcs_and_sigs.push((htlc, None, source)); htlcs_and_sigs.push((htlc, None, source));
} }
@ -4265,7 +4214,7 @@ mod tests {
assert!(preimage.is_some()); assert!(preimage.is_some());
} }
chan.sign_htlc_transaction(&mut htlc_tx, &remote_signature, &preimage, &htlc, &keys).unwrap(); chan_utils::sign_htlc_transaction(&mut htlc_tx, &remote_signature, &preimage, &htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key, &keys.per_commitment_point, chan.local_keys.htlc_base_key(), &chan.secp_ctx).unwrap();
assert_eq!(serialize(&htlc_tx)[..], assert_eq!(serialize(&htlc_tx)[..],
hex::decode($tx_hex).unwrap()[..]); hex::decode($tx_hex).unwrap()[..]);
}; };

View file

@ -337,8 +337,6 @@ enum Storage {
delayed_payment_base_key: SecretKey, delayed_payment_base_key: SecretKey,
payment_base_key: SecretKey, payment_base_key: SecretKey,
shutdown_pubkey: PublicKey, shutdown_pubkey: PublicKey,
prev_latest_per_commitment_point: Option<PublicKey>,
latest_per_commitment_point: Option<PublicKey>,
funding_info: Option<(OutPoint, Script)>, funding_info: Option<(OutPoint, Script)>,
current_remote_commitment_txid: Option<Sha256dHash>, current_remote_commitment_txid: Option<Sha256dHash>,
prev_remote_commitment_txid: Option<Sha256dHash>, prev_remote_commitment_txid: Option<Sha256dHash>,
@ -358,8 +356,9 @@ struct LocalSignedTx {
a_htlc_key: PublicKey, a_htlc_key: PublicKey,
b_htlc_key: PublicKey, b_htlc_key: PublicKey,
delayed_payment_key: PublicKey, delayed_payment_key: PublicKey,
per_commitment_point: PublicKey,
feerate_per_kw: u64, feerate_per_kw: u64,
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<(Signature, Signature)>, Option<HTLCSource>)>, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
} }
#[derive(PartialEq)] #[derive(PartialEq)]
@ -741,8 +740,6 @@ impl ChannelMonitor {
delayed_payment_base_key: delayed_payment_base_key.clone(), delayed_payment_base_key: delayed_payment_base_key.clone(),
payment_base_key: payment_base_key.clone(), payment_base_key: payment_base_key.clone(),
shutdown_pubkey: shutdown_pubkey.clone(), shutdown_pubkey: shutdown_pubkey.clone(),
prev_latest_per_commitment_point: None,
latest_per_commitment_point: None,
funding_info: None, funding_info: None,
current_remote_commitment_txid: None, current_remote_commitment_txid: None,
prev_remote_commitment_txid: None, prev_remote_commitment_txid: None,
@ -969,9 +966,7 @@ impl ChannelMonitor {
/// is important that any clones of this channel monitor (including remote clones) by kept /// is important that any clones of this channel monitor (including remote clones) by kept
/// up-to-date as our local commitment transaction is updated. /// up-to-date as our local commitment transaction is updated.
/// Panics if set_their_to_self_delay has never been called. /// 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 pub(super) fn provide_latest_local_commitment_tx_info(&mut self, commitment_tx: LocalCommitmentTransaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>) {
/// case of onchain HTLC tx
pub(super) fn provide_latest_local_commitment_tx_info(&mut self, commitment_tx: LocalCommitmentTransaction, 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()); assert!(self.their_to_self_delay.is_some());
self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take(); self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take();
self.current_local_signed_commitment_tx = Some(LocalSignedTx { self.current_local_signed_commitment_tx = Some(LocalSignedTx {
@ -981,15 +976,10 @@ impl ChannelMonitor {
a_htlc_key: local_keys.a_htlc_key, a_htlc_key: local_keys.a_htlc_key,
b_htlc_key: local_keys.b_htlc_key, b_htlc_key: local_keys.b_htlc_key,
delayed_payment_key: local_keys.a_delayed_payment_key, delayed_payment_key: local_keys.a_delayed_payment_key,
per_commitment_point: local_keys.per_commitment_point,
feerate_per_kw, feerate_per_kw,
htlc_outputs, htlc_outputs,
}); });
if let Storage::Local { ref mut latest_per_commitment_point, .. } = self.key_storage {
*latest_per_commitment_point = Some(local_keys.per_commitment_point);
} else {
panic!("Channel somehow ended up with its internal ChannelMonitor being in Watchtower mode?");
}
} }
/// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all /// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all
@ -1152,7 +1142,7 @@ impl ChannelMonitor {
} }
match self.key_storage { match self.key_storage {
Storage::Local { ref funding_key, ref revocation_base_key, ref htlc_base_key, ref delayed_payment_base_key, ref payment_base_key, ref shutdown_pubkey, ref prev_latest_per_commitment_point, ref latest_per_commitment_point, ref funding_info, ref current_remote_commitment_txid, ref prev_remote_commitment_txid } => { Storage::Local { ref funding_key, ref revocation_base_key, ref htlc_base_key, ref delayed_payment_base_key, ref payment_base_key, ref shutdown_pubkey, ref funding_info, ref current_remote_commitment_txid, ref prev_remote_commitment_txid } => {
writer.write_all(&[0; 1])?; writer.write_all(&[0; 1])?;
writer.write_all(&funding_key[..])?; writer.write_all(&funding_key[..])?;
writer.write_all(&revocation_base_key[..])?; writer.write_all(&revocation_base_key[..])?;
@ -1160,8 +1150,6 @@ impl ChannelMonitor {
writer.write_all(&delayed_payment_base_key[..])?; writer.write_all(&delayed_payment_base_key[..])?;
writer.write_all(&payment_base_key[..])?; writer.write_all(&payment_base_key[..])?;
writer.write_all(&shutdown_pubkey.serialize())?; writer.write_all(&shutdown_pubkey.serialize())?;
prev_latest_per_commitment_point.write(writer)?;
latest_per_commitment_point.write(writer)?;
match funding_info { match funding_info {
&Some((ref outpoint, ref script)) => { &Some((ref outpoint, ref script)) => {
writer.write_all(&outpoint.txid[..])?; writer.write_all(&outpoint.txid[..])?;
@ -1256,15 +1244,15 @@ impl ChannelMonitor {
writer.write_all(&$local_tx.a_htlc_key.serialize())?; writer.write_all(&$local_tx.a_htlc_key.serialize())?;
writer.write_all(&$local_tx.b_htlc_key.serialize())?; writer.write_all(&$local_tx.b_htlc_key.serialize())?;
writer.write_all(&$local_tx.delayed_payment_key.serialize())?; writer.write_all(&$local_tx.delayed_payment_key.serialize())?;
writer.write_all(&$local_tx.per_commitment_point.serialize())?;
writer.write_all(&byte_utils::be64_to_array($local_tx.feerate_per_kw))?; 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))?; writer.write_all(&byte_utils::be64_to_array($local_tx.htlc_outputs.len() as u64))?;
for &(ref htlc_output, ref sigs, ref htlc_source) in $local_tx.htlc_outputs.iter() { for &(ref htlc_output, ref sig, ref htlc_source) in $local_tx.htlc_outputs.iter() {
serialize_htlc_in_commitment!(htlc_output); serialize_htlc_in_commitment!(htlc_output);
if let &Some((ref their_sig, ref our_sig)) = sigs { if let &Some(ref their_sig) = sig {
1u8.write(writer)?; 1u8.write(writer)?;
writer.write_all(&their_sig.serialize_compact())?; writer.write_all(&their_sig.serialize_compact())?;
writer.write_all(&our_sig.serialize_compact())?;
} else { } else {
0u8.write(writer)?; 0u8.write(writer)?;
} }
@ -2087,7 +2075,7 @@ impl ChannelMonitor {
} else { (None, None) } } else { (None, None) }
} }
fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option<PublicKey>, delayed_payment_base_key: &Option<SecretKey>, height: u32) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>, Vec<TxOut>, Vec<(Sha256dHash, ClaimTxBumpMaterial)>) { fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, delayed_payment_base_key: &SecretKey, height: u32) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>, Vec<TxOut>, Vec<(Sha256dHash, ClaimTxBumpMaterial)>) {
let mut res = Vec::with_capacity(local_tx.htlc_outputs.len()); let mut res = Vec::with_capacity(local_tx.htlc_outputs.len());
let mut spendable_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); let mut spendable_outputs = Vec::with_capacity(local_tx.htlc_outputs.len());
let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len());
@ -2095,18 +2083,14 @@ impl ChannelMonitor {
macro_rules! add_dynamic_output { macro_rules! add_dynamic_output {
($father_tx: expr, $vout: expr) => { ($father_tx: expr, $vout: expr) => {
if let Some(ref per_commitment_point) = *per_commitment_point { if let Ok(local_delayedkey) = chan_utils::derive_private_key(&self.secp_ctx, &local_tx.per_commitment_point, delayed_payment_base_key) {
if let Some(ref delayed_payment_base_key) = *delayed_payment_base_key { spendable_outputs.push(SpendableOutputDescriptor::DynamicOutputP2WSH {
if let Ok(local_delayedkey) = chan_utils::derive_private_key(&self.secp_ctx, per_commitment_point, delayed_payment_base_key) { outpoint: BitcoinOutPoint { txid: $father_tx.txid(), vout: $vout },
spendable_outputs.push(SpendableOutputDescriptor::DynamicOutputP2WSH { key: local_delayedkey,
outpoint: BitcoinOutPoint { txid: $father_tx.txid(), vout: $vout }, witness_script: chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.our_to_self_delay, &local_tx.delayed_payment_key),
key: local_delayedkey, to_self_delay: self.our_to_self_delay,
witness_script: chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.our_to_self_delay, &local_tx.delayed_payment_key), output: $father_tx.output[$vout as usize].clone(),
to_self_delay: self.our_to_self_delay, });
output: $father_tx.output[$vout as usize].clone(),
});
}
}
} }
} }
} }
@ -2120,60 +2104,50 @@ impl ChannelMonitor {
} }
} }
for &(ref htlc, ref sigs, _) in local_tx.htlc_outputs.iter() { if let &Storage::Local { ref htlc_base_key, .. } = &self.key_storage {
if let Some(transaction_output_index) = htlc.transaction_output_index { for &(ref htlc, ref sigs, _) in local_tx.htlc_outputs.iter() {
if let &Some((ref their_sig, ref our_sig)) = sigs { if let Some(transaction_output_index) = htlc.transaction_output_index {
if htlc.offered { if let &Some(ref their_sig) = sigs {
log_trace!(self, "Broadcasting HTLC-Timeout transaction against local commitment transactions"); 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); log_trace!(self, "Broadcasting HTLC-Timeout transaction against local commitment transactions");
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);
let (our_sig, htlc_script) = match
chan_utils::sign_htlc_transaction(&mut htlc_timeout_tx, their_sig, &None, htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key, &local_tx.per_commitment_point, htlc_base_key, &self.secp_ctx) {
Ok(res) => res,
Err(_) => continue,
};
htlc_timeout_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy add_dynamic_output!(htlc_timeout_tx, 0);
htlc_timeout_tx.input[0].witness.push(their_sig.serialize_der().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().to_vec());
htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8);
htlc_timeout_tx.input[0].witness.push(Vec::new());
let htlc_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key);
htlc_timeout_tx.input[0].witness.push(htlc_script.clone().into_bytes());
add_dynamic_output!(htlc_timeout_tx, 0);
let height_timer = Self::get_height_timer(height, htlc.cltv_expiry);
let mut per_input_material = HashMap::with_capacity(1);
per_input_material.insert(htlc_timeout_tx.input[0].previous_output, InputMaterial::LocalHTLC { script: htlc_script, sigs: (*their_sig, *our_sig), preimage: None, amount: htlc.amount_msat / 1000});
//TODO: with option_simplified_commitment track outpoint too
log_trace!(self, "Outpoint {}:{} is being being claimed, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}", htlc_timeout_tx.input[0].previous_output.vout, htlc_timeout_tx.input[0].previous_output.txid, height_timer);
pending_claims.push((htlc_timeout_tx.txid(), ClaimTxBumpMaterial { height_timer, feerate_previous: 0, soonest_timelock: htlc.cltv_expiry, per_input_material }));
res.push(htlc_timeout_tx);
} else {
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
log_trace!(self, "Broadcasting HTLC-Success transaction against local commitment transactions");
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(their_sig.serialize_der().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().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());
let htlc_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key);
htlc_success_tx.input[0].witness.push(htlc_script.clone().into_bytes());
add_dynamic_output!(htlc_success_tx, 0);
let height_timer = Self::get_height_timer(height, htlc.cltv_expiry); let height_timer = Self::get_height_timer(height, htlc.cltv_expiry);
let mut per_input_material = HashMap::with_capacity(1); let mut per_input_material = HashMap::with_capacity(1);
per_input_material.insert(htlc_success_tx.input[0].previous_output, InputMaterial::LocalHTLC { script: htlc_script, sigs: (*their_sig, *our_sig), preimage: Some(*payment_preimage), amount: htlc.amount_msat / 1000}); per_input_material.insert(htlc_timeout_tx.input[0].previous_output, InputMaterial::LocalHTLC { script: htlc_script, sigs: (*their_sig, our_sig), preimage: None, amount: htlc.amount_msat / 1000});
//TODO: with option_simplified_commitment track outpoint too //TODO: with option_simplified_commitment track outpoint too
log_trace!(self, "Outpoint {}:{} is being being claimed, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}", htlc_success_tx.input[0].previous_output.vout, htlc_success_tx.input[0].previous_output.txid, height_timer); log_trace!(self, "Outpoint {}:{} is being being claimed, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}", htlc_timeout_tx.input[0].previous_output.vout, htlc_timeout_tx.input[0].previous_output.txid, height_timer);
pending_claims.push((htlc_success_tx.txid(), ClaimTxBumpMaterial { height_timer, feerate_previous: 0, soonest_timelock: htlc.cltv_expiry, per_input_material })); pending_claims.push((htlc_timeout_tx.txid(), ClaimTxBumpMaterial { height_timer, feerate_previous: 0, soonest_timelock: htlc.cltv_expiry, per_input_material }));
res.push(htlc_success_tx); res.push(htlc_timeout_tx);
} else {
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
log_trace!(self, "Broadcasting HTLC-Success transaction against local commitment transactions");
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);
let (our_sig, htlc_script) = match
chan_utils::sign_htlc_transaction(&mut htlc_success_tx, their_sig, &Some(*payment_preimage), htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key, &local_tx.per_commitment_point, htlc_base_key, &self.secp_ctx) {
Ok(res) => res,
Err(_) => continue,
};
add_dynamic_output!(htlc_success_tx, 0);
let height_timer = Self::get_height_timer(height, htlc.cltv_expiry);
let mut per_input_material = HashMap::with_capacity(1);
per_input_material.insert(htlc_success_tx.input[0].previous_output, InputMaterial::LocalHTLC { script: htlc_script, sigs: (*their_sig, our_sig), preimage: Some(*payment_preimage), amount: htlc.amount_msat / 1000});
//TODO: with option_simplified_commitment track outpoint too
log_trace!(self, "Outpoint {}:{} is being being claimed, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}", htlc_success_tx.input[0].previous_output.vout, htlc_success_tx.input[0].previous_output.txid, height_timer);
pending_claims.push((htlc_success_tx.txid(), ClaimTxBumpMaterial { height_timer, feerate_previous: 0, soonest_timelock: htlc.cltv_expiry, per_input_material }));
res.push(htlc_success_tx);
}
} }
} watch_outputs.push(local_tx.tx.without_valid_witness().output[transaction_output_index as usize].clone());
watch_outputs.push(local_tx.tx.without_valid_witness().output[transaction_output_index as usize].clone()); } else { panic!("Should have sigs for non-dust local tx outputs!") }
} else { panic!("Should have sigs for non-dust local tx outputs!") } }
} }
} }
@ -2245,12 +2219,10 @@ impl ChannelMonitor {
log_trace!(self, "Got latest local commitment tx broadcast, searching for available HTLCs to claim"); log_trace!(self, "Got latest local commitment tx broadcast, searching for available HTLCs to claim");
assert!(local_tx.tx.has_local_sig()); assert!(local_tx.tx.has_local_sig());
match self.key_storage { match self.key_storage {
Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { Storage::Local { ref delayed_payment_base_key, .. } => {
append_onchain_update!(self.broadcast_by_local_state(local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key), height)); append_onchain_update!(self.broadcast_by_local_state(local_tx, delayed_payment_base_key, height));
}, },
Storage::Watchtower { .. } => { Storage::Watchtower { .. } => { }
append_onchain_update!(self.broadcast_by_local_state(local_tx, &None, &None, height));
}
} }
} }
} }
@ -2270,12 +2242,10 @@ impl ChannelMonitor {
log_trace!(self, "Got previous local commitment tx broadcast, searching for available HTLCs to claim"); log_trace!(self, "Got previous local commitment tx broadcast, searching for available HTLCs to claim");
assert!(local_tx.tx.has_local_sig()); assert!(local_tx.tx.has_local_sig());
match self.key_storage { match self.key_storage {
Storage::Local { ref delayed_payment_base_key, ref prev_latest_per_commitment_point, .. } => { Storage::Local { ref delayed_payment_base_key, .. } => {
append_onchain_update!(self.broadcast_by_local_state(local_tx, prev_latest_per_commitment_point, &Some(*delayed_payment_base_key), height)); append_onchain_update!(self.broadcast_by_local_state(local_tx, delayed_payment_base_key, height));
}, },
Storage::Watchtower { .. } => { Storage::Watchtower { .. } => { }
append_onchain_update!(self.broadcast_by_local_state(local_tx, &None, &None, height));
}
} }
} }
} }
@ -2351,8 +2321,8 @@ impl ChannelMonitor {
if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
let mut res = vec![local_tx.tx.with_valid_witness().clone()]; let mut res = vec![local_tx.tx.with_valid_witness().clone()];
match self.key_storage { match self.key_storage {
Storage::Local { ref delayed_payment_base_key, ref prev_latest_per_commitment_point, .. } => { Storage::Local { ref delayed_payment_base_key, .. } => {
res.append(&mut self.broadcast_by_local_state(local_tx, prev_latest_per_commitment_point, &Some(*delayed_payment_base_key), 0).0); res.append(&mut self.broadcast_by_local_state(local_tx, delayed_payment_base_key, 0).0);
// We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do. // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
// The data will be re-generated and tracked in check_spend_local_transaction if we get a confirmation. // The data will be re-generated and tracked in check_spend_local_transaction if we get a confirmation.
}, },
@ -2524,8 +2494,8 @@ impl ChannelMonitor {
log_trace!(self, "Broadcast onchain {}", log_tx!(cur_local_tx.tx.with_valid_witness())); log_trace!(self, "Broadcast onchain {}", log_tx!(cur_local_tx.tx.with_valid_witness()));
broadcaster.broadcast_transaction(&cur_local_tx.tx.with_valid_witness()); broadcaster.broadcast_transaction(&cur_local_tx.tx.with_valid_witness());
match self.key_storage { match self.key_storage {
Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { Storage::Local { ref delayed_payment_base_key, .. } => {
let (txs, mut spendable_output, new_outputs, _) = self.broadcast_by_local_state(&cur_local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key), height); let (txs, mut spendable_output, new_outputs, _) = self.broadcast_by_local_state(&cur_local_tx, delayed_payment_base_key, height);
spendable_outputs.append(&mut spendable_output); spendable_outputs.append(&mut spendable_output);
if !new_outputs.is_empty() { if !new_outputs.is_empty() {
watch_outputs.push((cur_local_tx.txid.clone(), new_outputs)); watch_outputs.push((cur_local_tx.txid.clone(), new_outputs));
@ -2535,17 +2505,7 @@ impl ChannelMonitor {
broadcaster.broadcast_transaction(&tx); broadcaster.broadcast_transaction(&tx);
} }
}, },
Storage::Watchtower { .. } => { Storage::Watchtower { .. } => { },
let (txs, mut spendable_output, new_outputs, _) = self.broadcast_by_local_state(&cur_local_tx, &None, &None, height);
spendable_outputs.append(&mut spendable_output);
if !new_outputs.is_empty() {
watch_outputs.push((cur_local_tx.txid.clone(), new_outputs));
}
for tx in txs {
log_trace!(self, "Broadcast onchain {}", log_tx!(tx));
broadcaster.broadcast_transaction(&tx);
}
}
} }
} }
} }
@ -3010,8 +2970,6 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
let delayed_payment_base_key = Readable::read(reader)?; let delayed_payment_base_key = Readable::read(reader)?;
let payment_base_key = Readable::read(reader)?; let payment_base_key = Readable::read(reader)?;
let shutdown_pubkey = Readable::read(reader)?; let shutdown_pubkey = Readable::read(reader)?;
let prev_latest_per_commitment_point = Readable::read(reader)?;
let latest_per_commitment_point = Readable::read(reader)?;
// Technically this can fail and serialize fail a round-trip, but only for serialization of // Technically this can fail and serialize fail a round-trip, but only for serialization of
// barely-init'd ChannelMonitors that we can't do anything with. // barely-init'd ChannelMonitors that we can't do anything with.
let outpoint = OutPoint { let outpoint = OutPoint {
@ -3028,8 +2986,6 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
delayed_payment_base_key, delayed_payment_base_key,
payment_base_key, payment_base_key,
shutdown_pubkey, shutdown_pubkey,
prev_latest_per_commitment_point,
latest_per_commitment_point,
funding_info, funding_info,
current_remote_commitment_txid, current_remote_commitment_txid,
prev_remote_commitment_txid, prev_remote_commitment_txid,
@ -3130,6 +3086,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
let a_htlc_key = Readable::read(reader)?; let a_htlc_key = Readable::read(reader)?;
let b_htlc_key = Readable::read(reader)?; let b_htlc_key = Readable::read(reader)?;
let delayed_payment_key = Readable::read(reader)?; let delayed_payment_key = Readable::read(reader)?;
let per_commitment_point = Readable::read(reader)?;
let feerate_per_kw: u64 = Readable::read(reader)?; let feerate_per_kw: u64 = Readable::read(reader)?;
let htlcs_len: u64 = Readable::read(reader)?; let htlcs_len: u64 = Readable::read(reader)?;
@ -3138,7 +3095,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
let htlc = read_htlc_in_commitment!(); let htlc = read_htlc_in_commitment!();
let sigs = match <u8 as Readable<R>>::read(reader)? { let sigs = match <u8 as Readable<R>>::read(reader)? {
0 => None, 0 => None,
1 => Some((Readable::read(reader)?, Readable::read(reader)?)), 1 => Some(Readable::read(reader)?),
_ => return Err(DecodeError::InvalidValue), _ => return Err(DecodeError::InvalidValue),
}; };
htlcs.push((htlc, sigs, Readable::read(reader)?)); htlcs.push((htlc, sigs, Readable::read(reader)?));
@ -3146,7 +3103,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
LocalSignedTx { LocalSignedTx {
txid: tx.txid(), txid: tx.txid(),
tx, revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, feerate_per_kw, tx, revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, per_commitment_point, feerate_per_kw,
htlc_outputs: htlcs htlc_outputs: htlcs
} }
} }