@@ -55,7 +55,7 @@ use crate::ln::channelmanager::{
5555 RAACommitmentOrder, SentHTLCId, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT,
5656 MIN_CLTV_EXPIRY_DELTA,
5757};
58- use crate::ln::funding::{FundingTxInput, SpliceContribution};
58+ use crate::ln::funding::{FundingContribution, FundingTxInput, SpliceContribution};
5959use crate::ln::interactivetxs::{
6060 calculate_change_output_value, get_output_weight, AbortReason, HandleTxCompleteValue,
6161 InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSend,
@@ -2802,24 +2802,28 @@ impl_writeable_tlv_based!(SpliceInstructions, {
28022802
28032803#[derive(Debug)]
28042804pub(crate) enum QuiescentAction {
2805- Splice(SpliceInstructions),
2805+ LegacySplice(SpliceInstructions),
2806+ Splice(SpliceContribution),
28062807 #[cfg(any(test, fuzzing))]
28072808 DoNothing,
28082809}
28092810
28102811pub(crate) enum StfuResponse {
28112812 Stfu(msgs::Stfu),
28122813 SpliceInit(msgs::SpliceInit),
2814+ FundingNeeded(FundingContribution),
28132815}
28142816
28152817#[cfg(any(test, fuzzing))]
28162818impl_writeable_tlv_based_enum_upgradable!(QuiescentAction,
28172819 (0, DoNothing) => {},
2818- {1, Splice} => (),
2820+ {1, LegacySplice} => (),
2821+ {2, Splice} => (),
28192822);
28202823#[cfg(not(any(test, fuzzing)))]
28212824impl_writeable_tlv_based_enum_upgradable!(QuiescentAction,,
2822- {1, Splice} => (),
2825+ {1, LegacySplice} => (),
2826+ {2, Splice} => (),
28232827);
28242828
28252829/// Wrapper around a [`Transaction`] useful for caching the result of [`Transaction::compute_txid`].
@@ -6495,7 +6499,7 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
64956499}
64966500
64976501fn check_splice_contribution_sufficient(
6498- contribution: &SpliceContribution , is_initiator: bool, funding_feerate: FeeRate,
6502+ contribution: &FundingContribution , is_initiator: bool, funding_feerate: FeeRate,
64996503) -> Result<SignedAmount, String> {
65006504 if contribution.inputs().is_empty() {
65016505 let estimated_fee = Amount::from_sat(estimate_v2_funding_transaction_fee(
@@ -6621,30 +6625,30 @@ fn check_v2_funding_inputs_sufficient(
66216625
66226626/// Context for negotiating channels (dual-funded V2 open, splicing)
66236627#[derive(Debug)]
6624- pub(super) struct FundingNegotiationContext {
6628+ pub struct FundingNegotiationContext {
66256629 /// Whether we initiated the funding negotiation.
6626- pub is_initiator: bool,
6630+ pub(super) is_initiator: bool,
66276631 /// The amount in satoshis we will be contributing to the channel.
6628- pub our_funding_contribution: SignedAmount,
6632+ pub(super) our_funding_contribution: SignedAmount,
66296633 /// The funding transaction locktime suggested by the initiator. If set by us, it is always set
66306634 /// to the current block height to align incentives against fee-sniping.
6631- pub funding_tx_locktime: LockTime,
6635+ pub(super) funding_tx_locktime: LockTime,
66326636 /// The feerate set by the initiator to be used for the funding transaction.
66336637 #[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled.
6634- pub funding_feerate_sat_per_1000_weight: u32,
6638+ pub(super) funding_feerate_sat_per_1000_weight: u32,
66356639 /// The input spending the previous funding output, if this is a splice.
66366640 #[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
6637- pub shared_funding_input: Option<SharedOwnedInput>,
6641+ pub(super) shared_funding_input: Option<SharedOwnedInput>,
66386642 /// The funding inputs we will be contributing to the channel.
66396643 #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
6640- pub our_funding_inputs: Vec<FundingTxInput>,
6644+ pub(super) our_funding_inputs: Vec<FundingTxInput>,
66416645 /// The funding outputs we will be contributing to the channel.
66426646 #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
6643- pub our_funding_outputs: Vec<TxOut>,
6647+ pub(super) our_funding_outputs: Vec<TxOut>,
66446648 /// The change output script. This will be used if needed or -- if not set -- generated using
66456649 /// `SignerProvider::get_destination_script`.
66466650 #[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
6647- pub change_script: Option<ScriptBuf>,
6651+ pub(super) change_script: Option<ScriptBuf>,
66486652}
66496653
66506654impl FundingNegotiationContext {
@@ -6970,7 +6974,7 @@ where
69706974 self.reset_pending_splice_state()
69716975 } else {
69726976 match self.quiescent_action.take() {
6973- Some(QuiescentAction::Splice (instructions)) => {
6977+ Some(QuiescentAction::LegacySplice (instructions)) => {
69746978 self.context.channel_state.clear_awaiting_quiescence();
69756979 let (inputs, outputs) = instructions.into_contributed_inputs_and_outputs();
69766980 Some(SpliceFundingFailed {
@@ -6980,6 +6984,15 @@ where
69806984 contributed_outputs: outputs,
69816985 })
69826986 },
6987+ Some(QuiescentAction::Splice(contribution)) => {
6988+ self.context.channel_state.clear_awaiting_quiescence();
6989+ Some(SpliceFundingFailed {
6990+ funding_txo: None,
6991+ channel_type: None,
6992+ contributed_inputs: vec![],
6993+ contributed_outputs: contribution.into_outputs(),
6994+ })
6995+ },
69836996 #[cfg(any(test, fuzzing))]
69846997 Some(quiescent_action) => {
69856998 self.quiescent_action = Some(quiescent_action);
@@ -11274,7 +11287,7 @@ where
1127411287 self.get_announcement_sigs(node_signer, chain_hash, user_config, block_height, logger);
1127511288
1127611289 if let Some(quiescent_action) = self.quiescent_action.as_ref() {
11277- if matches!(quiescent_action, QuiescentAction::Splice(_)) {
11290+ if matches!(quiescent_action, QuiescentAction::Splice(_) | QuiescentAction::LegacySplice(_) ) {
1127811291 self.context.channel_state.set_awaiting_quiescence();
1127911292 }
1128011293 }
@@ -11924,8 +11937,7 @@ where
1192411937 /// - `change_script`: an option change output script. If `None` and needed, one will be
1192511938 /// generated by `SignerProvider::get_destination_script`.
1192611939 pub fn splice_channel<L: Deref>(
11927- &mut self, contribution: SpliceContribution, funding_feerate_per_kw: u32, locktime: u32,
11928- logger: &L,
11940+ &mut self, contribution: SpliceContribution, logger: &L,
1192911941 ) -> Result<Option<msgs::Stfu>, APIError>
1193011942 where
1193111943 L::Target: Logger,
@@ -11939,8 +11951,15 @@ where
1193911951 });
1194011952 }
1194111953
11942- // Check if a splice has been initiated already.
11943- // Note: only a single outstanding splice is supported (per spec)
11954+ if self.context.channel_state.is_quiescent() {
11955+ return Err(APIError::APIMisuseError {
11956+ err: format!(
11957+ "Channel {} cannot be spliced as it is already quiescent",
11958+ self.context.channel_id(),
11959+ ),
11960+ });
11961+ }
11962+
1194411963 if self.pending_splice.is_some() || self.quiescent_action.is_some() {
1194511964 return Err(APIError::APIMisuseError {
1194611965 err: format!(
@@ -11969,71 +11988,71 @@ where
1196911988 });
1197011989 }
1197111990
11972- // Fees for splice-out are paid from the channel balance whereas fees for splice-in
11973- // are paid by the funding inputs. Therefore, in the case of splice-out, we add the
11974- // fees on top of the user-specified contribution. We leave the user-specified
11975- // contribution as-is for splice-ins.
11976- let adjusted_funding_contribution = check_splice_contribution_sufficient(
11977- &contribution,
11978- true,
11979- FeeRate::from_sat_per_kwu(u64::from(funding_feerate_per_kw)),
11980- )
11981- .map_err(|e| APIError::APIMisuseError {
11982- err: format!(
11983- "Channel {} cannot be {}; {}",
11984- self.context.channel_id(),
11985- if our_funding_contribution.is_positive() { "spliced in" } else { "spliced out" },
11986- e
11987- ),
11988- })?;
11991+ //// Fees for splice-out are paid from the channel balance whereas fees for splice-in
11992+ //// are paid by the funding inputs. Therefore, in the case of splice-out, we add the
11993+ //// fees on top of the user-specified contribution. We leave the user-specified
11994+ //// contribution as-is for splice-ins.
11995+ // let adjusted_funding_contribution = check_splice_contribution_sufficient(
11996+ // &contribution,
11997+ // true,
11998+ // FeeRate::from_sat_per_kwu(u64::from(funding_feerate_per_kw)),
11999+ // )
12000+ // .map_err(|e| APIError::APIMisuseError {
12001+ // err: format!(
12002+ // "Channel {} cannot be {}; {}",
12003+ // self.context.channel_id(),
12004+ // if our_funding_contribution.is_positive() { "spliced in" } else { "spliced out" },
12005+ // e
12006+ // ),
12007+ // })?;
1198912008
1199012009 // Note: post-splice channel value is not yet known at this point, counterparty contribution is not known
1199112010 // (Cannot test for miminum required post-splice channel value)
1199212011 let their_funding_contribution = SignedAmount::ZERO;
1199312012 self.validate_splice_contributions(
11994- adjusted_funding_contribution,
12013+ //adjusted_funding_contribution,
12014+ our_funding_contribution,
1199512015 their_funding_contribution,
1199612016 )
1199712017 .map_err(|err| APIError::APIMisuseError { err })?;
1199812018
11999- for FundingTxInput { utxo, prevtx, .. } in contribution.inputs().iter() {
12000- const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
12001- channel_id: ChannelId([0; 32]),
12002- serial_id: 0,
12003- prevtx: None,
12004- prevtx_out: 0,
12005- sequence: 0,
12006- // Mutually exclusive with prevtx, which is accounted for below.
12007- shared_input_txid: None,
12008- };
12009- let message_len = MESSAGE_TEMPLATE.serialized_length() + prevtx.serialized_length();
12010- if message_len > LN_MAX_MSG_LEN {
12011- return Err(APIError::APIMisuseError {
12012- err: format!(
12013- "Funding input references a prevtx that is too large for tx_add_input: {}",
12014- utxo.outpoint,
12015- ),
12016- });
12017- }
12018- }
12019-
12020- let (our_funding_inputs, our_funding_outputs, change_script) = contribution.into_tx_parts();
12021-
12022- let action = QuiescentAction::Splice(SpliceInstructions {
12023- adjusted_funding_contribution,
12024- our_funding_inputs,
12025- our_funding_outputs,
12026- change_script,
12027- funding_feerate_per_kw,
12028- locktime,
12029- });
12030- self.propose_quiescence(logger, action)
12019+ //for FundingTxInput { utxo, prevtx, .. } in contribution.inputs().iter() {
12020+ // const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
12021+ // channel_id: ChannelId([0; 32]),
12022+ // serial_id: 0,
12023+ // prevtx: None,
12024+ // prevtx_out: 0,
12025+ // sequence: 0,
12026+ // // Mutually exclusive with prevtx, which is accounted for below.
12027+ // shared_input_txid: None,
12028+ // };
12029+ // let message_len = MESSAGE_TEMPLATE.serialized_length() + prevtx.serialized_length();
12030+ // if message_len > LN_MAX_MSG_LEN {
12031+ // return Err(APIError::APIMisuseError {
12032+ // err: format!(
12033+ // "Funding input references a prevtx that is too large for tx_add_input: {}",
12034+ // utxo.outpoint,
12035+ // ),
12036+ // });
12037+ // }
12038+ //}
12039+
12040+ self.propose_quiescence(logger, QuiescentAction::Splice(contribution))
1203112041 .map_err(|e| APIError::APIMisuseError { err: e.to_owned() })
1203212042 }
1203312043
12034- fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
12035- debug_assert!(self.pending_splice.is_none());
12044+ pub fn funding_contributed<L: Deref>(
12045+ &mut self, context: FundingNegotiationContext, logger: &L,
12046+ ) -> Result<msgs::SpliceInit, APIError>
12047+ where
12048+ L::Target: Logger,
12049+ {
12050+ // TODO: Add any checks or move them to FundingNegotiationContext construction. Probably
12051+ // emit a `SpliceFailed` event instead of returning an error
12052+ Ok(self.send_splice_init_internal(context))
12053+ }
1203612054
12055+ fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
1203712056 let SpliceInstructions {
1203812057 adjusted_funding_contribution,
1203912058 our_funding_inputs,
@@ -12055,6 +12074,11 @@ where
1205512074 change_script,
1205612075 };
1205712076
12077+ self.send_splice_init_internal(context)
12078+ }
12079+
12080+ fn send_splice_init_internal(&mut self, context: FundingNegotiationContext) -> msgs::SpliceInit {
12081+ debug_assert!(self.pending_splice.is_none());
1205812082 // Rotate the funding pubkey using the prev_funding_txid as a tweak
1205912083 let prev_funding_txid = self.funding.get_funding_txid();
1206012084 let funding_pubkey = match (prev_funding_txid, &self.context.holder_signer) {
@@ -12069,6 +12093,10 @@ where
1206912093 _ => todo!(),
1207012094 };
1207112095
12096+ let funding_feerate_per_kw = context.funding_feerate_sat_per_1000_weight;
12097+ let funding_contribution_satoshis = context.our_funding_contribution.to_sat();
12098+ let locktime = context.funding_tx_locktime.to_consensus_u32();
12099+
1207212100 let funding_negotiation =
1207312101 FundingNegotiation::AwaitingAck { context, new_holder_funding_key: funding_pubkey };
1207412102 self.pending_splice = Some(PendingFunding {
@@ -12080,7 +12108,7 @@ where
1208012108
1208112109 msgs::SpliceInit {
1208212110 channel_id: self.context.channel_id,
12083- funding_contribution_satoshis: adjusted_funding_contribution.to_sat() ,
12111+ funding_contribution_satoshis,
1208412112 funding_feerate_per_kw,
1208512113 locktime,
1208612114 funding_pubkey,
@@ -13302,9 +13330,9 @@ where
1330213330 "Internal Error: Didn't have anything to do after reaching quiescence".to_owned()
1330313331 ));
1330413332 },
13305- Some(QuiescentAction::Splice (instructions)) => {
13333+ Some(QuiescentAction::LegacySplice (instructions)) => {
1330613334 if self.pending_splice.is_some() {
13307- self.quiescent_action = Some(QuiescentAction::Splice (instructions));
13335+ self.quiescent_action = Some(QuiescentAction::LegacySplice (instructions));
1330813336
1330913337 return Err(ChannelError::WarnAndDisconnect(
1331013338 format!(
@@ -13317,6 +13345,21 @@ where
1331713345 let splice_init = self.send_splice_init(instructions);
1331813346 return Ok(Some(StfuResponse::SpliceInit(splice_init)));
1331913347 },
13348+ Some(QuiescentAction::Splice(contribution)) => {
13349+ if self.pending_splice.is_some() {
13350+ self.quiescent_action = Some(QuiescentAction::Splice(contribution));
13351+
13352+ return Err(ChannelError::WarnAndDisconnect(
13353+ format!(
13354+ "Channel {} cannot be spliced as it already has a splice pending",
13355+ self.context.channel_id(),
13356+ ),
13357+ ));
13358+ }
13359+
13360+ let contribution = contribution.into_funding_contribution();
13361+ return Ok(Some(StfuResponse::FundingNeeded(contribution)));
13362+ },
1332013363 #[cfg(any(test, fuzzing))]
1332113364 Some(QuiescentAction::DoNothing) => {
1332213365 // In quiescence test we want to just hang out here, letting the test manually
0 commit comments