Skip to content

Commit 91166b9

Browse files
jkczyzclaude
andcommitted
f - Avoid an extra Vec allocation when forwarding broadcasts
Classifying a package no longer collects the transactions into a fresh Vec; the originally-queued package is returned and the chain-source broadcast loop iterates it directly. No behavior change. Generated with assistance from Claude Code. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent 1352a4c commit 91166b9

5 files changed

Lines changed: 25 additions & 19 deletions

File tree

src/chain/bitcoind.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,16 +568,18 @@ impl BitcoindChainSource {
568568
Ok(())
569569
}
570570

571-
pub(crate) async fn process_broadcast_package(&self, package: Vec<Transaction>) {
571+
pub(crate) async fn process_broadcast_package(
572+
&self, txs: impl IntoIterator<Item = Transaction>,
573+
) {
572574
// While it's a bit unclear when we'd be able to lean on Bitcoin Core >v28
573575
// features, we should eventually switch to use `submitpackage` via the
574576
// `rust-bitcoind-json-rpc` crate rather than just broadcasting individual
575577
// transactions.
576-
for tx in &package {
578+
for tx in txs {
577579
let txid = tx.compute_txid();
578580
let timeout_fut = tokio::time::timeout(
579581
Duration::from_secs(DEFAULT_TX_BROADCAST_TIMEOUT_SECS),
580-
self.api_client.broadcast_transaction(tx),
582+
self.api_client.broadcast_transaction(&tx),
581583
);
582584
match timeout_fut.await {
583585
Ok(res) => match res {

src/chain/electrum.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,9 @@ impl ElectrumChainSource {
275275
Ok(())
276276
}
277277

278-
pub(crate) async fn process_broadcast_package(&self, package: Vec<Transaction>) {
278+
pub(crate) async fn process_broadcast_package(
279+
&self, txs: impl IntoIterator<Item = Transaction>,
280+
) {
279281
let electrum_client: Arc<ElectrumRuntimeClient> = if let Some(client) =
280282
self.electrum_runtime_status.read().expect("lock").client().as_ref()
281283
{
@@ -285,7 +287,7 @@ impl ElectrumChainSource {
285287
return;
286288
};
287289

288-
for tx in package {
290+
for tx in txs {
289291
electrum_client.broadcast(tx).await;
290292
}
291293
}

src/chain/esplora.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,14 @@ impl EsploraChainSource {
352352
Ok(())
353353
}
354354

355-
pub(crate) async fn process_broadcast_package(&self, package: Vec<Transaction>) {
356-
for tx in &package {
355+
pub(crate) async fn process_broadcast_package(
356+
&self, txs: impl IntoIterator<Item = Transaction>,
357+
) {
358+
for tx in txs {
357359
let txid = tx.compute_txid();
358360
let timeout_fut = tokio::time::timeout(
359361
Duration::from_secs(self.sync_config.timeouts_config.tx_broadcast_timeout_secs),
360-
self.esplora_client.broadcast(tx),
362+
self.esplora_client.broadcast(&tx),
361363
);
362364
match timeout_fut.await {
363365
Ok(res) => match res {

src/chain/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,8 @@ impl ChainSource {
453453
return;
454454
}
455455
Some(next_package) = receiver.recv() => {
456-
let txs = match self.tx_broadcaster.classify_package(next_package).await {
457-
Ok(txs) => txs,
456+
let package = match self.tx_broadcaster.classify_package(next_package).await {
457+
Ok(p) => p,
458458
Err(e) => {
459459
log_error!(
460460
tx_bcast_logger,
@@ -464,6 +464,7 @@ impl ChainSource {
464464
continue;
465465
},
466466
};
467+
let txs = package.into_iter().map(|(tx, _)| tx);
467468
match &self.kind {
468469
ChainSourceKind::Esplora(esplora_chain_source) => {
469470
esplora_chain_source.process_broadcast_package(txs).await

src/tx_broadcaster.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,25 @@ where
6565
self.queue_receiver.lock().await
6666
}
6767

68-
/// Classifies a queued package into payment records and returns the raw
69-
/// transactions ready for the chain client. Returns `Err` if any classification
70-
/// fails; callers must not broadcast the package in that case, since a crash would
71-
/// leave the tx on-chain without a record.
68+
/// Classifies a queued package into payment records and returns the package ready
69+
/// for the chain client. Returns `Err` if any classification fails; callers must
70+
/// not broadcast the package in that case, since a crash would leave the tx
71+
/// on-chain without a record.
7272
pub(crate) async fn classify_package(
7373
&self, package: BroadcastPackage,
74-
) -> Result<Vec<Transaction>, Error> {
74+
) -> Result<BroadcastPackage, Error> {
7575
let wallet_opt = self.wallet.lock().expect("lock").as_ref().and_then(Weak::upgrade);
7676
if let Some(wallet) = wallet_opt {
77-
let package = tokio::task::spawn_blocking(move || {
77+
tokio::task::spawn_blocking(move || {
7878
for (tx, tx_type) in &package {
7979
wallet.classify_broadcast(tx, tx_type)?;
8080
}
8181
Ok::<_, Error>(package)
8282
})
8383
.await
84-
.map_err(|_| Error::PersistenceFailed)??;
85-
Ok(package.into_iter().map(|(tx, _)| tx).collect())
84+
.map_err(|_| Error::PersistenceFailed)?
8685
} else {
87-
Ok(package.into_iter().map(|(tx, _)| tx).collect())
86+
Ok(package)
8887
}
8988
}
9089
}

0 commit comments

Comments
 (0)