From: benthecarman Date: Fri, 5 May 2023 13:29:52 +0000 (-0500) Subject: Support broadcasting multiple transactions at once X-Git-Tag: v0.0.116-alpha1~32^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=29b392a96de6c4d597a2d546d06e02824b83b6dd;p=rust-lightning Support broadcasting multiple transactions at once --- diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 837386bd9..ee2b51067 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -101,7 +101,7 @@ impl Router for FuzzRouter { pub struct TestBroadcaster {} impl BroadcasterInterface for TestBroadcaster { - fn broadcast_transaction(&self, _tx: &Transaction) { } + fn broadcast_transactions(&self, _txs: &[&Transaction]) { } } pub struct VecWriter(pub Vec); diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index d044a35f0..6542b2e47 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -145,8 +145,9 @@ struct TestBroadcaster { txn_broadcasted: Mutex>, } impl BroadcasterInterface for TestBroadcaster { - fn broadcast_transaction(&self, tx: &Transaction) { - self.txn_broadcasted.lock().unwrap().push(tx.clone()); + fn broadcast_transactions(&self, txs: &[&Transaction]) { + let owned_txs: Vec = txs.iter().map(|tx| (*tx).clone()).collect(); + self.txn_broadcasted.lock().unwrap().extend(owned_txs); } } diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs index e923a94bb..d875dcce3 100644 --- a/lightning/src/chain/chaininterface.rs +++ b/lightning/src/chain/chaininterface.rs @@ -19,8 +19,20 @@ use bitcoin::blockdata::transaction::Transaction; /// An interface to send a transaction to the Bitcoin network. pub trait BroadcasterInterface { - /// Sends a transaction out to (hopefully) be mined. - fn broadcast_transaction(&self, tx: &Transaction); + /// Sends a list of transactions out to (hopefully) be mined. + /// This only needs to handle the actual broadcasting of transactions, LDK will automatically + /// rebroadcast transactions that haven't made it into a block. + /// + /// In some cases LDK may attempt to broadcast a transaction which double-spends another + /// and this isn't a bug and can be safely ignored. + /// + /// If more than one transaction is given, these transactions should be considered to be a + /// package and broadcast together. Some of the transactions may or may not depend on each other, + /// be sure to manage both cases correctly. + /// + /// Bitcoin transaction packages are defined in BIP 331 and here: + /// https://github.com/bitcoin/bitcoin/blob/master/doc/policy/packages.md + fn broadcast_transactions(&self, txs: &[&Transaction]); } /// An enum that represents the speed at which we want a transaction to confirm used for feerate diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 7d1a325c7..5adc15640 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -2327,10 +2327,13 @@ impl ChannelMonitorImpl { where B::Target: BroadcasterInterface, L::Target: Logger, { - for tx in self.get_latest_holder_commitment_txn(logger).iter() { + let commit_txs = self.get_latest_holder_commitment_txn(logger); + let mut txs = vec![]; + for tx in commit_txs.iter() { log_info!(logger, "Broadcasting local {}", log_tx!(tx)); - broadcaster.broadcast_transaction(tx); + txs.push(tx); } + broadcaster.broadcast_transactions(&txs); self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0)); } diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index 21b4717e1..45968c57e 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -513,7 +513,7 @@ impl OnchainTxHandler OnchainClaim::Tx(tx) => { let log_start = if bumped_feerate { "Broadcasting RBF-bumped" } else { "Rebroadcasting" }; log_info!(logger, "{} onchain {}", log_start, log_tx!(tx)); - broadcaster.broadcast_transaction(&tx); + broadcaster.broadcast_transactions(&[&tx]); }, #[cfg(anchors)] OnchainClaim::Event(event) => { @@ -767,7 +767,7 @@ impl OnchainTxHandler let package_id = match claim { OnchainClaim::Tx(tx) => { log_info!(logger, "Broadcasting onchain {}", log_tx!(tx)); - broadcaster.broadcast_transaction(&tx); + broadcaster.broadcast_transactions(&[&tx]); tx.txid().into_inner() }, #[cfg(anchors)] @@ -960,7 +960,7 @@ impl OnchainTxHandler match bump_claim { OnchainClaim::Tx(bump_tx) => { log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx)); - broadcaster.broadcast_transaction(&bump_tx); + broadcaster.broadcast_transactions(&[&bump_tx]); }, #[cfg(anchors)] OnchainClaim::Event(claim_event) => { @@ -1046,7 +1046,7 @@ impl OnchainTxHandler match bump_claim { OnchainClaim::Tx(bump_tx) => { log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx)); - broadcaster.broadcast_transaction(&bump_tx); + broadcaster.broadcast_transactions(&[&bump_tx]); }, #[cfg(anchors)] OnchainClaim::Event(claim_event) => { diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index bf863797a..aac843df3 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -4480,7 +4480,7 @@ where if let Some(tx) = funding_broadcastable { log_info!(self.logger, "Broadcasting funding transaction with txid {}", tx.txid()); - self.tx_broadcaster.broadcast_transaction(&tx); + self.tx_broadcaster.broadcast_transactions(&[&tx]); } { @@ -5012,7 +5012,7 @@ where }; if let Some(broadcast_tx) = tx { log_info!(self.logger, "Broadcasting {}", log_tx!(broadcast_tx)); - self.tx_broadcaster.broadcast_transaction(&broadcast_tx); + self.tx_broadcaster.broadcast_transactions(&[&broadcast_tx]); } if let Some(chan) = chan_option { if let Ok(update) = self.get_channel_update_for_broadcast(&chan) { @@ -5618,7 +5618,7 @@ where self.issue_channel_close_events(chan, ClosureReason::CooperativeClosure); log_info!(self.logger, "Broadcasting {}", log_tx!(tx)); - self.tx_broadcaster.broadcast_transaction(&tx); + self.tx_broadcaster.broadcast_transactions(&[&tx]); update_maps_on_chan_removal!(self, chan); false } else { true } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 658876fe3..4b3cc4113 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -341,17 +341,20 @@ impl TestBroadcaster { } impl chaininterface::BroadcasterInterface for TestBroadcaster { - fn broadcast_transaction(&self, tx: &Transaction) { - let lock_time = tx.lock_time.0; - assert!(lock_time < 1_500_000_000); - if bitcoin::LockTime::from(tx.lock_time).is_block_height() && lock_time > self.blocks.lock().unwrap().last().unwrap().1 { - for inp in tx.input.iter() { - if inp.sequence != Sequence::MAX { - panic!("We should never broadcast a transaction before its locktime ({})!", tx.lock_time); + fn broadcast_transactions(&self, txs: &[&Transaction]) { + for tx in txs { + let lock_time = tx.lock_time.0; + assert!(lock_time < 1_500_000_000); + if bitcoin::LockTime::from(tx.lock_time).is_block_height() && lock_time > self.blocks.lock().unwrap().last().unwrap().1 { + for inp in tx.input.iter() { + if inp.sequence != Sequence::MAX { + panic!("We should never broadcast a transaction before its locktime ({})!", tx.lock_time); + } } } } - self.txn_broadcasted.lock().unwrap().push(tx.clone()); + let owned_txs: Vec = txs.iter().map(|tx| (*tx).clone()).collect(); + self.txn_broadcasted.lock().unwrap().extend(owned_txs); } }