X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Fln%2Fonchaintx.rs;h=7ee0ccb100fb145b33a7d30cf1561966adb77ea2;hb=824e318be3c58e2a316ab62e0ede0e343c9b9031;hp=7e84132e481b3c11799d4b6e8f27c0f281bb8a20;hpb=275814cc1db90b72b2f44272f33cd1346395231a;p=rust-lightning diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 7e84132e..7ee0ccb1 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -17,7 +17,8 @@ use bitcoin::secp256k1::key::PublicKey; 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; +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; @@ -53,7 +54,7 @@ enum OnchainEvent { struct RemoteTxCache { remote_delayed_payment_base_key: PublicKey, remote_htlc_base_key: PublicKey, - per_htlc: HashMap> + per_htlc: HashMap> } /// Higher-level cache structure needed to re-generate bumped claim txn if needed @@ -101,8 +102,8 @@ impl Readable for ClaimTxBumpMaterial { } } -#[derive(PartialEq)] -pub(super) enum InputDescriptors { +#[derive(PartialEq, Clone, Copy)] +pub(crate) enum InputDescriptors { RevokedOfferedHTLC, RevokedReceivedHTLC, OfferedHTLC, @@ -110,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 { ($logger: ident, $fee_estimator: expr, $value: expr, $predicted_weight: expr, $used_feerate: expr) => { { @@ -316,7 +364,7 @@ impl Readable for OnchainTxHandler 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, .. } => { @@ -584,19 +632,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 is_htlc, 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 { - 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().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!(logger, "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!(logger, "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); }, &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 @@ -927,7 +997,7 @@ impl OnchainTxHandler { } } - pub(super) fn provide_latest_remote_tx(&mut self, commitment_txid: Sha256dHash, htlcs: Vec) { + pub(super) fn provide_latest_remote_tx(&mut self, commitment_txid: Txid, htlcs: Vec) { self.remote_tx_cache.per_htlc.insert(commitment_txid, htlcs); }