Support broadcasting multiple transactions at once
authorbenthecarman <benthecarman@live.com>
Fri, 5 May 2023 13:29:52 +0000 (08:29 -0500)
committerbenthecarman <benthecarman@live.com>
Sat, 13 May 2023 04:29:38 +0000 (23:29 -0500)
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
lightning/src/chain/chaininterface.rs
lightning/src/chain/channelmonitor.rs
lightning/src/chain/onchaintx.rs
lightning/src/ln/channelmanager.rs
lightning/src/util/test_utils.rs

index 837386bd94ce6a4f288102be3fca40b20f0cca75..ee2b51067fc3abb59840a63a26b3ba85e629d82b 100644 (file)
@@ -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<u8>);
index d044a35f01bba364a8d17d1831591df4f74c8627..6542b2e470b4076ebec924d72cf8e40dc43be880 100644 (file)
@@ -145,8 +145,9 @@ struct TestBroadcaster {
        txn_broadcasted: Mutex<Vec<Transaction>>,
 }
 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<Transaction> = txs.iter().map(|tx| (*tx).clone()).collect();
+               self.txn_broadcasted.lock().unwrap().extend(owned_txs);
        }
 }
 
index e923a94bb6d3e7afb5f37376b6de132225821d21..d875dcce3e128c1443a2deaa46f1a8465a7cd06b 100644 (file)
@@ -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
index 7d1a325c7210500696495677511c2686a47c7b90..5adc156405bf087bb03158615b4b1cfbd217f3a8 100644 (file)
@@ -2327,10 +2327,13 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                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));
        }
 
index 21b4717e1d9786dfd2b0eb68092e41f7b3d19afd..45968c57e537077c2d583a24fe9702300d19a8cb 100644 (file)
@@ -513,7 +513,7 @@ impl<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                                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<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                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<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                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<ChannelSigner: WriteableEcdsaChannelSigner> OnchainTxHandler<ChannelSigner>
                                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) => {
index bf863797ada01ff4594615a8e7c7bda84e22fb9c..aac843df38a122ab59a8630b1508e865700db70a 100644 (file)
@@ -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 }
index 658876fe33a6a478865da7f2ccaf1d729cb15569..4b3cc4113bc35214dc62e3a6d12b6b9290f88eca 100644 (file)
@@ -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<Transaction> = txs.iter().map(|tx| (*tx).clone()).collect();
+               self.txn_broadcasted.lock().unwrap().extend(owned_txs);
        }
 }