From 3a5301010b9aa0de469293a11e0fa7b6ca7adb01 Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Mon, 23 Mar 2020 21:22:14 -0400 Subject: [PATCH 1/5] Cache remote basepoint and remote_csv in new OnchainTxHandler::RemoteTxCache Used in next commits to avoid passing script between ChannelMonitor and OnchainTxHandler. ChannelMonitor duplicata will be removed in future commits. --- lightning/src/ln/channelmonitor.rs | 6 ++--- lightning/src/ln/onchaintx.rs | 35 +++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index c417671eca0..16532c2e27f 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -1064,7 +1064,7 @@ impl ChannelMonitor { let our_channel_close_key_hash = Hash160::hash(&shutdown_pubkey.serialize()); let shutdown_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script(); - let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), their_to_self_delay, logger.clone()); + let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), their_to_self_delay, their_delayed_payment_base_key.clone(), their_htlc_base_key.clone(), our_to_self_delay, logger.clone()); let local_tx_sequence = initial_local_commitment_tx.unsigned_tx.input[0].sequence as u64; let local_tx_locktime = initial_local_commitment_tx.unsigned_tx.lock_time as u64; @@ -1099,8 +1099,8 @@ impl ChannelMonitor { current_remote_commitment_txid: None, prev_remote_commitment_txid: None, - their_htlc_base_key: their_htlc_base_key.clone(), - their_delayed_payment_base_key: their_delayed_payment_base_key.clone(), + their_htlc_base_key: *their_htlc_base_key, + their_delayed_payment_base_key: *their_delayed_payment_base_key, funding_redeemscript, channel_value_satoshis: channel_value_satoshis, their_cur_revocation_points: None, diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 49572f2cb8b..0779bab52f8 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -11,6 +11,7 @@ use bitcoin::util::bip143; use bitcoin_hashes::sha256d::Hash as Sha256dHash; use secp256k1::{Secp256k1, Signature}; +use secp256k1::key::PublicKey; use secp256k1; use ln::msgs::DecodeError; @@ -48,6 +49,13 @@ enum OnchainEvent { } } +/// Cache remote basepoint to compute any transaction on +/// remote outputs, either justice or preimage/timeout transactions. +struct RemoteTxCache { + remote_delayed_payment_base_key: PublicKey, + remote_htlc_base_key: PublicKey +} + /// Higher-level cache structure needed to re-generate bumped claim txn if needed #[derive(Clone, PartialEq)] pub struct ClaimTxBumpMaterial { @@ -195,6 +203,8 @@ pub struct OnchainTxHandler { prev_local_commitment: Option, prev_local_htlc_sigs: Option>>, local_csv: u16, + remote_tx_cache: RemoteTxCache, + remote_csv: u16, key_storage: ChanSigner, @@ -241,6 +251,10 @@ impl OnchainTxHandler { self.local_csv.write(writer)?; + self.remote_tx_cache.remote_delayed_payment_base_key.write(writer)?; + self.remote_tx_cache.remote_htlc_base_key.write(writer)?; + self.remote_csv.write(writer)?; + self.key_storage.write(writer)?; writer.write_all(&byte_utils::be64_to_array(self.pending_claim_requests.len() as u64))?; @@ -289,6 +303,16 @@ impl ReadableArgs> for OnchainTx let local_csv = Readable::read(reader)?; + let remote_tx_cache = { + let remote_delayed_payment_base_key = Readable::read(reader)?; + let remote_htlc_base_key = Readable::read(reader)?; + RemoteTxCache { + remote_delayed_payment_base_key, + remote_htlc_base_key, + } + }; + let remote_csv = Readable::read(reader)?; + let key_storage = Readable::read(reader)?; let pending_claim_requests_len: u64 = Readable::read(reader)?; @@ -341,6 +365,8 @@ impl ReadableArgs> for OnchainTx prev_local_commitment, prev_local_htlc_sigs, local_csv, + remote_tx_cache, + remote_csv, key_storage, claimable_outpoints, pending_claim_requests, @@ -352,10 +378,15 @@ impl ReadableArgs> for OnchainTx } impl OnchainTxHandler { - pub(super) fn new(destination_script: Script, keys: ChanSigner, local_csv: u16, logger: Arc) -> Self { + pub(super) fn new(destination_script: Script, keys: ChanSigner, local_csv: u16, remote_delayed_payment_base_key: PublicKey, remote_htlc_base_key: PublicKey, remote_csv: u16, logger: Arc) -> Self { let key_storage = keys; + let remote_tx_cache = RemoteTxCache { + remote_delayed_payment_base_key, + remote_htlc_base_key, + }; + OnchainTxHandler { destination_script, local_commitment: None, @@ -363,6 +394,8 @@ impl OnchainTxHandler { prev_local_commitment: None, prev_local_htlc_sigs: None, local_csv, + remote_tx_cache, + remote_csv, key_storage, pending_claim_requests: HashMap::new(), claimable_outpoints: HashMap::new(), From 8cd604b710150e09b8812ead31ab5ba67e2de4fe Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Mon, 23 Mar 2020 22:17:46 -0400 Subject: [PATCH 2/5] Cache remote HTLC inside OnchainTxHandler::RemoteTxCache As we can't predict if any and which revoked commitment tx is going to appear onchain we have by design to cache all htlc information to regenerate htlc script if needed. --- lightning/src/ln/channelmonitor.rs | 9 +++++++- lightning/src/ln/onchaintx.rs | 33 ++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index 16532c2e27f..8d7bdfdf604 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -1205,7 +1205,7 @@ impl ChannelMonitor { log_trace!(self, "New potential remote commitment transaction: {}", encode::serialize_hex(unsigned_commitment_tx)); self.prev_remote_commitment_txid = self.current_remote_commitment_txid.take(); self.current_remote_commitment_txid = Some(new_txid); - self.remote_claimable_outpoints.insert(new_txid, htlc_outputs); + self.remote_claimable_outpoints.insert(new_txid, htlc_outputs.clone()); 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 { @@ -1226,6 +1226,13 @@ impl ChannelMonitor { self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None)); } } + let mut htlcs = Vec::with_capacity(htlc_outputs.len()); + for htlc in htlc_outputs { + if htlc.0.transaction_output_index.is_some() { + htlcs.push(htlc.0); + } + } + self.onchain_tx_handler.provide_latest_remote_tx(new_txid, htlcs); } pub(super) fn provide_rescue_remote_commitment_tx_info(&mut self, their_revocation_point: PublicKey) { diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 0779bab52f8..d2000bd6fba 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -17,7 +17,7 @@ use secp256k1; use ln::msgs::DecodeError; use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest}; use ln::channelmanager::PaymentPreimage; -use ln::chan_utils::{HTLCType, LocalCommitmentTransaction}; +use ln::chan_utils::{HTLCType, LocalCommitmentTransaction, HTLCOutputInCommitment}; use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; use chain::keysinterface::ChannelKeys; use util::logger::Logger; @@ -53,7 +53,8 @@ enum OnchainEvent { /// remote outputs, either justice or preimage/timeout transactions. struct RemoteTxCache { remote_delayed_payment_base_key: PublicKey, - remote_htlc_base_key: PublicKey + remote_htlc_base_key: PublicKey, + per_htlc: HashMap> } /// Higher-level cache structure needed to re-generate bumped claim txn if needed @@ -253,6 +254,14 @@ impl OnchainTxHandler { self.remote_tx_cache.remote_delayed_payment_base_key.write(writer)?; self.remote_tx_cache.remote_htlc_base_key.write(writer)?; + writer.write_all(&byte_utils::be64_to_array(self.remote_tx_cache.per_htlc.len() as u64))?; + for (ref txid, ref htlcs) in self.remote_tx_cache.per_htlc.iter() { + writer.write_all(&txid[..])?; + writer.write_all(&byte_utils::be64_to_array(htlcs.len() as u64))?; + for &ref htlc in htlcs.iter() { + htlc.write(writer)?; + } + } self.remote_csv.write(writer)?; self.key_storage.write(writer)?; @@ -306,9 +315,24 @@ impl ReadableArgs> for OnchainTx let remote_tx_cache = { let remote_delayed_payment_base_key = Readable::read(reader)?; let remote_htlc_base_key = Readable::read(reader)?; + let per_htlc_len: u64 = Readable::read(reader)?; + let mut per_htlc = HashMap::with_capacity(cmp::min(per_htlc_len as usize, MAX_ALLOC_SIZE / 64)); + for _ in 0..per_htlc_len { + let txid: Sha256dHash = Readable::read(reader)?; + 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 { + let htlc = Readable::read(reader)?; + htlcs.push(htlc); + } + if let Some(_) = per_htlc.insert(txid, htlcs) { + return Err(DecodeError::InvalidValue); + } + } RemoteTxCache { remote_delayed_payment_base_key, remote_htlc_base_key, + per_htlc, } }; let remote_csv = Readable::read(reader)?; @@ -385,6 +409,7 @@ impl OnchainTxHandler { let remote_tx_cache = RemoteTxCache { remote_delayed_payment_base_key, remote_htlc_base_key, + per_htlc: HashMap::new(), }; OnchainTxHandler { @@ -903,6 +928,10 @@ impl OnchainTxHandler { } } + pub(super) fn provide_latest_remote_tx(&mut self, commitment_txid: Sha256dHash, htlcs: Vec) { + self.remote_tx_cache.per_htlc.insert(commitment_txid, htlcs); + } + #[cfg(test)] pub(super) fn get_fully_signed_copy_local_tx(&mut self, funding_redeemscript: &Script) -> Option { if let Some(ref mut local_commitment) = self.local_commitment { From cd9a66eb4b9fda5e9305385259daf28124f27214 Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Mon, 23 Mar 2020 23:28:00 -0400 Subject: [PATCH 3/5] Replace is_htlc in InputMaterial by InputDescriptor As we cache more and more transaction elements in OnchainTxHandler we should dry up completly InputMaterial until them being replaced directly by InputDescriptor --- lightning/src/ln/channelmonitor.rs | 18 ++++----- lightning/src/ln/onchaintx.rs | 63 ++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index 8d7bdfdf604..626335e4bee 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -32,7 +32,7 @@ use ln::msgs::DecodeError; use ln::chan_utils; use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, LocalCommitmentTransaction, HTLCType}; use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; -use ln::onchaintx::OnchainTxHandler; +use ln::onchaintx::{OnchainTxHandler, InputDescriptors}; use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface, FeeEstimator}; use chain::transaction::OutPoint; use chain::keysinterface::{SpendableOutputDescriptor, ChannelKeys}; @@ -428,7 +428,7 @@ pub(crate) enum InputMaterial { witness_script: Script, pubkey: Option, key: SecretKey, - is_htlc: bool, + input_descriptor: InputDescriptors, amount: u64, }, RemoteHTLC { @@ -450,12 +450,12 @@ pub(crate) enum InputMaterial { impl Writeable for InputMaterial { fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { match self { - &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref is_htlc, ref amount} => { + &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref input_descriptor, ref amount} => { writer.write_all(&[0; 1])?; witness_script.write(writer)?; pubkey.write(writer)?; writer.write_all(&key[..])?; - is_htlc.write(writer)?; + input_descriptor.write(writer)?; writer.write_all(&byte_utils::be64_to_array(*amount))?; }, &InputMaterial::RemoteHTLC { ref witness_script, ref key, ref preimage, ref amount, ref locktime } => { @@ -487,13 +487,13 @@ impl Readable for InputMaterial { let witness_script = Readable::read(reader)?; let pubkey = Readable::read(reader)?; let key = Readable::read(reader)?; - let is_htlc = Readable::read(reader)?; + let input_descriptor = Readable::read(reader)?; let amount = Readable::read(reader)?; InputMaterial::Revoked { witness_script, pubkey, key, - is_htlc, + input_descriptor, amount } }, @@ -1474,7 +1474,7 @@ impl ChannelMonitor { // First, process non-htlc outputs (to_local & to_remote) for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { - let witness_data = InputMaterial::Revoked { witness_script: revokeable_redeemscript.clone(), pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: false, amount: outp.value }; + let witness_data = InputMaterial::Revoked { witness_script: revokeable_redeemscript.clone(), pubkey: Some(revocation_pubkey), key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value }; claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data}); } } @@ -1489,7 +1489,7 @@ impl ChannelMonitor { tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } - let witness_data = InputMaterial::Revoked { witness_script: expected_script, pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: true, amount: tx.output[transaction_output_index as usize].value }; + let witness_data = InputMaterial::Revoked { witness_script: expected_script, pubkey: Some(revocation_pubkey), key: revocation_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value }; claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } @@ -1668,7 +1668,7 @@ impl ChannelMonitor { let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); log_trace!(self, "Remote HTLC broadcast {}:{}", htlc_txid, 0); - let witness_data = InputMaterial::Revoked { witness_script: redeemscript, pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: false, amount: tx.output[0].value }; + let witness_data = InputMaterial::Revoked { witness_script: redeemscript, pubkey: Some(revocation_pubkey), key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value }; let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data }); (claimable_outpoints, Some((htlc_txid, tx.output.clone()))) } diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index d2000bd6fba..db89cb7ff4d 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -17,7 +17,7 @@ use secp256k1; use ln::msgs::DecodeError; use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest}; use ln::channelmanager::PaymentPreimage; -use ln::chan_utils::{HTLCType, LocalCommitmentTransaction, HTLCOutputInCommitment}; +use ln::chan_utils::{LocalCommitmentTransaction, HTLCOutputInCommitment}; use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; use chain::keysinterface::ChannelKeys; use util::logger::Logger; @@ -102,8 +102,8 @@ impl Readable for ClaimTxBumpMaterial { } } -#[derive(PartialEq)] -pub(super) enum InputDescriptors { +#[derive(PartialEq, Clone, Copy)] +pub(crate) enum InputDescriptors { RevokedOfferedHTLC, RevokedReceivedHTLC, OfferedHTLC, @@ -111,6 +111,53 @@ pub(super) enum InputDescriptors { RevokedOutput, // either a revoked to_local output on commitment tx, a revoked HTLC-Timeout output or a revoked HTLC-Success output } +impl Writeable for InputDescriptors { + fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + match self { + &InputDescriptors::RevokedOfferedHTLC => { + writer.write_all(&[0; 1])?; + }, + &InputDescriptors::RevokedReceivedHTLC => { + writer.write_all(&[1; 1])?; + }, + &InputDescriptors::OfferedHTLC => { + writer.write_all(&[2; 1])?; + }, + &InputDescriptors::ReceivedHTLC => { + writer.write_all(&[3; 1])?; + } + &InputDescriptors::RevokedOutput => { + writer.write_all(&[4; 1])?; + } + } + Ok(()) + } +} + +impl Readable for InputDescriptors { + fn read(reader: &mut R) -> Result { + let input_descriptor = match ::read(reader)? { + 0 => { + InputDescriptors::RevokedOfferedHTLC + }, + 1 => { + InputDescriptors::RevokedReceivedHTLC + }, + 2 => { + InputDescriptors::OfferedHTLC + }, + 3 => { + InputDescriptors::ReceivedHTLC + }, + 4 => { + InputDescriptors::RevokedOutput + } + _ => return Err(DecodeError::InvalidValue), + }; + Ok(input_descriptor) + } +} + macro_rules! subtract_high_prio_fee { ($self: ident, $fee_estimator: expr, $value: expr, $predicted_weight: expr, $used_feerate: expr) => { { @@ -548,8 +595,8 @@ impl OnchainTxHandler { let mut dynamic_fee = true; for per_outp_material in cached_claim_datas.per_input_material.values() { match per_outp_material { - &InputMaterial::Revoked { ref witness_script, ref is_htlc, ref amount, .. } => { - inputs_witnesses_weight += Self::get_witnesses_weight(if !is_htlc { &[InputDescriptors::RevokedOutput] } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::OfferedHTLC) { &[InputDescriptors::RevokedOfferedHTLC] } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::AcceptedHTLC) { &[InputDescriptors::RevokedReceivedHTLC] } else { unreachable!() }); + &InputMaterial::Revoked { ref input_descriptor, ref amount, .. } => { + inputs_witnesses_weight += Self::get_witnesses_weight(&[*input_descriptor]); amt += *amount; }, &InputMaterial::RemoteHTLC { ref preimage, ref amount, .. } => { @@ -587,19 +634,19 @@ impl OnchainTxHandler { for (i, (outp, per_outp_material)) in cached_claim_datas.per_input_material.iter().enumerate() { match per_outp_material { - &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref is_htlc, ref amount } => { + &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref input_descriptor, ref amount } => { let sighash_parts = bip143::SighashComponents::new(&bumped_tx); let sighash = hash_to_message!(&sighash_parts.sighash_all(&bumped_tx.input[i], &witness_script, *amount)[..]); let sig = self.secp_ctx.sign(&sighash, &key); bumped_tx.input[i].witness.push(sig.serialize_der().to_vec()); bumped_tx.input[i].witness[0].push(SigHashType::All as u8); - if *is_htlc { + if *input_descriptor != InputDescriptors::RevokedOutput { bumped_tx.input[i].witness.push(pubkey.unwrap().clone().serialize().to_vec()); } else { bumped_tx.input[i].witness.push(vec!(1)); } bumped_tx.input[i].witness.push(witness_script.clone().into_bytes()); - log_trace!(self, "Going to broadcast Penalty Transaction {} claiming revoked {} output {} from {} with new feerate {}...", bumped_tx.txid(), if !is_htlc { "to_local" } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::OfferedHTLC) { "offered" } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::AcceptedHTLC) { "received" } else { "" }, outp.vout, outp.txid, new_feerate); + log_trace!(self, "Going to broadcast Penalty Transaction {} claiming revoked {} output {} from {} with new feerate {}...", bumped_tx.txid(), if *input_descriptor == InputDescriptors::RevokedOutput { "to_local" } else if *input_descriptor == InputDescriptors::RevokedOfferedHTLC { "offered" } else if *input_descriptor == InputDescriptors::RevokedReceivedHTLC { "received" } else { "" }, outp.vout, outp.txid, new_feerate); }, &InputMaterial::RemoteHTLC { ref witness_script, ref key, ref preimage, ref amount, ref locktime } => { if !preimage.is_some() { bumped_tx.lock_time = *locktime }; // Right now we don't aggregate time-locked transaction, if we do we should set lock_time before to avoid breaking hash computation From 13b6e4fc473984e9c1ff57b797f904d6e11a66a0 Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Mon, 23 Mar 2020 21:50:23 -0400 Subject: [PATCH 4/5] Build witness_script for justice tx inside OnchainTxHandler By moving script generation inside OnchainTxHandler, we may dry-up further ChannelMonitor in next commits. --- lightning/src/ln/channelmonitor.rs | 29 ++++++------------ lightning/src/ln/onchaintx.rs | 49 ++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index 626335e4bee..28f926a077d 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -425,8 +425,7 @@ struct LocalSignedTx { #[derive(Clone, PartialEq)] pub(crate) enum InputMaterial { Revoked { - witness_script: Script, - pubkey: Option, + per_commitment_point: PublicKey, key: SecretKey, input_descriptor: InputDescriptors, amount: u64, @@ -450,10 +449,9 @@ pub(crate) enum InputMaterial { impl Writeable for InputMaterial { fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { match self { - &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref input_descriptor, ref amount} => { + &InputMaterial::Revoked { ref per_commitment_point, ref key, ref input_descriptor, ref amount} => { writer.write_all(&[0; 1])?; - witness_script.write(writer)?; - pubkey.write(writer)?; + per_commitment_point.write(writer)?; writer.write_all(&key[..])?; input_descriptor.write(writer)?; writer.write_all(&byte_utils::be64_to_array(*amount))?; @@ -484,14 +482,12 @@ impl Readable for InputMaterial { fn read(reader: &mut R) -> Result { let input_material = match ::read(reader)? { 0 => { - let witness_script = Readable::read(reader)?; - let pubkey = Readable::read(reader)?; + let per_commitment_point = Readable::read(reader)?; let key = Readable::read(reader)?; let input_descriptor = Readable::read(reader)?; let amount = Readable::read(reader)?; InputMaterial::Revoked { - witness_script, - pubkey, + per_commitment_point, key, input_descriptor, amount @@ -1456,10 +1452,8 @@ impl ChannelMonitor { let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().revocation_basepoint)); let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); - let b_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().htlc_basepoint)); let local_payment_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, &per_commitment_point, &self.keys.payment_base_key())); let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key)); - let a_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_htlc_base_key)); let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh(); @@ -1474,7 +1468,7 @@ impl ChannelMonitor { // First, process non-htlc outputs (to_local & to_remote) for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { - let witness_data = InputMaterial::Revoked { witness_script: revokeable_redeemscript.clone(), pubkey: Some(revocation_pubkey), key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value }; claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data}); } } @@ -1483,13 +1477,11 @@ impl ChannelMonitor { if let Some(ref per_commitment_data) = per_commitment_option { for (_, &(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() || - tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 || - tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { + tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } - let witness_data = InputMaterial::Revoked { witness_script: expected_script, pubkey: Some(revocation_pubkey), key: revocation_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, key: revocation_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value }; claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } @@ -1662,13 +1654,10 @@ impl ChannelMonitor { let secret = if let Some(secret) = self.get_secret(commitment_number) { secret } else { return (Vec::new(), None); }; let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); - let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().revocation_basepoint)); let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); - let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &self.their_delayed_payment_base_key)); - let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); log_trace!(self, "Remote HTLC broadcast {}:{}", htlc_txid, 0); - let witness_data = InputMaterial::Revoked { witness_script: redeemscript, pubkey: Some(revocation_pubkey), key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value }; let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data }); (claimable_outpoints, Some((htlc_txid, tx.output.clone()))) } diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index db89cb7ff4d..50868a70abe 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -17,7 +17,8 @@ use secp256k1; use ln::msgs::DecodeError; use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest}; use ln::channelmanager::PaymentPreimage; -use ln::chan_utils::{LocalCommitmentTransaction, HTLCOutputInCommitment}; +use ln::chan_utils; +use ln::chan_utils::{TxCreationKeys, LocalCommitmentTransaction, HTLCOutputInCommitment}; use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT}; use chain::keysinterface::ChannelKeys; use util::logger::Logger; @@ -634,19 +635,41 @@ impl OnchainTxHandler { for (i, (outp, per_outp_material)) in cached_claim_datas.per_input_material.iter().enumerate() { match per_outp_material { - &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref input_descriptor, ref amount } => { - let sighash_parts = bip143::SighashComponents::new(&bumped_tx); - let sighash = hash_to_message!(&sighash_parts.sighash_all(&bumped_tx.input[i], &witness_script, *amount)[..]); - let sig = self.secp_ctx.sign(&sighash, &key); - bumped_tx.input[i].witness.push(sig.serialize_der().to_vec()); - bumped_tx.input[i].witness[0].push(SigHashType::All as u8); - if *input_descriptor != InputDescriptors::RevokedOutput { - bumped_tx.input[i].witness.push(pubkey.unwrap().clone().serialize().to_vec()); - } else { - bumped_tx.input[i].witness.push(vec!(1)); + &InputMaterial::Revoked { ref per_commitment_point, ref key, ref input_descriptor, ref amount } => { + if let Ok(chan_keys) = TxCreationKeys::new(&self.secp_ctx, &per_commitment_point, &self.remote_tx_cache.remote_delayed_payment_base_key, &self.remote_tx_cache.remote_htlc_base_key, &self.key_storage.pubkeys().revocation_basepoint, &self.key_storage.pubkeys().payment_basepoint, &self.key_storage.pubkeys().htlc_basepoint) { + + let mut this_htlc = None; + if *input_descriptor != InputDescriptors::RevokedOutput { + if let Some(htlcs) = self.remote_tx_cache.per_htlc.get(&outp.txid) { + for htlc in htlcs { + if htlc.transaction_output_index.unwrap() == outp.vout { + this_htlc = Some(htlc); + } + } + } + } + + let witness_script = if *input_descriptor != InputDescriptors::RevokedOutput && this_htlc.is_some() { + chan_utils::get_htlc_redeemscript_with_explicit_keys(&this_htlc.unwrap(), &chan_keys.a_htlc_key, &chan_keys.b_htlc_key, &chan_keys.revocation_key) + } else if *input_descriptor != InputDescriptors::RevokedOutput { + return None; + } else { + chan_utils::get_revokeable_redeemscript(&chan_keys.revocation_key, self.remote_csv, &chan_keys.a_delayed_payment_key) + }; + + let sighash_parts = bip143::SighashComponents::new(&bumped_tx); + let sighash = hash_to_message!(&sighash_parts.sighash_all(&bumped_tx.input[i], &witness_script, *amount)[..]); + let sig = self.secp_ctx.sign(&sighash, &key); + bumped_tx.input[i].witness.push(sig.serialize_der().to_vec()); + bumped_tx.input[i].witness[0].push(SigHashType::All as u8); + if *input_descriptor != InputDescriptors::RevokedOutput { + bumped_tx.input[i].witness.push(chan_keys.revocation_key.clone().serialize().to_vec()); + } else { + bumped_tx.input[i].witness.push(vec!(1)); + } + bumped_tx.input[i].witness.push(witness_script.clone().into_bytes()); + log_trace!(self, "Going to broadcast Penalty Transaction {} claiming revoked {} output {} from {} with new feerate {}...", bumped_tx.txid(), if *input_descriptor == InputDescriptors::RevokedOutput { "to_local" } else if *input_descriptor == InputDescriptors::RevokedOfferedHTLC { "offered" } else if *input_descriptor == InputDescriptors::RevokedReceivedHTLC { "received" } else { "" }, outp.vout, outp.txid, new_feerate); } - bumped_tx.input[i].witness.push(witness_script.clone().into_bytes()); - log_trace!(self, "Going to broadcast Penalty Transaction {} claiming revoked {} output {} from {} with new feerate {}...", bumped_tx.txid(), if *input_descriptor == InputDescriptors::RevokedOutput { "to_local" } else if *input_descriptor == InputDescriptors::RevokedOfferedHTLC { "offered" } else if *input_descriptor == InputDescriptors::RevokedReceivedHTLC { "received" } else { "" }, outp.vout, outp.txid, new_feerate); }, &InputMaterial::RemoteHTLC { ref witness_script, ref key, ref preimage, ref amount, ref locktime } => { if !preimage.is_some() { bumped_tx.lock_time = *locktime }; // Right now we don't aggregate time-locked transaction, if we do we should set lock_time before to avoid breaking hash computation From abf18a1d0cdf3ee33e1a59a0e236129677b7db9b Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Tue, 24 Mar 2020 14:22:16 -0400 Subject: [PATCH 5/5] Move justice transaction signature behind ChanSigner --- lightning/src/chain/keysinterface.rs | 21 ++++++++++++++++++++- lightning/src/ln/chan_utils.rs | 2 +- lightning/src/ln/channelmonitor.rs | 18 ++++++++---------- lightning/src/ln/onchaintx.rs | 15 +++------------ lightning/src/util/enforcing_trait_impls.rs | 5 +++++ 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 73c22684c54..2178d5a2683 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -2,7 +2,7 @@ //! spendable on-chain outputs which the user owns and is responsible for using just as any other //! on-chain output which is theirs. -use bitcoin::blockdata::transaction::{Transaction, OutPoint, TxOut}; +use bitcoin::blockdata::transaction::{Transaction, OutPoint, TxOut, SigHashType}; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; use bitcoin::network::constants::Network; @@ -245,6 +245,9 @@ pub trait ChannelKeys : Send+Clone { /// return value must contain a signature. fn sign_local_commitment_htlc_transactions(&self, local_commitment_tx: &LocalCommitmentTransaction, local_csv: u16, secp_ctx: &Secp256k1) -> Result>, ()>; + /// Signs a justice transaction. + fn sign_justice_transaction(&self, bumped_tx: &mut Transaction, input: usize, witness_script: &Script, amount: u64, per_commitment_key: &SecretKey, revocation_pubkey: &PublicKey, is_htlc: bool, secp_ctx: &Secp256k1); + /// Create a signature for a (proposed) closing transaction. /// /// Note that, due to rounding, there may be one "missing" satoshi, and either party may have @@ -393,6 +396,22 @@ impl ChannelKeys for InMemoryChannelKeys { local_commitment_tx.get_htlc_sigs(&self.htlc_base_key, local_csv, secp_ctx) } + fn sign_justice_transaction(&self, bumped_tx: &mut Transaction, input: usize, witness_script: &Script, amount: u64, per_commitment_key: &SecretKey, revocation_pubkey: &PublicKey, is_htlc: bool, secp_ctx: &Secp256k1) { + if let Ok(revocation_key) = chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key) { + let sighash_parts = bip143::SighashComponents::new(&bumped_tx); + let sighash = hash_to_message!(&sighash_parts.sighash_all(&bumped_tx.input[input], &witness_script, amount)[..]); + let sig = secp_ctx.sign(&sighash, &revocation_key); + bumped_tx.input[input].witness.push(sig.serialize_der().to_vec()); + bumped_tx.input[input].witness[0].push(SigHashType::All as u8); + if is_htlc { + bumped_tx.input[input].witness.push(revocation_pubkey.clone().serialize().to_vec()); + } else { + bumped_tx.input[input].witness.push(vec!(1)); + } + bumped_tx.input[input].witness.push(witness_script.clone().into_bytes()); + } + } + fn sign_closing_transaction(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1) -> Result { if closing_tx.input.len() != 1 { return Err(()); } if closing_tx.input[0].witness.len() != 0 { return Err(()); } diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 62d3103337d..3794e8a9402 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -198,7 +198,7 @@ pub(super) fn derive_public_key(secp_ctx: &Secp256k1, /// 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(secp_ctx: &Secp256k1, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result { +pub fn derive_private_revocation_key(secp_ctx: &Secp256k1, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result { 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); diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index 28f926a077d..d283147a5a9 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -426,7 +426,7 @@ struct LocalSignedTx { pub(crate) enum InputMaterial { Revoked { per_commitment_point: PublicKey, - key: SecretKey, + per_commitment_key: SecretKey, input_descriptor: InputDescriptors, amount: u64, }, @@ -449,10 +449,10 @@ pub(crate) enum InputMaterial { impl Writeable for InputMaterial { fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { match self { - &InputMaterial::Revoked { ref per_commitment_point, ref key, ref input_descriptor, ref amount} => { + &InputMaterial::Revoked { ref per_commitment_point, ref per_commitment_key, ref input_descriptor, ref amount} => { writer.write_all(&[0; 1])?; per_commitment_point.write(writer)?; - writer.write_all(&key[..])?; + writer.write_all(&per_commitment_key[..])?; input_descriptor.write(writer)?; writer.write_all(&byte_utils::be64_to_array(*amount))?; }, @@ -483,12 +483,12 @@ impl Readable for InputMaterial { let input_material = match ::read(reader)? { 0 => { let per_commitment_point = Readable::read(reader)?; - let key = Readable::read(reader)?; + let per_commitment_key = Readable::read(reader)?; let input_descriptor = Readable::read(reader)?; let amount = Readable::read(reader)?; InputMaterial::Revoked { per_commitment_point, - key, + per_commitment_key, input_descriptor, amount } @@ -1451,7 +1451,6 @@ impl ChannelMonitor { let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().revocation_basepoint)); - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); let local_payment_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, &per_commitment_point, &self.keys.payment_base_key())); let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key)); @@ -1468,7 +1467,7 @@ impl ChannelMonitor { // First, process non-htlc outputs (to_local & to_remote) for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { - let witness_data = InputMaterial::Revoked { per_commitment_point, key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value }; claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data}); } } @@ -1481,7 +1480,7 @@ impl ChannelMonitor { tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } - let witness_data = InputMaterial::Revoked { per_commitment_point, key: revocation_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, per_commitment_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value }; claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } @@ -1654,10 +1653,9 @@ impl ChannelMonitor { let secret = if let Some(secret) = self.get_secret(commitment_number) { secret } else { return (Vec::new(), None); }; let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); log_trace!(self, "Remote HTLC broadcast {}:{}", htlc_txid, 0); - let witness_data = InputMaterial::Revoked { per_commitment_point, key: revocation_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value }; let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data }); (claimable_outpoints, Some((htlc_txid, tx.output.clone()))) } diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 50868a70abe..3e95c0354bc 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -635,7 +635,7 @@ impl OnchainTxHandler { for (i, (outp, per_outp_material)) in cached_claim_datas.per_input_material.iter().enumerate() { match per_outp_material { - &InputMaterial::Revoked { ref per_commitment_point, ref key, ref input_descriptor, ref amount } => { + &InputMaterial::Revoked { ref per_commitment_point, ref per_commitment_key, ref input_descriptor, ref amount } => { if let Ok(chan_keys) = TxCreationKeys::new(&self.secp_ctx, &per_commitment_point, &self.remote_tx_cache.remote_delayed_payment_base_key, &self.remote_tx_cache.remote_htlc_base_key, &self.key_storage.pubkeys().revocation_basepoint, &self.key_storage.pubkeys().payment_basepoint, &self.key_storage.pubkeys().htlc_basepoint) { let mut this_htlc = None; @@ -657,17 +657,8 @@ impl OnchainTxHandler { chan_utils::get_revokeable_redeemscript(&chan_keys.revocation_key, self.remote_csv, &chan_keys.a_delayed_payment_key) }; - let sighash_parts = bip143::SighashComponents::new(&bumped_tx); - let sighash = hash_to_message!(&sighash_parts.sighash_all(&bumped_tx.input[i], &witness_script, *amount)[..]); - let sig = self.secp_ctx.sign(&sighash, &key); - bumped_tx.input[i].witness.push(sig.serialize_der().to_vec()); - bumped_tx.input[i].witness[0].push(SigHashType::All as u8); - if *input_descriptor != InputDescriptors::RevokedOutput { - bumped_tx.input[i].witness.push(chan_keys.revocation_key.clone().serialize().to_vec()); - } else { - bumped_tx.input[i].witness.push(vec!(1)); - } - bumped_tx.input[i].witness.push(witness_script.clone().into_bytes()); + self.key_storage.sign_justice_transaction(&mut bumped_tx, i, &witness_script, *amount, &per_commitment_key, &chan_keys.revocation_key, *input_descriptor != InputDescriptors::RevokedOutput, &self.secp_ctx); + log_trace!(self, "Going to broadcast Penalty Transaction {} claiming revoked {} output {} from {} with new feerate {}...", bumped_tx.txid(), if *input_descriptor == InputDescriptors::RevokedOutput { "to_local" } else if *input_descriptor == InputDescriptors::RevokedOfferedHTLC { "offered" } else if *input_descriptor == InputDescriptors::RevokedReceivedHTLC { "received" } else { "" }, outp.vout, outp.txid, new_feerate); } }, diff --git a/lightning/src/util/enforcing_trait_impls.rs b/lightning/src/util/enforcing_trait_impls.rs index 3e1ffd04446..a54ded65efa 100644 --- a/lightning/src/util/enforcing_trait_impls.rs +++ b/lightning/src/util/enforcing_trait_impls.rs @@ -6,6 +6,7 @@ use std::cmp; use std::sync::{Mutex, Arc}; use bitcoin::blockdata::transaction::Transaction; +use bitcoin::blockdata::script::Script; use bitcoin::util::bip143; use secp256k1; @@ -105,6 +106,10 @@ impl ChannelKeys for EnforcingChannelKeys { Ok(self.inner.sign_local_commitment_htlc_transactions(local_commitment_tx, local_csv, secp_ctx).unwrap()) } + fn sign_justice_transaction(&self, bumped_tx: &mut Transaction, input: usize, witness_script: &Script, amount: u64, per_commitment_key: &SecretKey, revocation_pubkey: &PublicKey, is_htlc: bool, secp_ctx: &Secp256k1) { + self.inner.sign_justice_transaction(bumped_tx, input, witness_script, amount, per_commitment_key, revocation_pubkey, is_htlc, secp_ctx); + } + fn sign_closing_transaction(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1) -> Result { Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap()) }