Skip to content

Commit 8283ad4

Browse files
committed
Change FundingInfo::Contribution to expose contributed output scripts
Exposing the amounts for each output isn't very helpful because it's possible that they vary across over multiple splice candidates due to RBF. This commit changes `FundingInfo::Contribution` and several of the helpers used to derive it to be based on output scripts instead.
1 parent 7d82e14 commit 8283ad4

5 files changed

Lines changed: 117 additions & 70 deletions

File tree

lightning/src/events/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
5151
use bitcoin::hashes::Hash;
5252
use bitcoin::script::ScriptBuf;
5353
use bitcoin::secp256k1::PublicKey;
54-
use bitcoin::{OutPoint, Transaction, TxOut};
54+
use bitcoin::{OutPoint, Transaction};
5555
use core::ops::Deref;
5656

5757
#[allow(unused_imports)]
@@ -81,8 +81,8 @@ pub enum FundingInfo {
8181
Contribution {
8282
/// UTXOs spent as inputs contributed to the funding transaction.
8383
inputs: Vec<OutPoint>,
84-
/// Outputs contributed to the funding transaction.
85-
outputs: Vec<TxOut>,
84+
/// Output scripts contributed to the funding transaction.
85+
outputs: Vec<ScriptBuf>,
8686
},
8787
}
8888

lightning/src/ln/channel.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3083,7 +3083,7 @@ impl PendingFunding {
30833083
self.contributions.iter().flat_map(|c| c.contributed_inputs())
30843084
}
30853085

3086-
fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
3086+
fn contributed_outputs(&self) -> impl Iterator<Item = &bitcoin::Script> + '_ {
30873087
self.contributions.iter().flat_map(|c| c.contributed_outputs())
30883088
}
30893089

@@ -3092,7 +3092,7 @@ impl PendingFunding {
30923092
self.contributions[..len.saturating_sub(1)].iter().flat_map(|c| c.contributed_inputs())
30933093
}
30943094

3095-
fn prior_contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
3095+
fn prior_contributed_outputs(&self) -> impl Iterator<Item = &bitcoin::Script> + '_ {
30963096
let len = self.contributions.len();
30973097
self.contributions[..len.saturating_sub(1)].iter().flat_map(|c| c.contributed_outputs())
30983098
}
@@ -3141,7 +3141,7 @@ pub(crate) enum QuiescentAction {
31413141

31423142
pub(super) enum QuiescentError {
31433143
DoNothing,
3144-
DiscardFunding { inputs: Vec<bitcoin::OutPoint>, outputs: Vec<bitcoin::TxOut> },
3144+
DiscardFunding { inputs: Vec<bitcoin::OutPoint>, outputs: Vec<ScriptBuf> },
31453145
FailSplice(SpliceFundingFailed),
31463146
}
31473147

@@ -6516,23 +6516,27 @@ impl FundingNegotiationContext {
65166516
}
65176517
}
65186518

6519-
fn into_contributed_inputs_and_outputs(self) -> (Vec<bitcoin::OutPoint>, Vec<TxOut>) {
6519+
fn into_contributed_inputs_and_outputs(self) -> (Vec<bitcoin::OutPoint>, Vec<ScriptBuf>) {
65206520
let contributed_inputs =
65216521
self.our_funding_inputs.into_iter().map(|input| input.utxo.outpoint).collect();
6522-
let contributed_outputs = self.our_funding_outputs;
6522+
let contributed_outputs =
6523+
self.our_funding_outputs.into_iter().map(|output| output.script_pubkey).collect();
65236524
(contributed_inputs, contributed_outputs)
65246525
}
65256526

65266527
fn contributed_inputs(&self) -> impl Iterator<Item = bitcoin::OutPoint> + '_ {
65276528
self.our_funding_inputs.iter().map(|input| input.utxo.outpoint)
65286529
}
65296530

6530-
fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
6531-
self.our_funding_outputs.iter()
6531+
fn contributed_outputs(&self) -> impl Iterator<Item = &bitcoin::Script> + '_ {
6532+
self.our_funding_outputs.iter().map(|output| output.script_pubkey.as_script())
65326533
}
65336534

6534-
fn to_contributed_inputs_and_outputs(&self) -> (Vec<bitcoin::OutPoint>, Vec<TxOut>) {
6535-
(self.contributed_inputs().collect(), self.contributed_outputs().cloned().collect())
6535+
fn to_contributed_inputs_and_outputs(&self) -> (Vec<bitcoin::OutPoint>, Vec<ScriptBuf>) {
6536+
(
6537+
self.contributed_inputs().collect(),
6538+
self.contributed_outputs().map(|script| script.into()).collect(),
6539+
)
65366540
}
65376541
}
65386542

@@ -6692,8 +6696,8 @@ pub struct SpliceFundingFailed {
66926696
/// UTXOs spent as inputs contributed to the splice transaction.
66936697
pub contributed_inputs: Vec<bitcoin::OutPoint>,
66946698

6695-
/// Outputs contributed to the splice transaction.
6696-
pub contributed_outputs: Vec<bitcoin::TxOut>,
6699+
/// Output scripts contributed to the splice transaction.
6700+
pub contributed_outputs: Vec<ScriptBuf>,
66976701
}
66986702

66996703
macro_rules! maybe_create_splice_funding_failed {
@@ -6733,7 +6737,7 @@ macro_rules! maybe_create_splice_funding_failed {
67336737
contributed_inputs.retain(|i| *i != input);
67346738
}
67356739
for output in pending_splice.prior_contributed_outputs() {
6736-
contributed_outputs.retain(|o| o.script_pubkey != output.script_pubkey);
6740+
contributed_outputs.retain(|i| i != output);
67376741
}
67386742
}
67396743

@@ -6778,15 +6782,16 @@ where
67786782
fn quiescent_action_into_error(&self, action: QuiescentAction) -> QuiescentError {
67796783
match action {
67806784
QuiescentAction::Splice { contribution, .. } => {
6781-
let (mut inputs, mut outputs) = contribution.into_contributed_inputs_and_outputs();
6782-
if let Some(ref pending_splice) = self.pending_splice {
6783-
for input in pending_splice.contributed_inputs() {
6784-
inputs.retain(|i| *i != input);
6785-
}
6786-
for output in pending_splice.contributed_outputs() {
6787-
outputs.retain(|o| o.script_pubkey != output.script_pubkey);
6788-
}
6789-
}
6785+
let (inputs, outputs) = if let Some(ref pending_splice) = self.pending_splice {
6786+
contribution
6787+
.into_unique_contributions(
6788+
pending_splice.contributed_inputs(),
6789+
pending_splice.contributed_outputs(),
6790+
)
6791+
.unwrap_or((Vec::new(), Vec::new()))
6792+
} else {
6793+
contribution.into_contributed_inputs_and_outputs()
6794+
};
67906795
QuiescentError::FailSplice(SpliceFundingFailed {
67916796
funding_txo: None,
67926797
channel_type: None,

lightning/src/ln/funding.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,11 @@ impl FundingContribution {
422422
self.inputs.iter().map(|input| input.utxo.outpoint)
423423
}
424424

425-
pub(super) fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
426-
self.outputs.iter().chain(self.change_output.iter())
425+
pub(super) fn contributed_outputs(&self) -> impl Iterator<Item = &bitcoin::Script> + '_ {
426+
self.outputs
427+
.iter()
428+
.chain(self.change_output.iter())
429+
.map(|output| output.script_pubkey.as_script())
427430
}
428431

429432
/// Returns the change output included in this contribution, if any.
@@ -444,26 +447,41 @@ impl FundingContribution {
444447
(inputs, outputs)
445448
}
446449

447-
pub(super) fn into_contributed_inputs_and_outputs(self) -> (Vec<OutPoint>, Vec<TxOut>) {
448-
let (inputs, outputs) = self.into_tx_parts();
449-
450-
(inputs.into_iter().map(|input| input.utxo.outpoint).collect(), outputs)
450+
pub(super) fn into_contributed_inputs_and_outputs(self) -> (Vec<OutPoint>, Vec<ScriptBuf>) {
451+
let FundingContribution { inputs, outputs, change_output, .. } = self;
452+
let contributed_inputs = inputs.into_iter().map(|input| input.utxo.outpoint).collect();
453+
let contributed_outputs = outputs.into_iter().chain(change_output.into_iter());
454+
(contributed_inputs, contributed_outputs.map(|output| output.script_pubkey).collect())
451455
}
452456

453457
pub(super) fn into_unique_contributions<'a>(
454458
self, existing_inputs: impl Iterator<Item = OutPoint>,
455-
existing_outputs: impl Iterator<Item = &'a TxOut>,
456-
) -> Option<(Vec<OutPoint>, Vec<TxOut>)> {
457-
let (mut inputs, mut outputs) = self.into_contributed_inputs_and_outputs();
459+
existing_outputs: impl Iterator<Item = &'a bitcoin::Script>,
460+
) -> Option<(Vec<OutPoint>, Vec<ScriptBuf>)> {
461+
let FundingContribution { mut inputs, mut outputs, mut change_output, .. } = self;
458462
for existing in existing_inputs {
459-
inputs.retain(|input| *input != existing);
463+
inputs.retain(|input| input.outpoint() != existing);
460464
}
461465
for existing in existing_outputs {
462-
outputs.retain(|output| *output != *existing);
466+
outputs.retain(|output| output.script_pubkey.as_script() != existing);
467+
// TODO: Replace with `take_if` once our MSRV is >= 1.80.
468+
if change_output
469+
.as_ref()
470+
.filter(|output| output.script_pubkey.as_script() == existing)
471+
.is_some()
472+
{
473+
change_output.take();
474+
}
463475
}
464-
if inputs.is_empty() && outputs.is_empty() {
476+
if inputs.is_empty() && outputs.is_empty() && change_output.as_ref().is_none() {
465477
None
466478
} else {
479+
let inputs = inputs.into_iter().map(|input| input.outpoint()).collect();
480+
let outputs = outputs
481+
.into_iter()
482+
.chain(change_output.into_iter())
483+
.map(|output| output.script_pubkey)
484+
.collect();
467485
Some((inputs, outputs))
468486
}
469487
}

lightning/src/ln/interactivetxs.rs

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl SerialIdExt for SerialId {
9494
pub(crate) struct NegotiationError {
9595
pub reason: AbortReason,
9696
pub contributed_inputs: Vec<BitcoinOutPoint>,
97-
pub contributed_outputs: Vec<TxOut>,
97+
pub contributed_outputs: Vec<ScriptBuf>,
9898
}
9999

100100
#[derive(Debug, Clone, Copy, PartialEq)]
@@ -390,22 +390,25 @@ impl ConstructedTransaction {
390390
.map(|(_, (txin, _))| txin.previous_output)
391391
}
392392

393-
fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
393+
fn contributed_outputs(&self) -> impl Iterator<Item = &bitcoin::Script> + '_ {
394394
self.tx
395395
.output
396396
.iter()
397397
.zip(self.output_metadata.iter())
398398
.enumerate()
399399
.filter(|(_, (_, output))| output.is_local(self.holder_is_initiator))
400400
.filter(|(index, _)| *index != self.shared_output_index as usize)
401-
.map(|(_, (txout, _))| txout)
401+
.map(|(_, (txout, _))| txout.script_pubkey.as_script())
402402
}
403403

404-
fn to_contributed_inputs_and_outputs(&self) -> (Vec<BitcoinOutPoint>, Vec<TxOut>) {
405-
(self.contributed_inputs().collect(), self.contributed_outputs().cloned().collect())
404+
fn to_contributed_inputs_and_outputs(&self) -> (Vec<BitcoinOutPoint>, Vec<ScriptBuf>) {
405+
(
406+
self.contributed_inputs().collect(),
407+
self.contributed_outputs().map(|script| script.into()).collect(),
408+
)
406409
}
407410

408-
fn into_contributed_inputs_and_outputs(self) -> (Vec<BitcoinOutPoint>, Vec<TxOut>) {
411+
fn into_contributed_inputs_and_outputs(self) -> (Vec<BitcoinOutPoint>, Vec<ScriptBuf>) {
409412
let contributed_inputs = self
410413
.tx
411414
.input
@@ -429,7 +432,7 @@ impl ConstructedTransaction {
429432
.enumerate()
430433
.filter(|(_, (_, output))| output.is_local(self.holder_is_initiator))
431434
.filter(|(index, _)| *index != self.shared_output_index as usize)
432-
.map(|(_, (txout, _))| txout)
435+
.map(|(_, (txout, _))| txout.script_pubkey)
433436
.collect();
434437

435438
(contributed_inputs, contributed_outputs)
@@ -917,15 +920,19 @@ impl InteractiveTxSigningSession {
917920
self.unsigned_tx.contributed_inputs()
918921
}
919922

920-
pub(super) fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
923+
pub(super) fn contributed_outputs(&self) -> impl Iterator<Item = &bitcoin::Script> + '_ {
921924
self.unsigned_tx.contributed_outputs()
922925
}
923926

924-
pub(super) fn to_contributed_inputs_and_outputs(&self) -> (Vec<BitcoinOutPoint>, Vec<TxOut>) {
925-
(self.contributed_inputs().collect(), self.contributed_outputs().cloned().collect())
927+
pub(super) fn to_contributed_inputs_and_outputs(
928+
&self,
929+
) -> (Vec<BitcoinOutPoint>, Vec<ScriptBuf>) {
930+
self.unsigned_tx.to_contributed_inputs_and_outputs()
926931
}
927932

928-
pub(super) fn into_contributed_inputs_and_outputs(self) -> (Vec<BitcoinOutPoint>, Vec<TxOut>) {
933+
pub(super) fn into_contributed_inputs_and_outputs(
934+
self,
935+
) -> (Vec<BitcoinOutPoint>, Vec<ScriptBuf>) {
929936
self.unsigned_tx.into_contributed_inputs_and_outputs()
930937
}
931938
}
@@ -2165,7 +2172,9 @@ impl InteractiveTxConstructor {
21652172
NegotiationError { reason, contributed_inputs, contributed_outputs }
21662173
}
21672174

2168-
pub(super) fn into_contributed_inputs_and_outputs(self) -> (Vec<BitcoinOutPoint>, Vec<TxOut>) {
2175+
pub(super) fn into_contributed_inputs_and_outputs(
2176+
self,
2177+
) -> (Vec<BitcoinOutPoint>, Vec<ScriptBuf>) {
21692178
let contributed_inputs = self
21702179
.inputs_to_contribute
21712180
.into_iter()
@@ -2176,8 +2185,9 @@ impl InteractiveTxConstructor {
21762185
.outputs_to_contribute
21772186
.into_iter()
21782187
.filter(|(_, output)| !output.is_shared())
2179-
.map(|(_, output)| output.into_tx_out())
2188+
.map(|(_, output)| output.into_tx_out().script_pubkey)
21802189
.collect();
2190+
21812191
(contributed_inputs, contributed_outputs)
21822192
}
21832193

@@ -2188,15 +2198,20 @@ impl InteractiveTxConstructor {
21882198
.map(|(_, input)| input.tx_in().previous_output)
21892199
}
21902200

2191-
pub(super) fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
2201+
pub(super) fn contributed_outputs(&self) -> impl Iterator<Item = &bitcoin::Script> + '_ {
21922202
self.outputs_to_contribute
21932203
.iter()
21942204
.filter(|(_, output)| !output.is_shared())
2195-
.map(|(_, output)| output.tx_out())
2205+
.map(|(_, output)| output.tx_out().script_pubkey.as_script())
21962206
}
21972207

2198-
pub(super) fn to_contributed_inputs_and_outputs(&self) -> (Vec<BitcoinOutPoint>, Vec<TxOut>) {
2199-
(self.contributed_inputs().collect(), self.contributed_outputs().cloned().collect())
2208+
pub(super) fn to_contributed_inputs_and_outputs(
2209+
&self,
2210+
) -> (Vec<BitcoinOutPoint>, Vec<ScriptBuf>) {
2211+
(
2212+
self.contributed_inputs().collect(),
2213+
self.contributed_outputs().map(|script| script.into()).collect(),
2214+
)
22002215
}
22012216

22022217
pub fn is_initiator(&self) -> bool {

0 commit comments

Comments
 (0)