Skip to content

Commit 85b1a9e

Browse files
committed
Make ChannelMonitor sign local transactions (at broadcast time)
1 parent d498352 commit 85b1a9e

File tree

6 files changed

+289
-170
lines changed

6 files changed

+289
-170
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ pub fn do_test(data: &[u8]) {
212212
monitor.latest_good_update.lock().unwrap().insert(outpoint, monitor_ser);
213213
}
214214
let mut monitor_refs = HashMap::new();
215-
for (outpoint, monitor) in monitors.iter() {
215+
for (outpoint, monitor) in monitors.iter_mut() {
216216
monitor_refs.insert(*outpoint, monitor);
217217
}
218218

@@ -223,7 +223,7 @@ pub fn do_test(data: &[u8]) {
223223
tx_broadcaster: broadcast.clone(),
224224
logger,
225225
default_config: config,
226-
channel_monitors: &monitor_refs,
226+
channel_monitors: &mut monitor_refs,
227227
};
228228

229229
let res = (<(Sha256d, ChannelManager<EnforcingChannelKeys>)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor);

lightning/src/ln/chan_utils.rs

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
55
use bitcoin::blockdata::script::{Script,Builder};
66
use bitcoin::blockdata::opcodes;
7-
use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction};
7+
use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction, SigHashType};
8+
use bitcoin::consensus::encode::{self, Decodable, Encodable};
9+
use bitcoin::util::bip143;
810

911
use bitcoin_hashes::{Hash, HashEngine};
1012
use bitcoin_hashes::sha256::Hash as Sha256;
@@ -13,9 +15,11 @@ use bitcoin_hashes::hash160::Hash as Hash160;
1315
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
1416

1517
use ln::channelmanager::PaymentHash;
18+
use ln::msgs::DecodeError;
19+
use util::ser::{Readable, Writeable, Writer, WriterWriteAdaptor};
1620

17-
use secp256k1::key::{PublicKey,SecretKey};
18-
use secp256k1::Secp256k1;
21+
use secp256k1::key::{SecretKey,PublicKey};
22+
use secp256k1::{Secp256k1, Signature};
1923
use secp256k1;
2024

2125
pub(super) const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
@@ -281,3 +285,113 @@ pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_s
281285
output: txouts,
282286
}
283287
}
288+
289+
#[derive(Clone)]
290+
pub(crate) struct LocalCommitmentTransaction {
291+
tx: Transaction
292+
}
293+
impl LocalCommitmentTransaction {
294+
#[cfg(test)]
295+
pub fn dummy() -> Self {
296+
Self { tx: Transaction {
297+
version: 2,
298+
input: Vec::new(),
299+
output: Vec::new(),
300+
lock_time: 0,
301+
} }
302+
}
303+
304+
pub fn new_from_unsigned(mut tx: Transaction, their_sig: &Signature, our_funding_key: &PublicKey, their_funding_key: &PublicKey) -> LocalCommitmentTransaction {
305+
if tx.input.len() != 1 { panic!("Tried to store a commitment transaction that had input count != 1!"); }
306+
if tx.input[0].witness.len() != 0 { panic!("Tried to store a signed commitment transaction?"); }
307+
308+
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
309+
310+
if our_funding_key.serialize()[..] < their_funding_key.serialize()[..] {
311+
tx.input[0].witness.push(Vec::new());
312+
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
313+
tx.input[0].witness[2].push(SigHashType::All as u8);
314+
} else {
315+
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
316+
tx.input[0].witness[1].push(SigHashType::All as u8);
317+
tx.input[0].witness.push(Vec::new());
318+
}
319+
320+
Self { tx }
321+
}
322+
323+
pub fn txid(&self) -> Sha256dHash {
324+
self.tx.txid()
325+
}
326+
327+
pub fn is_signed(&self) -> bool {
328+
if self.tx.input.len() != 1 { panic!("Commitment transactions must have input count == 1!"); }
329+
if self.tx.input[0].witness.len() == 4 {
330+
assert!(!self.tx.input[0].witness[1].is_empty());
331+
assert!(!self.tx.input[0].witness[2].is_empty());
332+
true
333+
} else {
334+
assert_eq!(self.tx.input[0].witness.len(), 3);
335+
assert!(self.tx.input[0].witness[0].is_empty());
336+
assert!(self.tx.input[0].witness[1].is_empty() || self.tx.input[0].witness[2].is_empty());
337+
false
338+
}
339+
}
340+
341+
pub fn sign<T: secp256k1::Signing>(&mut self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) {
342+
if self.is_signed() { return; }
343+
let sighash = hash_to_message!(&bip143::SighashComponents::new(&self.tx)
344+
.sighash_all(&self.tx.input[0], funding_redeemscript, channel_value_satoshis)[..]);
345+
let our_sig = secp_ctx.sign(&sighash, funding_key);
346+
347+
if self.tx.input[0].witness[1].is_empty() {
348+
self.tx.input[0].witness[1] = our_sig.serialize_der().to_vec();
349+
self.tx.input[0].witness[1].push(SigHashType::All as u8);
350+
} else {
351+
self.tx.input[0].witness[2] = our_sig.serialize_der().to_vec();
352+
self.tx.input[0].witness[2].push(SigHashType::All as u8);
353+
}
354+
355+
self.tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec());
356+
}
357+
358+
pub fn unsigned(&self) -> &Transaction { &self.tx }
359+
pub fn signed(&self) -> &Transaction {
360+
assert!(self.is_signed());
361+
&self.tx
362+
}
363+
}
364+
impl PartialEq for LocalCommitmentTransaction {
365+
// We dont care whether we are signed in equality comparison
366+
fn eq(&self, o: &Self) -> bool {
367+
self.txid() == o.txid()
368+
}
369+
}
370+
impl Writeable for LocalCommitmentTransaction {
371+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
372+
if let Err(e) = self.tx.consensus_encode(&mut WriterWriteAdaptor(writer)) {
373+
match e {
374+
encode::Error::Io(e) => return Err(e),
375+
_ => panic!("local tx must have been well-formed!"),
376+
}
377+
}
378+
Ok(())
379+
}
380+
}
381+
impl<R: ::std::io::Read> Readable<R> for LocalCommitmentTransaction {
382+
fn read(reader: &mut R) -> Result<Self, DecodeError> {
383+
let tx = match Transaction::consensus_decode(reader.by_ref()) {
384+
Ok(tx) => tx,
385+
Err(e) => match e {
386+
encode::Error::Io(ioe) => return Err(DecodeError::Io(ioe)),
387+
_ => return Err(DecodeError::InvalidValue),
388+
},
389+
};
390+
391+
if tx.input.len() != 1 {
392+
// Ensure tx didn't hit the 0-input ambiguity case.
393+
return Err(DecodeError::InvalidValue);
394+
}
395+
Ok(Self { tx })
396+
}
397+
}

lightning/src/ln/channel.rs

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use ln::msgs;
1919
use ln::msgs::{DecodeError, OptionalField, LocalFeatures, DataLossProtect};
2020
use ln::channelmonitor::ChannelMonitor;
2121
use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
22-
use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
22+
use ln::chan_utils::{LocalCommitmentTransaction,TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
2323
use ln::chan_utils;
2424
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
2525
use chain::transaction::OutPoint;
@@ -450,7 +450,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
450450
let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
451451

452452
let secp_ctx = Secp256k1::new();
453-
let channel_monitor = ChannelMonitor::new(chan_keys.revocation_base_key(), chan_keys.delayed_payment_base_key(),
453+
let channel_monitor = ChannelMonitor::new(chan_keys.funding_key(), chan_keys.revocation_base_key(), chan_keys.delayed_payment_base_key(),
454454
chan_keys.htlc_base_key(), chan_keys.payment_base_key(), &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
455455
keys_provider.get_destination_script(), logger.clone());
456456

@@ -644,7 +644,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
644644
}
645645

646646
let secp_ctx = Secp256k1::new();
647-
let channel_monitor = ChannelMonitor::new(chan_keys.revocation_base_key(), chan_keys.delayed_payment_base_key(),
647+
let channel_monitor = ChannelMonitor::new(chan_keys.funding_key(), chan_keys.revocation_base_key(), chan_keys.delayed_payment_base_key(),
648648
chan_keys.htlc_base_key(), chan_keys.payment_base_key(), &keys_provider.get_shutdown_pubkey(), config.own_channel_config.our_to_self_delay,
649649
keys_provider.get_destination_script(), logger.clone());
650650

@@ -1122,38 +1122,6 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
11221122
}.push_opcode(opcodes::all::OP_PUSHNUM_2).push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script()
11231123
}
11241124

1125-
fn sign_commitment_transaction(&self, tx: &mut Transaction, their_sig: &Signature) -> Signature {
1126-
if tx.input.len() != 1 {
1127-
panic!("Tried to sign commitment transaction that had input count != 1!");
1128-
}
1129-
if tx.input[0].witness.len() != 0 {
1130-
panic!("Tried to re-sign commitment transaction");
1131-
}
1132-
1133-
let funding_redeemscript = self.get_funding_redeemscript();
1134-
1135-
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
1136-
let our_sig = self.secp_ctx.sign(&sighash, self.local_keys.funding_key());
1137-
1138-
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
1139-
1140-
let our_funding_key = PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()).serialize();
1141-
let their_funding_key = self.their_funding_pubkey.unwrap().serialize();
1142-
if our_funding_key[..] < their_funding_key[..] {
1143-
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
1144-
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
1145-
} else {
1146-
tx.input[0].witness.push(their_sig.serialize_der().to_vec());
1147-
tx.input[0].witness.push(our_sig.serialize_der().to_vec());
1148-
}
1149-
tx.input[0].witness[1].push(SigHashType::All as u8);
1150-
tx.input[0].witness[2].push(SigHashType::All as u8);
1151-
1152-
tx.input[0].witness.push(funding_redeemscript.into_bytes());
1153-
1154-
our_sig
1155-
}
1156-
11571125
/// Builds the htlc-success or htlc-timeout transaction which spends a given HTLC output
11581126
/// @local is used only to convert relevant internal structures which refer to remote vs local
11591127
/// to decide value of outputs and direction of HTLCs.
@@ -1492,26 +1460,25 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
14921460
Ok(())
14931461
}
14941462

1495-
fn funding_created_signature(&mut self, sig: &Signature) -> Result<(Transaction, Transaction, Signature, TxCreationKeys), ChannelError> {
1463+
fn funding_created_signature(&mut self, sig: &Signature) -> Result<(Transaction, LocalCommitmentTransaction, Signature, TxCreationKeys), ChannelError> {
14961464
let funding_script = self.get_funding_redeemscript();
14971465

14981466
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
1499-
let mut local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, self.feerate_per_kw).0;
1467+
let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, self.feerate_per_kw).0;
15001468
let local_sighash = hash_to_message!(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
15011469

15021470
// They sign the "local" commitment transaction...
15031471
secp_check!(self.secp_ctx.verify(&local_sighash, &sig, &self.their_funding_pubkey.unwrap()), "Invalid funding_created signature from peer");
15041472

1505-
// ...and we sign it, allowing us to broadcast the tx if we wish
1506-
self.sign_commitment_transaction(&mut local_initial_commitment_tx, sig);
1473+
let localtx = LocalCommitmentTransaction::new_from_unsigned(local_initial_commitment_tx, sig, &PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()), self.their_funding_pubkey.as_ref().unwrap());
15071474

15081475
let remote_keys = self.build_remote_transaction_keys()?;
15091476
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
15101477
let remote_signature = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
15111478
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0;
15121479

15131480
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
1514-
Ok((remote_initial_commitment_tx, local_initial_commitment_tx, remote_signature, local_keys))
1481+
Ok((remote_initial_commitment_tx, localtx, remote_signature, local_keys))
15151482
}
15161483

15171484
pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result<(msgs::FundingSigned, ChannelMonitor), ChannelError> {
@@ -1575,14 +1542,15 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
15751542
let funding_script = self.get_funding_redeemscript();
15761543

15771544
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
1578-
let mut local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, self.feerate_per_kw).0;
1545+
let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, self.feerate_per_kw).0;
15791546
let local_sighash = hash_to_message!(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
15801547

15811548
// They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish.
15821549
secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid funding_signed signature from peer");
15831550

1584-
self.sign_commitment_transaction(&mut local_initial_commitment_tx, &msg.signature);
1585-
self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx, local_keys, self.feerate_per_kw, Vec::new());
1551+
self.channel_monitor.provide_latest_local_commitment_tx_info(
1552+
LocalCommitmentTransaction::new_from_unsigned(local_initial_commitment_tx, &msg.signature, &PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()), self.their_funding_pubkey.as_ref().unwrap()),
1553+
local_keys, self.feerate_per_kw, Vec::new());
15861554
self.channel_state = ChannelState::FundingSent as u32 | (self.channel_state & (ChannelState::MonitorUpdateFailed as u32));
15871555
self.cur_local_commitment_transaction_number -= 1;
15881556

@@ -1846,8 +1814,6 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18461814
return Err(ChannelError::Close("Got wrong number of HTLC signatures from remote"));
18471815
}
18481816

1849-
self.sign_commitment_transaction(&mut local_commitment_tx.0, &msg.signature);
1850-
18511817
let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.2.len());
18521818
for (idx, (htlc, source)) in local_commitment_tx.2.drain(..).enumerate() {
18531819
if let Some(_) = htlc.transaction_output_index {
@@ -1881,7 +1847,10 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18811847
}
18821848
}
18831849

1884-
self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs);
1850+
1851+
self.channel_monitor.provide_latest_local_commitment_tx_info(
1852+
LocalCommitmentTransaction::new_from_unsigned(local_commitment_tx.0, &msg.signature, &PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()), self.their_funding_pubkey.as_ref().unwrap()),
1853+
local_keys, self.feerate_per_kw, htlcs_and_sigs);
18851854

18861855
for htlc in self.pending_inbound_htlcs.iter_mut() {
18871856
let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
@@ -2859,11 +2828,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
28592828
}
28602829

28612830
/// May only be called after funding has been initiated (ie is_funding_initiated() is true)
2862-
pub fn channel_monitor(&self) -> &ChannelMonitor {
2831+
pub fn channel_monitor(&mut self) -> &mut ChannelMonitor {
28632832
if self.channel_state < ChannelState::FundingCreated as u32 {
28642833
panic!("Can't get a channel monitor until funding has been created");
28652834
}
2866-
&self.channel_monitor
2835+
&mut self.channel_monitor
28672836
}
28682837

28692838
/// Guaranteed to be Some after both FundingLocked messages have been exchanged (and, thus,
@@ -4141,6 +4110,7 @@ mod tests {
41414110
use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys};
41424111
use ln::channel::MAX_FUNDING_SATOSHIS;
41434112
use ln::chan_utils;
4113+
use ln::chan_utils::LocalCommitmentTransaction;
41444114
use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
41454115
use chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
41464116
use chain::transaction::OutPoint;
@@ -4260,13 +4230,15 @@ mod tests {
42604230
.collect();
42614231
(res.0, htlcs)
42624232
};
4233+
let redeemscript = chan.get_funding_redeemscript();
42634234
let their_signature = Signature::from_der(&hex::decode($their_sig_hex).unwrap()[..]).unwrap();
4264-
let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &chan.get_funding_redeemscript(), chan.channel_value_satoshis)[..]).unwrap();
4235+
let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &redeemscript, chan.channel_value_satoshis)[..]).unwrap();
42654236
secp_ctx.verify(&sighash, &their_signature, &chan.their_funding_pubkey.unwrap()).unwrap();
42664237

4267-
chan.sign_commitment_transaction(&mut unsigned_tx.0, &their_signature);
4238+
let mut localtx = LocalCommitmentTransaction::new_from_unsigned(unsigned_tx.0.clone(), &their_signature, &PublicKey::from_secret_key(&secp_ctx, chan.local_keys.funding_key()), chan.their_funding_pubkey.as_ref().unwrap());
4239+
localtx.sign(chan.local_keys.funding_key(), &redeemscript, chan.channel_value_satoshis, &chan.secp_ctx);
42684240

4269-
assert_eq!(serialize(&unsigned_tx.0)[..],
4241+
assert_eq!(serialize(localtx.signed())[..],
42704242
hex::decode($tx_hex).unwrap()[..]);
42714243
};
42724244
}

lightning/src/ln/channelmanager.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3216,7 +3216,7 @@ pub struct ChannelManagerReadArgs<'a, 'b, ChanSigner: ChannelKeys> {
32163216
///
32173217
/// In such cases the latest local transactions will be sent to the tx_broadcaster included in
32183218
/// this struct.
3219-
pub channel_monitors: &'a HashMap<OutPoint, &'a ChannelMonitor>,
3219+
pub channel_monitors: &'a mut HashMap<OutPoint, &'a mut ChannelMonitor>,
32203220
}
32213221

32223222
impl<'a, 'b, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R, ChannelManagerReadArgs<'a, 'b, ChanSigner>> for (Sha256dHash, ChannelManager<'b, ChanSigner>) {
@@ -3245,7 +3245,7 @@ impl<'a, 'b, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> Readabl
32453245

32463246
let funding_txo = channel.channel_monitor().get_funding_txo().ok_or(DecodeError::InvalidValue)?;
32473247
funding_txo_set.insert(funding_txo.clone());
3248-
if let Some(monitor) = args.channel_monitors.get(&funding_txo) {
3248+
if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
32493249
if channel.get_cur_local_commitment_transaction_number() != monitor.get_cur_local_commitment_number() ||
32503250
channel.get_revoked_remote_commitment_transaction_number() != monitor.get_min_seen_secret() ||
32513251
channel.get_cur_remote_commitment_transaction_number() != monitor.get_cur_remote_commitment_number() {
@@ -3263,7 +3263,7 @@ impl<'a, 'b, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> Readabl
32633263
}
32643264
}
32653265

3266-
for (ref funding_txo, ref monitor) in args.channel_monitors.iter() {
3266+
for (ref funding_txo, ref mut monitor) in args.channel_monitors.iter_mut() {
32673267
if !funding_txo_set.contains(funding_txo) {
32683268
closed_channels.push((monitor.get_latest_local_commitment_txn(), Vec::new()));
32693269
}

0 commit comments

Comments
 (0)