Store shared output index in ConstructedTransaction
What changed, and why it matters
This commit is a small internal cleanup in the code that builds Bitcoin funding transactions for the Lightning interactive-tx protocol. It records the position of the shared funding output inside a data structure, just as the shared input position was already recorded. The immediate change only refactors how the code checks that the shared output exists, and it adds serialization for the new field. There is no direct security fix here, but it prepares the ground for later error-handling logic that will need to ignore the shared output when building protocol error messages.
Treat as a routine refactor/preparatory commit. Review the follow-up commit that uses shared_output_index to ensure the shared output is correctly excluded from any protocol error transaction, because omitting it could leak the shared output or produce an invalid error message. Verify that adding a required TLV field does not break compatibility with older serialized states.
Security signals we found
Refactors shared-output presence check but preserves the same MissingFundingOutput abort behavior
Adds required TLV field shared_output_index, which may affect backward/forward serialization compatibility
Commit message references future interactive-tx error-path filtering of shared inputs/outputs
No bounds or validation logic change beyond the existing u16::MAX sentinel
Evidence from the diff
In lightning/src/ln/interactivetxs.rs, ConstructedTransaction gains a new required u16 field shared_output_index, populated by searching outputs for context.shared_funding_output.tx_out and defaulting to u16::MAX when absent. The existing ‘any()’ check for the shared output is replaced by a comparison against u16::MAX. The field is also added to the TLV serialization macro and to a unit-test construction. The commit message explicitly frames this as groundwork: ‘This will be used later to filter out the shared input when constructing an error during interactive tx negotiation. Store the shared output index as well so that the shared output can be filtered out as well.’
Changed components
lightning/src/ln/interactivetxs.rsConstructedTransaction struct and serializationInteractive transaction negotiation (dual-funded / splicing paths)Inspect captured patch +11 / −1
diff --git a/lightning/src/ln/interactivetxs.rs b/lightning/src/ln/interactivetxs.rs
index 7063edd..ebb6a89 100644
--- a/lightning/src/ln/interactivetxs.rs
+++ b/lightning/src/ln/interactivetxs.rs
@@ -200,6 +200,7 @@ pub(crate) struct ConstructedTransaction {
output_metadata: Vec<TxOutMetadata>,
tx: Transaction,
shared_input_index: Option<u32>,
+ shared_output_index: u16,
}
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -244,6 +245,7 @@ impl_writeable_tlv_based!(ConstructedTransaction, {
(5, output_metadata, required),
(7, tx, required),
(9, shared_input_index, option),
+ (11, shared_output_index, required),
});
impl ConstructedTransaction {
@@ -280,12 +282,19 @@ impl ConstructedTransaction {
.map(|position| position as u32)
});
+ let shared_output_index = output
+ .iter()
+ .position(|txout| *txout == context.shared_funding_output.tx_out)
+ .map(|position| position as u16)
+ .unwrap_or(u16::MAX);
+
let tx = ConstructedTransaction {
holder_is_initiator: context.holder_is_initiator,
input_metadata,
output_metadata,
tx: Transaction { version: Version::TWO, lock_time, input, output },
shared_input_index,
+ shared_output_index,
};
// The receiving node:
@@ -315,7 +324,7 @@ impl ConstructedTransaction {
return Err(AbortReason::MissingFundingInput);
}
- if !tx.tx.output.iter().any(|txout| *txout == context.shared_funding_output.tx_out) {
+ if tx.shared_output_index == u16::MAX {
return Err(AbortReason::MissingFundingOutput);
}
@@ -3329,6 +3338,7 @@ mod tests {
output_metadata: vec![], // N/A for test
tx: transaction.clone(),
shared_input_index: None,
+ shared_output_index: 0,
};
let secp_ctx = Secp256k1::new();
Why this scored 20/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.