Skip to content

Commit b9dfd8c

Browse files
committed
Add FundingNeeded event for splicing
Rather than requiring the user to pass FundingTxInputs when initiating a splice, generate a FundingNeeded event once the channel has become quiescent. This simplifies error handling and UTXO / change address clean-up by consolidating it in SpliceFailed event handling. Later, this event will be used for opportunistic contributions (i.e., when the counterparty wins quiescence or initiates), dual-funding, and RBF.
1 parent 8f82573 commit b9dfd8c

File tree

9 files changed

+1083
-708
lines changed

9 files changed

+1083
-708
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use lightning::ln::channelmanager::{
5252
RecipientOnionFields,
5353
};
5454
use lightning::ln::functional_test_utils::*;
55-
use lightning::ln::funding::{FundingTxInput, SpliceContribution};
55+
use lightning::ln::funding::SpliceContribution;
5656
use lightning::ln::inbound_payment::ExpandedKey;
5757
use lightning::ln::msgs::{
5858
BaseMessageHandler, ChannelMessageHandler, CommitmentUpdate, Init, MessageSendEvent,
@@ -1859,16 +1859,11 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
18591859
},
18601860

18611861
0xa0 => {
1862-
let input = FundingTxInput::new_p2wpkh(coinbase_tx.clone(), 0).unwrap();
1863-
let contribution =
1864-
SpliceContribution::splice_in(Amount::from_sat(10_000), vec![input], None);
1865-
let funding_feerate_sat_per_kw = fee_est_a.ret_val.load(atomic::Ordering::Acquire);
1862+
let contribution = SpliceContribution::splice_in(Amount::from_sat(10_000), None);
18661863
if let Err(e) = nodes[0].splice_channel(
18671864
&chan_a_id,
18681865
&nodes[1].get_our_node_id(),
18691866
contribution,
1870-
funding_feerate_sat_per_kw,
1871-
None,
18721867
) {
18731868
assert!(
18741869
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),
@@ -1878,16 +1873,11 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
18781873
}
18791874
},
18801875
0xa1 => {
1881-
let input = FundingTxInput::new_p2wpkh(coinbase_tx.clone(), 1).unwrap();
1882-
let contribution =
1883-
SpliceContribution::splice_in(Amount::from_sat(10_000), vec![input], None);
1884-
let funding_feerate_sat_per_kw = fee_est_b.ret_val.load(atomic::Ordering::Acquire);
1876+
let contribution = SpliceContribution::splice_in(Amount::from_sat(10_000), None);
18851877
if let Err(e) = nodes[1].splice_channel(
18861878
&chan_a_id,
18871879
&nodes[0].get_our_node_id(),
18881880
contribution,
1889-
funding_feerate_sat_per_kw,
1890-
None,
18911881
) {
18921882
assert!(
18931883
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),
@@ -1897,16 +1887,11 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
18971887
}
18981888
},
18991889
0xa2 => {
1900-
let input = FundingTxInput::new_p2wpkh(coinbase_tx.clone(), 0).unwrap();
1901-
let contribution =
1902-
SpliceContribution::splice_in(Amount::from_sat(10_000), vec![input], None);
1903-
let funding_feerate_sat_per_kw = fee_est_b.ret_val.load(atomic::Ordering::Acquire);
1890+
let contribution = SpliceContribution::splice_in(Amount::from_sat(10_000), None);
19041891
if let Err(e) = nodes[1].splice_channel(
19051892
&chan_b_id,
19061893
&nodes[2].get_our_node_id(),
19071894
contribution,
1908-
funding_feerate_sat_per_kw,
1909-
None,
19101895
) {
19111896
assert!(
19121897
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),
@@ -1916,16 +1901,11 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
19161901
}
19171902
},
19181903
0xa3 => {
1919-
let input = FundingTxInput::new_p2wpkh(coinbase_tx.clone(), 1).unwrap();
1920-
let contribution =
1921-
SpliceContribution::splice_in(Amount::from_sat(10_000), vec![input], None);
1922-
let funding_feerate_sat_per_kw = fee_est_c.ret_val.load(atomic::Ordering::Acquire);
1904+
let contribution = SpliceContribution::splice_in(Amount::from_sat(10_000), None);
19231905
if let Err(e) = nodes[2].splice_channel(
19241906
&chan_b_id,
19251907
&nodes[1].get_our_node_id(),
19261908
contribution,
1927-
funding_feerate_sat_per_kw,
1928-
None,
19291909
) {
19301910
assert!(
19311911
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),
@@ -1950,14 +1930,10 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
19501930
value: Amount::from_sat(MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS),
19511931
script_pubkey: coinbase_tx.output[0].script_pubkey.clone(),
19521932
}]);
1953-
let funding_feerate_sat_per_kw =
1954-
fee_est_a.ret_val.load(atomic::Ordering::Acquire);
19551933
if let Err(e) = nodes[0].splice_channel(
19561934
&chan_a_id,
19571935
&nodes[1].get_our_node_id(),
19581936
contribution,
1959-
funding_feerate_sat_per_kw,
1960-
None,
19611937
) {
19621938
assert!(
19631939
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),
@@ -1979,14 +1955,10 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
19791955
value: Amount::from_sat(MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS),
19801956
script_pubkey: coinbase_tx.output[1].script_pubkey.clone(),
19811957
}]);
1982-
let funding_feerate_sat_per_kw =
1983-
fee_est_b.ret_val.load(atomic::Ordering::Acquire);
19841958
if let Err(e) = nodes[1].splice_channel(
19851959
&chan_a_id,
19861960
&nodes[0].get_our_node_id(),
19871961
contribution,
1988-
funding_feerate_sat_per_kw,
1989-
None,
19901962
) {
19911963
assert!(
19921964
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),
@@ -2008,14 +1980,10 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
20081980
value: Amount::from_sat(MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS),
20091981
script_pubkey: coinbase_tx.output[1].script_pubkey.clone(),
20101982
}]);
2011-
let funding_feerate_sat_per_kw =
2012-
fee_est_b.ret_val.load(atomic::Ordering::Acquire);
20131983
if let Err(e) = nodes[1].splice_channel(
20141984
&chan_b_id,
20151985
&nodes[2].get_our_node_id(),
20161986
contribution,
2017-
funding_feerate_sat_per_kw,
2018-
None,
20191987
) {
20201988
assert!(
20211989
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),
@@ -2037,14 +2005,10 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out, anchors: bool) {
20372005
value: Amount::from_sat(MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS),
20382006
script_pubkey: coinbase_tx.output[2].script_pubkey.clone(),
20392007
}]);
2040-
let funding_feerate_sat_per_kw =
2041-
fee_est_c.ret_val.load(atomic::Ordering::Acquire);
20422008
if let Err(e) = nodes[2].splice_channel(
20432009
&chan_b_id,
20442010
&nodes[1].get_our_node_id(),
20452011
contribution,
2046-
funding_feerate_sat_per_kw,
2047-
None,
20482012
) {
20492013
assert!(
20502014
matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice pending")),

lightning/src/events/bump_transaction/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,12 @@ pub struct Input {
271271
pub satisfaction_weight: u64,
272272
}
273273

274+
impl_writeable_tlv_based!(Input, {
275+
(1, outpoint, required),
276+
(3, previous_utxo, required),
277+
(5, satisfaction_weight, required),
278+
});
279+
274280
/// An unspent transaction output that is available to spend resulting from a successful
275281
/// [`CoinSelection`] attempt.
276282
#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]

lightning/src/events/mod.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::blinded_path::payment::{
2525
use crate::chain::transaction;
2626
use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
2727
use crate::ln::channelmanager::{InterceptId, PaymentId, RecipientOnionFields};
28+
use crate::ln::funding::FundingTemplate;
2829
use crate::ln::msgs;
2930
use crate::ln::onion_utils::LocalHTLCFailureReason;
3031
use crate::ln::types::ChannelId;
@@ -1817,6 +1818,36 @@ pub enum Event {
18171818
/// [`ChannelManager::respond_to_static_invoice_request`]: crate::ln::channelmanager::ChannelManager::respond_to_static_invoice_request
18181819
invoice_request: InvoiceRequest,
18191820
},
1821+
/// Indicates that funding is needed for a channel splice or a dual-funded channel open.
1822+
///
1823+
/// The client should build a [`FundingContribution`] from the provided [`FundingTemplate`] and
1824+
/// pass it to [`ChannelManager::funding_contributed`].
1825+
///
1826+
/// [`FundingContribution`]: crate::ln::funding::FundingContribution
1827+
/// [`ChannelManager::funding_contributed`]: crate::ln::channelmanager::ChannelManager::funding_contributed
1828+
FundingNeeded {
1829+
/// The `channel_id` of the channel which you'll need to pass back into
1830+
/// [`ChannelManager::funding_contributed`].
1831+
///
1832+
/// [`ChannelManager::funding_contributed`]: crate::ln::channelmanager::ChannelManager::funding_contributed
1833+
channel_id: ChannelId,
1834+
/// The counterparty's `node_id`, which you'll need to pass back into
1835+
/// [`ChannelManager::funding_contributed`].
1836+
///
1837+
/// [`ChannelManager::funding_contributed`]: crate::ln::channelmanager::ChannelManager::funding_contributed
1838+
counterparty_node_id: PublicKey,
1839+
/// The `user_channel_id` value passed in for outbound channels, or for inbound channels if
1840+
/// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise
1841+
/// `user_channel_id` will be randomized for inbound channels.
1842+
///
1843+
/// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels
1844+
user_channel_id: u128,
1845+
/// A template for constructing a [`FundingContribution`], which contains information when
1846+
/// the funding was initiated.
1847+
///
1848+
/// [`FundingContribution`]: crate::ln::funding::FundingContribution
1849+
funding_template: FundingTemplate,
1850+
},
18201851
/// Indicates that a channel funding transaction constructed interactively is ready to be
18211852
/// signed. This event will only be triggered if at least one input was contributed.
18221853
///
@@ -2348,6 +2379,20 @@ impl Writeable for Event {
23482379
(13, *contributed_outputs, optional_vec),
23492380
});
23502381
},
2382+
&Event::FundingNeeded {
2383+
ref channel_id,
2384+
ref user_channel_id,
2385+
ref counterparty_node_id,
2386+
ref funding_template,
2387+
} => {
2388+
54u8.write(writer)?;
2389+
write_tlv_fields!(writer, {
2390+
(1, channel_id, required),
2391+
(3, user_channel_id, required),
2392+
(5, counterparty_node_id, required),
2393+
(7, funding_template, required),
2394+
});
2395+
},
23512396
// Note that, going forward, all new events must only write data inside of
23522397
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
23532398
// data via `write_tlv_fields`.
@@ -2979,6 +3024,24 @@ impl MaybeReadable for Event {
29793024
};
29803025
f()
29813026
},
3027+
54u8 => {
3028+
let mut f = || {
3029+
_init_and_read_len_prefixed_tlv_fields!(reader, {
3030+
(1, channel_id, required),
3031+
(3, user_channel_id, required),
3032+
(5, counterparty_node_id, required),
3033+
(7, funding_template, required),
3034+
});
3035+
3036+
Ok(Some(Event::FundingNeeded {
3037+
channel_id: channel_id.0.unwrap(),
3038+
user_channel_id: user_channel_id.0.unwrap(),
3039+
counterparty_node_id: counterparty_node_id.0.unwrap(),
3040+
funding_template: funding_template.0.unwrap(),
3041+
}))
3042+
};
3043+
f()
3044+
},
29823045
// Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue.
29833046
// Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt
29843047
// reads.

0 commit comments

Comments
 (0)