X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=inline;f=lightning%2Fsrc%2Fln%2Fchannelmonitor.rs;h=205f4b011ac0fb32d62304f5bf1e3ceadbbf2ca1;hb=d850e1234a21f0107a9700870b43a00d71f60e80;hp=a8fdb32aa3f7c1cda9ac20299cc48f839e4251be;hpb=3d640da5c343111f538f006996c13c9a98e0d9e6;p=rust-lightning diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index a8fdb32a..205f4b01 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -451,21 +451,21 @@ struct LocalSignedTx { #[derive(Clone, PartialEq)] pub(crate) enum InputMaterial { Revoked { - script: Script, + witness_script: Script, pubkey: Option, key: SecretKey, is_htlc: bool, amount: u64, }, RemoteHTLC { - script: Script, + witness_script: Script, key: SecretKey, preimage: Option, amount: u64, locktime: u32, }, LocalHTLC { - script: Script, + witness_script: Script, sigs: (Signature, Signature), preimage: Option, amount: u64, @@ -475,25 +475,25 @@ pub(crate) enum InputMaterial { impl Writeable for InputMaterial { fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { match self { - &InputMaterial::Revoked { ref script, ref pubkey, ref key, ref is_htlc, ref amount} => { + &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref is_htlc, ref amount} => { writer.write_all(&[0; 1])?; - script.write(writer)?; + witness_script.write(writer)?; pubkey.write(writer)?; writer.write_all(&key[..])?; is_htlc.write(writer)?; writer.write_all(&byte_utils::be64_to_array(*amount))?; }, - &InputMaterial::RemoteHTLC { ref script, ref key, ref preimage, ref amount, ref locktime } => { + &InputMaterial::RemoteHTLC { ref witness_script, ref key, ref preimage, ref amount, ref locktime } => { writer.write_all(&[1; 1])?; - script.write(writer)?; + witness_script.write(writer)?; key.write(writer)?; preimage.write(writer)?; writer.write_all(&byte_utils::be64_to_array(*amount))?; writer.write_all(&byte_utils::be32_to_array(*locktime))?; }, - &InputMaterial::LocalHTLC { ref script, ref sigs, ref preimage, ref amount } => { + &InputMaterial::LocalHTLC { ref witness_script, ref sigs, ref preimage, ref amount } => { writer.write_all(&[2; 1])?; - script.write(writer)?; + witness_script.write(writer)?; sigs.0.write(writer)?; sigs.1.write(writer)?; preimage.write(writer)?; @@ -508,13 +508,13 @@ impl Readable for InputMaterial { fn read(reader: &mut R) -> Result { let input_material = match ::read(reader)? { 0 => { - let script = Readable::read(reader)?; + let witness_script = Readable::read(reader)?; let pubkey = Readable::read(reader)?; let key = Readable::read(reader)?; let is_htlc = Readable::read(reader)?; let amount = Readable::read(reader)?; InputMaterial::Revoked { - script, + witness_script, pubkey, key, is_htlc, @@ -522,13 +522,13 @@ impl Readable for InputMaterial { } }, 1 => { - let script = Readable::read(reader)?; + let witness_script = Readable::read(reader)?; let key = Readable::read(reader)?; let preimage = Readable::read(reader)?; let amount = Readable::read(reader)?; let locktime = Readable::read(reader)?; InputMaterial::RemoteHTLC { - script, + witness_script, key, preimage, amount, @@ -536,13 +536,13 @@ impl Readable for InputMaterial { } }, 2 => { - let script = Readable::read(reader)?; + let witness_script = Readable::read(reader)?; let their_sig = Readable::read(reader)?; let our_sig = Readable::read(reader)?; let preimage = Readable::read(reader)?; let amount = Readable::read(reader)?; InputMaterial::LocalHTLC { - script, + witness_script, sigs: (their_sig, our_sig), preimage, amount @@ -554,6 +554,28 @@ impl Readable for InputMaterial { } } +/// ClaimRequest is a descriptor structure to communicate between detection +/// and reaction module. They are generated by ChannelMonitor while parsing +/// onchain txn leaked from a channel and handed over to OnchainTxHandler which +/// is responsible for opportunistic aggregation, selecting and enforcing +/// bumping logic, building and signing transactions. +pub(crate) struct ClaimRequest { + // Block height before which claiming is exclusive to one party, + // after reaching it, claiming may be contentious. + pub(crate) absolute_timelock: u32, + // Timeout tx must have nLocktime set which means aggregating multiple + // ones must take the higher nLocktime among them to satisfy all of them. + // Sadly it has few pitfalls, a) it takes longuer to get fund back b) CLTV_DELTA + // of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set. + // Do simplify we mark them as non-aggregable. + pub(crate) aggregable: bool, + // Basic bitcoin outpoint (txid, vout) + pub(crate) outpoint: BitcoinOutPoint, + // Following outpoint type, set of data needed to generate transaction digest + // and satisfy witness program. + pub(crate) witness_data: InputMaterial +} + /// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it /// once they mature to enough confirmations (ANTI_REORG_DELAY) #[derive(Clone, PartialEq)] @@ -1385,7 +1407,7 @@ impl ChannelMonitor { /// HTLC-Success/HTLC-Timeout transactions. /// Return updates for HTLC pending in the channel and failed automatically by the broadcast of /// revoked remote commitment tx - fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec<(u32, bool, BitcoinOutPoint, InputMaterial)>, (Sha256dHash, Vec), Vec) { + fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec, (Sha256dHash, Vec), Vec) { // Most secp and related errors trying to create keys means we have no hope of constructing // a spend transaction...so we return no transactions to broadcast let mut claimable_outpoints = Vec::new(); @@ -1439,7 +1461,8 @@ 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 { - claimable_outpoints.push((height + self.our_to_self_delay as u32, true, BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, InputMaterial::Revoked { 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, is_htlc: false, 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}); } else if Some(&outp.script_pubkey) == local_payment_p2wpkh.as_ref() { spendable_outputs.push(SpendableOutputDescriptor::DynamicOutputP2WPKH { outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, @@ -1459,7 +1482,8 @@ impl ChannelMonitor { tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { return (claimable_outpoints, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user } - claimable_outpoints.push((htlc.cltv_expiry, true, BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, InputMaterial::Revoked { 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, is_htlc: true, 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 }); } } } @@ -1622,7 +1646,8 @@ impl ChannelMonitor { let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None }; let aggregable = if !htlc.offered { false } else { true }; if preimage.is_some() || !htlc.offered { - claimable_outpoints.push((htlc.cltv_expiry, aggregable, BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, InputMaterial::RemoteHTLC { script: expected_script, key: htlc_privkey, preimage, amount: htlc.amount_msat / 1000, locktime: htlc.cltv_expiry })); + let witness_data = InputMaterial::RemoteHTLC { witness_script: expected_script, key: htlc_privkey, preimage, amount: htlc.amount_msat / 1000, locktime: htlc.cltv_expiry }; + claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } } @@ -1643,7 +1668,7 @@ impl ChannelMonitor { } /// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key - fn check_spend_remote_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32) -> Vec<(u32, bool, BitcoinOutPoint, InputMaterial)> { + fn check_spend_remote_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32) -> Vec { //TODO: send back new outputs to guarantee pending_claim_request consistency if tx.input.len() != 1 || tx.output.len() != 1 || tx.input[0].witness.len() != 5 { return Vec::new() @@ -1676,7 +1701,8 @@ impl ChannelMonitor { let htlc_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers! log_trace!(self, "Remote HTLC broadcast {}:{}", htlc_txid, 0); - let claimable_outpoints = vec!((height + self.our_to_self_delay as u32, true, BitcoinOutPoint { txid: htlc_txid, vout: 0}, InputMaterial::Revoked { 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, is_htlc: false, 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 } @@ -1723,7 +1749,7 @@ impl ChannelMonitor { add_dynamic_output!(htlc_timeout_tx, 0); 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}); + per_input_material.insert(htlc_timeout_tx.input[0].previous_output, InputMaterial::LocalHTLC { witness_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", htlc_timeout_tx.input[0].previous_output.vout, htlc_timeout_tx.input[0].previous_output.txid); res.push(htlc_timeout_tx); @@ -1739,7 +1765,7 @@ impl ChannelMonitor { add_dynamic_output!(htlc_success_tx, 0); 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_success_tx.input[0].previous_output, InputMaterial::LocalHTLC { witness_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", htlc_success_tx.input[0].previous_output.vout, htlc_success_tx.input[0].previous_output.txid); res.push(htlc_success_tx); @@ -1984,7 +2010,7 @@ impl ChannelMonitor { watch_outputs.push(new_outputs); } } - claimable_outpoints.push(new_outpoints); + claimable_outpoints.append(&mut new_outpoints); } if !funding_txo.is_none() && claimable_outpoints.is_empty() { if let Some(spendable_output) = self.check_spend_closing_transaction(&tx) { @@ -1994,7 +2020,7 @@ impl ChannelMonitor { } else { if let Some(&(commitment_number, _)) = self.remote_commitment_txn_on_chain.get(&prevout.txid) { let mut new_outpoints = self.check_spend_remote_htlc(&tx, commitment_number, height); - claimable_outpoints.push(new_outpoints); + claimable_outpoints.append(&mut new_outpoints); } } } @@ -2050,7 +2076,7 @@ impl ChannelMonitor { } } } - let mut spendable_output = self.onchain_tx_handler.block_connected(txn_matched, claimable_outpoints, height, broadcaster, &*fee_estimator); + let mut spendable_output = self.onchain_tx_handler.block_connected(txn_matched, claimable_outpoints, height, &*broadcaster, &*fee_estimator); spendable_outputs.append(&mut spendable_output); self.last_block_hash = block_hash.clone();