Skip to content

Commit b06c551

Browse files
author
Antoine Riard
committed
Integrate PackageTemplate
This commit replaces InputMaterial in both ChannelMonitor/OnchainTxHandler. This doesn't change behavior.
1 parent 6db0f4d commit b06c551

File tree

3 files changed

+106
-346
lines changed

3 files changed

+106
-346
lines changed

lightning/src/ln/channelmonitor.rs

Lines changed: 24 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
2323
use bitcoin::blockdata::block::BlockHeader;
2424
use bitcoin::blockdata::transaction::{TxOut, Transaction};
25-
use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
2625
use bitcoin::blockdata::script::{Script, Builder};
2726
use bitcoin::blockdata::opcodes;
2827
use bitcoin::consensus::encode;
@@ -40,7 +39,7 @@ use ln::chan_utils;
4039
use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HolderCommitmentTransaction, HTLCType};
4140
use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
4241
use ln::onchaintx::OnchainTxHandler;
43-
use ln::onchain_utils::InputDescriptors;
42+
use ln::onchain_utils::{InputDescriptors, PackageTemplate};
4443
use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface, FeeEstimator};
4544
use chain::transaction::OutPoint;
4645
use chain::keysinterface::{SpendableOutputDescriptor, ChannelKeys};
@@ -459,129 +458,6 @@ impl Readable for CounterpartyCommitmentTransaction {
459458
}
460459
}
461460

462-
/// When ChannelMonitor discovers an onchain outpoint being a step of a channel and that it needs
463-
/// to generate a tx to push channel state forward, we cache outpoint-solving tx material to build
464-
/// a new bumped one in case of lenghty confirmation delay
465-
#[derive(Clone, PartialEq)]
466-
pub(crate) enum InputMaterial {
467-
Revoked {
468-
per_commitment_point: PublicKey,
469-
counterparty_delayed_payment_base_key: PublicKey,
470-
counterparty_htlc_base_key: PublicKey,
471-
per_commitment_key: SecretKey,
472-
input_descriptor: InputDescriptors,
473-
amount: u64,
474-
htlc: Option<HTLCOutputInCommitment>,
475-
on_counterparty_tx_csv: u16,
476-
},
477-
CounterpartyHTLC {
478-
per_commitment_point: PublicKey,
479-
counterparty_delayed_payment_base_key: PublicKey,
480-
counterparty_htlc_base_key: PublicKey,
481-
preimage: Option<PaymentPreimage>,
482-
htlc: HTLCOutputInCommitment
483-
},
484-
HolderHTLC {
485-
preimage: Option<PaymentPreimage>,
486-
amount: u64,
487-
},
488-
Funding {
489-
funding_redeemscript: Script,
490-
}
491-
}
492-
493-
impl Writeable for InputMaterial {
494-
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
495-
match self {
496-
&InputMaterial::Revoked { ref per_commitment_point, ref counterparty_delayed_payment_base_key, ref counterparty_htlc_base_key, ref per_commitment_key, ref input_descriptor, ref amount, ref htlc, ref on_counterparty_tx_csv} => {
497-
writer.write_all(&[0; 1])?;
498-
per_commitment_point.write(writer)?;
499-
counterparty_delayed_payment_base_key.write(writer)?;
500-
counterparty_htlc_base_key.write(writer)?;
501-
writer.write_all(&per_commitment_key[..])?;
502-
input_descriptor.write(writer)?;
503-
writer.write_all(&byte_utils::be64_to_array(*amount))?;
504-
htlc.write(writer)?;
505-
on_counterparty_tx_csv.write(writer)?;
506-
},
507-
&InputMaterial::CounterpartyHTLC { ref per_commitment_point, ref counterparty_delayed_payment_base_key, ref counterparty_htlc_base_key, ref preimage, ref htlc} => {
508-
writer.write_all(&[1; 1])?;
509-
per_commitment_point.write(writer)?;
510-
counterparty_delayed_payment_base_key.write(writer)?;
511-
counterparty_htlc_base_key.write(writer)?;
512-
preimage.write(writer)?;
513-
htlc.write(writer)?;
514-
},
515-
&InputMaterial::HolderHTLC { ref preimage, ref amount } => {
516-
writer.write_all(&[2; 1])?;
517-
preimage.write(writer)?;
518-
writer.write_all(&byte_utils::be64_to_array(*amount))?;
519-
},
520-
&InputMaterial::Funding { ref funding_redeemscript } => {
521-
writer.write_all(&[3; 1])?;
522-
funding_redeemscript.write(writer)?;
523-
}
524-
}
525-
Ok(())
526-
}
527-
}
528-
529-
impl Readable for InputMaterial {
530-
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
531-
let input_material = match <u8 as Readable>::read(reader)? {
532-
0 => {
533-
let per_commitment_point = Readable::read(reader)?;
534-
let counterparty_delayed_payment_base_key = Readable::read(reader)?;
535-
let counterparty_htlc_base_key = Readable::read(reader)?;
536-
let per_commitment_key = Readable::read(reader)?;
537-
let input_descriptor = Readable::read(reader)?;
538-
let amount = Readable::read(reader)?;
539-
let htlc = Readable::read(reader)?;
540-
let on_counterparty_tx_csv = Readable::read(reader)?;
541-
InputMaterial::Revoked {
542-
per_commitment_point,
543-
counterparty_delayed_payment_base_key,
544-
counterparty_htlc_base_key,
545-
per_commitment_key,
546-
input_descriptor,
547-
amount,
548-
htlc,
549-
on_counterparty_tx_csv
550-
}
551-
},
552-
1 => {
553-
let per_commitment_point = Readable::read(reader)?;
554-
let counterparty_delayed_payment_base_key = Readable::read(reader)?;
555-
let counterparty_htlc_base_key = Readable::read(reader)?;
556-
let preimage = Readable::read(reader)?;
557-
let htlc = Readable::read(reader)?;
558-
InputMaterial::CounterpartyHTLC {
559-
per_commitment_point,
560-
counterparty_delayed_payment_base_key,
561-
counterparty_htlc_base_key,
562-
preimage,
563-
htlc
564-
}
565-
},
566-
2 => {
567-
let preimage = Readable::read(reader)?;
568-
let amount = Readable::read(reader)?;
569-
InputMaterial::HolderHTLC {
570-
preimage,
571-
amount,
572-
}
573-
},
574-
3 => {
575-
InputMaterial::Funding {
576-
funding_redeemscript: Readable::read(reader)?,
577-
}
578-
}
579-
_ => return Err(DecodeError::InvalidValue),
580-
};
581-
Ok(input_material)
582-
}
583-
}
584-
585461
/// ClaimRequest is a descriptor structure to communicate between detection
586462
/// and reaction module. They are generated by ChannelMonitor while parsing
587463
/// onchain txn leaked from a channel and handed over to OnchainTxHandler which
@@ -597,11 +473,9 @@ pub(crate) struct ClaimRequest {
597473
// of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set.
598474
// Do simplify we mark them as non-aggregable.
599475
pub(crate) aggregable: bool,
600-
// Basic bitcoin outpoint (txid, vout)
601-
pub(crate) outpoint: BitcoinOutPoint,
602-
// Following outpoint type, set of data needed to generate transaction digest
603-
// and satisfy witness program.
604-
pub(crate) witness_data: InputMaterial
476+
// Template (list of outpoint and set of data needed to generate transaction digest
477+
// and satisfy witness program).
478+
pub(crate) package_template: PackageTemplate,
605479
}
606480

607481
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
@@ -1526,8 +1400,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15261400
// First, process non-htlc outputs (to_holder & to_counterparty)
15271401
for (idx, outp) in tx.output.iter().enumerate() {
15281402
if outp.script_pubkey == revokeable_p2wsh {
1529-
let witness_data = InputMaterial::Revoked { per_commitment_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value, htlc: None, on_counterparty_tx_csv: self.counterparty_tx_cache.on_counterparty_tx_csv};
1530-
claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data});
1403+
let malleable_justice_tx = PackageTemplate::build_malleable_justice_tx(per_commitment_point, per_commitment_key, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, InputDescriptors::RevokedOutput, commitment_txid, idx as u32, outp.value, None, self.counterparty_tx_cache.on_counterparty_tx_csv);
1404+
claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, aggregable: true, package_template: malleable_justice_tx});
15311405
}
15321406
}
15331407

@@ -1539,8 +1413,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15391413
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
15401414
return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
15411415
}
1542-
let witness_data = InputMaterial::Revoked { per_commitment_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value, htlc: Some(htlc.clone()), on_counterparty_tx_csv: self.counterparty_tx_cache.on_counterparty_tx_csv};
1543-
claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
1416+
let malleable_justice_tx = PackageTemplate::build_malleable_justice_tx(per_commitment_point, per_commitment_key, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, commitment_txid, transaction_output_index, htlc.amount_msat / 1000, Some(htlc.clone()), self.counterparty_tx_cache.on_counterparty_tx_csv);
1417+
claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable: true, package_template: malleable_justice_tx});
15441418
}
15451419
}
15461420
}
@@ -1674,8 +1548,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
16741548
let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None };
16751549
let aggregable = if !htlc.offered { false } else { true };
16761550
if preimage.is_some() || !htlc.offered {
1677-
let witness_data = InputMaterial::CounterpartyHTLC { per_commitment_point: *revocation_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, preimage, htlc: htlc.clone() };
1678-
claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
1551+
let counterparty_htlc_tx = PackageTemplate::build_counterparty_htlc_tx(*revocation_point, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, preimage, htlc.clone(), commitment_txid, transaction_output_index);
1552+
claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, package_template: counterparty_htlc_tx });
16791553
}
16801554
}
16811555
}
@@ -1705,9 +1579,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17051579
let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret));
17061580
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
17071581

1708-
log_trace!(logger, "Counterparty HTLC broadcast {}:{}", htlc_txid, 0);
1709-
let witness_data = InputMaterial::Revoked { per_commitment_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value, htlc: None, on_counterparty_tx_csv: self.counterparty_tx_cache.on_counterparty_tx_csv };
1710-
let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data });
1582+
log_trace!(logger, "Remote HTLC broadcast {}:{}", htlc_txid, 0);
1583+
let malleable_justice_tx = PackageTemplate::build_malleable_justice_tx(per_commitment_point, per_commitment_key, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, InputDescriptors::RevokedOutput, htlc_txid, 0, tx.output[0].value, None, self.counterparty_tx_cache.on_counterparty_tx_csv);
1584+
let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, aggregable: true, package_template: malleable_justice_tx });
17111585
(claimable_outpoints, Some((htlc_txid, tx.output.clone())))
17121586
}
17131587

@@ -1720,18 +1594,15 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17201594

17211595
for &(ref htlc, _, _) in holder_tx.htlc_outputs.iter() {
17221596
if let Some(transaction_output_index) = htlc.transaction_output_index {
1723-
claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, outpoint: BitcoinOutPoint { txid: holder_tx.txid, vout: transaction_output_index as u32 },
1724-
witness_data: InputMaterial::HolderHTLC {
1725-
preimage: if !htlc.offered {
1726-
if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
1727-
Some(preimage.clone())
1728-
} else {
1729-
// We can't build an HTLC-Success transaction without the preimage
1730-
continue;
1731-
}
1732-
} else { None },
1733-
amount: htlc.amount_msat,
1734-
}});
1597+
let holder_htlc_tx = PackageTemplate::build_holder_htlc_tx(if !htlc.offered {
1598+
if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
1599+
Some(preimage.clone())
1600+
} else {
1601+
// We can't build an HTLC-Success transaction without the preimage
1602+
continue;
1603+
}
1604+
} else { None }, htlc.amount_msat, holder_tx.txid, transaction_output_index);
1605+
claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, package_template: holder_htlc_tx });
17351606
watch_outputs.push(commitment_tx.output[transaction_output_index as usize].clone());
17361607
}
17371608
}
@@ -1944,7 +1815,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
19441815
}
19451816
let should_broadcast = self.would_broadcast_at_height(height, &logger);
19461817
if should_broadcast {
1947-
claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding { funding_redeemscript: self.funding_redeemscript.clone() }});
1818+
let holder_commitment_tx = PackageTemplate::build_holder_commitment_tx(self.funding_redeemscript.clone(), self.funding_info.0.txid.clone(), self.funding_info.0.index as u32);
1819+
claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, package_template: holder_commitment_tx });
19481820
}
19491821
if should_broadcast {
19501822
self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));

lightning/src/ln/onchain_utils.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,9 @@ impl PackageTemplate {
280280
pub(crate) fn outpoints(&self) -> Vec<&BitcoinOutPoint> {
281281
match self {
282282
PackageTemplate::MalleableJusticeTx { ref inputs } => {
283-
assert_ne!(inputs.len(), 0);
284283
inputs.keys().collect()
285284
},
286285
PackageTemplate::CounterpartyHTLCTx { ref inputs } => {
287-
assert_ne!(inputs.len(), 0);
288286
inputs.keys().collect()
289287
},
290288
PackageTemplate::HolderHTLCTx { ref input } => {
@@ -299,29 +297,32 @@ impl PackageTemplate {
299297
},
300298
}
301299
}
302-
pub(crate) fn package_split(&mut self, outp: &BitcoinOutPoint) -> PackageTemplate {
303-
let package = match self {
300+
pub(crate) fn package_split(&mut self, outp: &BitcoinOutPoint) -> Option<PackageTemplate> {
301+
match self {
304302
PackageTemplate::MalleableJusticeTx { ref mut inputs } => {
305-
assert_ne!(inputs.len(), 0);
306-
let removed = inputs.remove(outp).unwrap();
307-
let mut input_splitted = HashMap::with_capacity(1);
308-
input_splitted.insert(*outp, removed);
309-
PackageTemplate::MalleableJusticeTx {
310-
inputs: input_splitted,
303+
if let Some(removed) = inputs.remove(outp) {
304+
let mut input_splitted = HashMap::with_capacity(1);
305+
input_splitted.insert(*outp, removed);
306+
return Some(PackageTemplate::MalleableJusticeTx {
307+
inputs: input_splitted,
308+
});
311309
}
310+
None
312311
},
313312
PackageTemplate::CounterpartyHTLCTx { ref mut inputs } => {
314-
assert_ne!(inputs.len(), 0);
315-
let removed = inputs.remove(outp).unwrap();
316-
let mut input_splitted = HashMap::with_capacity(1);
317-
input_splitted.insert(*outp, removed);
318-
PackageTemplate::CounterpartyHTLCTx {
319-
inputs: input_splitted,
313+
if let Some(removed) = inputs.remove(outp) {
314+
let mut input_splitted = HashMap::with_capacity(1);
315+
input_splitted.insert(*outp, removed);
316+
return Some(PackageTemplate::CounterpartyHTLCTx {
317+
inputs: input_splitted,
318+
});
320319
}
320+
None
321321
},
322-
_ => panic!("Removing outpoints from non-malleable packages")
323-
};
324-
package
322+
_ => {
323+
return None;
324+
}
325+
}
325326
}
326327
pub(crate) fn package_merge(&mut self, mut template: PackageTemplate) {
327328
match self {
@@ -413,7 +414,7 @@ impl PackageTemplate {
413414
};
414415
bumped_tx.get_weight() + witnesses_weight
415416
}
416-
pub(crate) fn package_finalize<L: Deref, ChanSigner: ChannelKeys>(&self, onchain_handler: &mut OnchainTxHandler<ChanSigner>, amount: u64, destination_script: Script, logger: &L) -> Option<Transaction>
417+
pub(crate) fn package_finalize<L: Deref, ChanSigner: ChannelKeys>(&self, onchain_handler: &mut OnchainTxHandler<ChanSigner>, value: u64, destination_script: Script, logger: &L) -> Option<Transaction>
417418
where L::Target: Logger,
418419
{
419420
let mut bumped_tx = Transaction {
@@ -422,7 +423,7 @@ impl PackageTemplate {
422423
input: vec![],
423424
output: vec![TxOut {
424425
script_pubkey: destination_script,
425-
value: 0
426+
value,
426427
}],
427428
};
428429
match self {
@@ -444,7 +445,7 @@ impl PackageTemplate {
444445
chan_utils::get_revokeable_redeemscript(&chan_keys.revocation_key, revk.on_counterparty_tx_csv, &chan_keys.broadcaster_delayed_payment_key)
445446
};
446447

447-
if let Ok(sig) = onchain_handler.key_storage.sign_justice_transaction(&bumped_tx, i, amount, &revk.per_commitment_key, &revk.htlc, &onchain_handler.secp_ctx) {
448+
if let Ok(sig) = onchain_handler.key_storage.sign_justice_transaction(&bumped_tx, i, revk.amount, &revk.per_commitment_key, &revk.htlc, &onchain_handler.secp_ctx) {
448449
bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
449450
bumped_tx.input[i].witness[0].push(SigHashType::All as u8);
450451
if revk.htlc.is_some() {

0 commit comments

Comments
 (0)