lightningd: make wallet_extract_owned_outputs return bool, optionally output numbers.
What changed, and why it matters
This is a small internal code cleanup in Core Lightning. A wallet helper function that scans transactions for outputs belonging to the node is changed from returning a count of found outputs to returning a simple yes/no answer, with an optional list of output numbers. Callers are updated to use the new yes/no style. Nothing in the commit message or diff suggests a security bug is being fixed.
No security action required. Treat as normal refactoring review; verify downstream branches that may rely on the previous int return value are updated.
Security signals we found
No security-relevant keywords in commit title or message
Refactor-only change with equivalent control flow
No input validation, memory allocation, or cryptographic changes
No bug fix description or CVE reference present
Evidence from the diff
The commit refactors wallet_extract_owned_outputs() in wallet/wallet.c to return bool instead of int, and adds an optional size_t **outputs parameter that records which transaction outputs were owned. All callers in chaintopology.c, channel_control.c, dual_open_control.c, peer_control.c, walletrpc.c, and a test stub are updated. The functional behavior remains the same: callers previously checked if (num_utxos) or == 0, now they check the boolean directly. The new outputs array is unused by existing callers (always passed as NULL).
Changed components
wallet/wallet.cwallet/wallet.hwallet/walletrpc.clightningd/chaintopology.clightningd/channel_control.clightningd/dual_open_control.clightningd/peer_control.clightningd/test/run-invoice-select-inchan.cInspect captured patch +37 / −25
diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c
index 0b2caec7..1f460e84 100644
--- a/lightningd/chaintopology.c
+++ b/lightningd/chaintopology.c
@@ -71,7 +71,7 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b)
txid = b->txids[i];
if (txfilter_match(filter, tx)) {
wallet_extract_owned_outputs(topo->bitcoind->ld->wallet,
- tx->wtx, is_coinbase, &b->height);
+ tx->wtx, is_coinbase, &b->height, NULL);
wallet_transaction_add(topo->ld->wallet, tx->wtx,
b->height, i);
// invoice_check_onchain_payment(tx);
diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c
index f03d224c..4a7a9b09 100644
--- a/lightningd/channel_control.c
+++ b/lightningd/channel_control.c
@@ -523,18 +523,17 @@ static void handle_tx_broadcast(struct send_splice_info *info)
struct json_stream *response;
struct bitcoin_txid txid;
u8 *tx_bytes;
- int num_utxos;
struct splice_command *cc;
tx_bytes = linearize_tx(tmpctx, info->final_tx);
bitcoin_txid(info->final_tx, &txid);
/* This might have spent UTXOs from our wallet */
- num_utxos = wallet_extract_owned_outputs(ld->wallet,
- info->final_tx->wtx, false,
- NULL);
- if (num_utxos)
+ if (wallet_extract_owned_outputs(ld->wallet,
+ info->final_tx->wtx, false,
+ NULL, NULL)) {
wallet_transaction_add(ld->wallet, info->final_tx->wtx, 0, 0);
+ }
cc = splice_command_for_chan(ld, info->channel);
diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c
index a605a528..cbd43ca5 100644
--- a/lightningd/dual_open_control.c
+++ b/lightningd/dual_open_control.c
@@ -1655,14 +1655,13 @@ static void handle_tx_broadcast(struct channel_send *cs)
struct command *cmd = channel->openchannel_signed_cmd;
struct json_stream *response;
struct bitcoin_txid txid;
- int num_utxos;
/* This might have spent UTXOs from our wallet */
- num_utxos = wallet_extract_owned_outputs(ld->wallet,
- /* FIXME: what txindex? */
- wtx, false, NULL);
- if (num_utxos)
+ if (wallet_extract_owned_outputs(ld->wallet,
+ /* FIXME: what txindex? */
+ wtx, false, NULL, NULL)) {
wallet_transaction_add(ld->wallet, wtx, 0, 0);
+ }
if (cmd) {
response = json_stream_success(cmd);
diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c
index d6393ffa..94fb9b85 100644
--- a/lightningd/peer_control.c
+++ b/lightningd/peer_control.c
@@ -310,7 +310,7 @@ static struct bitcoin_tx *sign_and_send_last(const tal_t *ctx,
tx = sign_last_tx(ctx, channel, last_tx, last_sig);
bitcoin_txid(tx, &txid);
wallet_transaction_add(ld->wallet, tx->wtx, 0, 0);
- wallet_extract_owned_outputs(ld->wallet, tx->wtx, false, NULL);
+ wallet_extract_owned_outputs(ld->wallet, tx->wtx, false, NULL, NULL);
/* Remember anchor information for commit_tx_boost */
adet = create_anchor_details(NULL, channel, tx);
diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c
index 4dd160f3..bb27f087 100644
--- a/lightningd/test/run-invoice-select-inchan.c
+++ b/lightningd/test/run-invoice-select-inchan.c
@@ -675,9 +675,11 @@ void wallet_channel_save(struct wallet *w UNNEEDED, struct channel *chan UNNEEDE
void wallet_delete_peer_if_unused(struct wallet *w UNNEEDED, u64 peer_dbid UNNEEDED)
{ fprintf(stderr, "wallet_delete_peer_if_unused called!\n"); abort(); }
/* Generated stub for wallet_extract_owned_outputs */
-int wallet_extract_owned_outputs(struct wallet *w UNNEEDED, const struct wally_tx *tx UNNEEDED,
- bool is_coinbase UNNEEDED,
- const u32 *blockheight UNNEEDED)
+bool wallet_extract_owned_outputs(struct wallet *w UNNEEDED,
+ const struct wally_tx *wtx UNNEEDED,
+ bool is_coinbase UNNEEDED,
+ const u32 *blockheight UNNEEDED,
+ size_t **outputs UNNEEDED)
{ fprintf(stderr, "wallet_extract_owned_outputs called!\n"); abort(); }
/* Generated stub for wallet_htlcs_load_in_for_channel */
bool wallet_htlcs_load_in_for_channel(struct wallet *wallet UNNEEDED,
diff --git a/wallet/wallet.c b/wallet/wallet.c
index a8f4da06..fdfa48ed 100644
--- a/wallet/wallet.c
+++ b/wallet/wallet.c
@@ -3365,11 +3365,13 @@ type_ok:
*outpoint = utxo->outpoint;
}
-int wallet_extract_owned_outputs(struct wallet *w, const struct wally_tx *wtx,
- bool is_coinbase,
- const u32 *blockheight)
+bool wallet_extract_owned_outputs(struct wallet *w,
+ const struct wally_tx *wtx,
+ bool is_coinbase,
+ const u32 *blockheight,
+ size_t **outputs)
{
- int num_utxos = 0;
+ bool matched = false;
for (size_t i = 0; i < wtx->num_outputs; i++) {
const struct wally_tx_output *txout = &wtx->outputs[i];
@@ -3384,9 +3386,11 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct wally_tx *wtx,
continue;
got_utxo(w, keyindex, addrtype, wtx, i, is_coinbase, blockheight, NULL);
- num_utxos++;
+ matched = true;
+ if (outputs)
+ tal_arr_expand(outputs, i);
}
- return num_utxos;
+ return matched;
}
void wallet_htlc_save_in(struct wallet *wallet,
diff --git a/wallet/wallet.h b/wallet/wallet.h
index dcfc3878..d7a13132 100644
--- a/wallet/wallet.h
+++ b/wallet/wallet.h
@@ -801,10 +801,18 @@ u32 wallet_blocks_contig_minheight(struct wallet *w);
/**
* wallet_extract_owned_outputs - given a tx, extract all of our outputs
+ * @w: wallet
+ * @is_coinbase: true if this is output 0 (can't spend for 100 blocks)
+ * @blockheight: non-NULL blockheight if known.
+ * @outputs: if non-NULL, output numbers of owned outputs are appended to it.
+ *
+ * Returns true if at least one output was to one of our addresses.
*/
-int wallet_extract_owned_outputs(struct wallet *w, const struct wally_tx *tx,
- bool is_coinbase,
- const u32 *blockheight);
+bool wallet_extract_owned_outputs(struct wallet *w,
+ const struct wally_tx *wtx,
+ bool is_coinbase,
+ const u32 *blockheight,
+ size_t **outputs);
/**
* wallet_htlc_save_in - store an htlc_in in the database
diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c
index 4ea6b3b0..3c022f96 100644
--- a/wallet/walletrpc.c
+++ b/wallet/walletrpc.c
@@ -1027,7 +1027,7 @@ static void sendpsbt_done(struct bitcoind *bitcoind UNUSED,
wally_txid(sending->wtx, &txid);
/* Extract the change output and add it to the DB */
- if (wallet_extract_owned_outputs(ld->wallet, sending->wtx, false, NULL) == 0) {
+ if (!wallet_extract_owned_outputs(ld->wallet, sending->wtx, false, NULL, NULL)) {
/* If we're not watching it for selfish reasons (i.e. pure send to
* others), make sure we're watching it so we can update depth in db */
watch_unconfirmed_txid(ld, ld->topology, &txid);
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.