@@ -138,12 +138,10 @@ use gossip::GossipSource;
138138use graph:: NetworkGraph ;
139139use io:: utils:: write_node_metrics;
140140use lightning:: chain:: BestBlock ;
141- use lightning:: events:: bump_transaction:: { Input , Wallet as LdkWallet } ;
141+ use lightning:: events:: bump_transaction:: Wallet as LdkWallet ;
142142use lightning:: impl_writeable_tlv_based;
143- use lightning:: ln:: chan_utils:: FUNDING_TRANSACTION_WITNESS_WEIGHT ;
144143use lightning:: ln:: channel_state:: { ChannelDetails as LdkChannelDetails , ChannelShutdownState } ;
145144use lightning:: ln:: channelmanager:: PaymentId ;
146- use lightning:: ln:: funding:: SpliceContribution ;
147145use lightning:: ln:: msgs:: SocketAddress ;
148146use lightning:: routing:: gossip:: NodeAlias ;
149147use lightning:: util:: persist:: KVStoreSync ;
@@ -1290,84 +1288,43 @@ impl Node {
12901288 {
12911289 self . check_sufficient_funds_for_channel ( splice_amount_sats, & counterparty_node_id) ?;
12921290
1293- const EMPTY_SCRIPT_SIG_WEIGHT : u64 =
1294- 1 /* empty script_sig */ * bitcoin:: constants:: WITNESS_SCALE_FACTOR as u64 ;
1295-
1296- let funding_txo = channel_details. funding_txo . ok_or_else ( || {
1297- log_error ! ( self . logger, "Failed to splice channel: channel not yet ready" , ) ;
1298- Error :: ChannelSplicingFailed
1299- } ) ?;
1300-
1301- let funding_output = channel_details. get_funding_output ( ) . ok_or_else ( || {
1302- log_error ! ( self . logger, "Failed to splice channel: channel not yet ready" ) ;
1303- Error :: ChannelSplicingFailed
1304- } ) ?;
1305-
1306- let shared_input = Input {
1307- outpoint : funding_txo. into_bitcoin_outpoint ( ) ,
1308- previous_utxo : funding_output. clone ( ) ,
1309- satisfaction_weight : EMPTY_SCRIPT_SIG_WEIGHT + FUNDING_TRANSACTION_WITNESS_WEIGHT ,
1310- } ;
1311-
1312- let shared_output = bitcoin:: TxOut {
1313- value : shared_input. previous_utxo . value + Amount :: from_sat ( splice_amount_sats) ,
1314- // will not actually be the exact same script pubkey after splice
1315- // but it is the same size and good enough for coin selection purposes
1316- script_pubkey : funding_output. script_pubkey . clone ( ) ,
1317- } ;
1318-
13191291 let fee_rate = self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
13201292
1321- let inputs = self
1322- . wallet
1323- . select_confirmed_utxos ( vec ! [ shared_input] , & [ shared_output] , fee_rate)
1324- . map_err ( |( ) | {
1325- log_error ! (
1326- self . logger,
1327- "Failed to splice channel: insufficient confirmed UTXOs" ,
1328- ) ;
1293+ // Phase 1: Initiate splice negotiation
1294+ let funding_template = self
1295+ . channel_manager
1296+ . splice_channel ( & channel_details. channel_id , & counterparty_node_id, fee_rate)
1297+ . map_err ( |e| {
1298+ log_error ! ( self . logger, "Failed to splice channel: {:?}" , e) ;
13291299 Error :: ChannelSplicingFailed
13301300 } ) ?;
13311301
1332- let change_address = self . wallet . get_new_internal_address ( ) ?;
1333-
1334- let contribution = SpliceContribution :: splice_in (
1335- Amount :: from_sat ( splice_amount_sats) ,
1336- inputs,
1337- Some ( change_address. script_pubkey ( ) ) ,
1338- ) ;
1302+ // Phase 2: Coin selection via LdkWallet (wraps our WalletSource)
1303+ let ldk_wallet = LdkWallet :: new ( Arc :: clone ( & self . wallet ) , Arc :: clone ( & self . logger ) ) ;
1304+ let contribution = self
1305+ . runtime
1306+ . block_on (
1307+ funding_template. splice_in ( Amount :: from_sat ( splice_amount_sats) , & ldk_wallet) ,
1308+ )
1309+ . map_err ( |( ) | {
1310+ log_error ! ( self . logger, "Failed to splice channel: coin selection failed" ) ;
1311+ Error :: ChannelSplicingFailed
1312+ } ) ?;
13391313
1340- let funding_feerate_per_kw: u32 = match fee_rate. to_sat_per_kwu ( ) . try_into ( ) {
1341- Ok ( fee_rate) => fee_rate,
1342- Err ( _) => {
1343- debug_assert ! ( false ) ;
1344- fee_estimator:: get_fallback_rate_for_target ( ConfirmationTarget :: ChannelFunding )
1345- } ,
1346- } ;
1314+ // Persist wallet state after coin selection
1315+ self . wallet . persist ( ) ?;
13471316
1317+ // Phase 3: Submit contribution
13481318 self . channel_manager
1349- . splice_channel (
1319+ . funding_contributed (
13501320 & channel_details. channel_id ,
13511321 & counterparty_node_id,
13521322 contribution,
1353- funding_feerate_per_kw,
13541323 None ,
13551324 )
13561325 . map_err ( |e| {
13571326 log_error ! ( self . logger, "Failed to splice channel: {:?}" , e) ;
1358- let tx = bitcoin:: Transaction {
1359- version : bitcoin:: transaction:: Version :: TWO ,
1360- lock_time : bitcoin:: absolute:: LockTime :: ZERO ,
1361- input : vec ! [ ] ,
1362- output : vec ! [ bitcoin:: TxOut {
1363- value: Amount :: ZERO ,
1364- script_pubkey: change_address. script_pubkey( ) ,
1365- } ] ,
1366- } ;
1367- match self . wallet . cancel_tx ( & tx) {
1368- Ok ( ( ) ) => Error :: ChannelSplicingFailed ,
1369- Err ( e) => e,
1370- }
1327+ Error :: ChannelSplicingFailed
13711328 } )
13721329 } else {
13731330 log_error ! (
@@ -1376,7 +1333,6 @@ impl Node {
13761333 user_channel_id,
13771334 counterparty_node_id
13781335 ) ;
1379-
13801336 Err ( Error :: ChannelSplicingFailed )
13811337 }
13821338 }
@@ -1407,27 +1363,40 @@ impl Node {
14071363
14081364 self . wallet . parse_and_validate_address ( address) ?;
14091365
1410- let contribution = SpliceContribution :: splice_out ( vec ! [ bitcoin:: TxOut {
1366+ let fee_rate = self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
1367+
1368+ // Phase 1: Initiate splice negotiation
1369+ let funding_template = self
1370+ . channel_manager
1371+ . splice_channel ( & channel_details. channel_id , & counterparty_node_id, fee_rate)
1372+ . map_err ( |e| {
1373+ log_error ! ( self . logger, "Failed to splice channel: {:?}" , e) ;
1374+ Error :: ChannelSplicingFailed
1375+ } ) ?;
1376+
1377+ // Phase 2: Build contribution with splice-out outputs
1378+ let outputs = vec ! [ bitcoin:: TxOut {
14111379 value: Amount :: from_sat( splice_amount_sats) ,
14121380 script_pubkey: address. script_pubkey( ) ,
1413- } ] ) ;
1381+ } ] ;
1382+ let ldk_wallet = LdkWallet :: new ( Arc :: clone ( & self . wallet ) , Arc :: clone ( & self . logger ) ) ;
1383+ let contribution = self
1384+ . runtime
1385+ . block_on ( funding_template. splice_out ( outputs, & ldk_wallet) )
1386+ . map_err ( |( ) | {
1387+ log_error ! ( self . logger, "Failed to splice channel: coin selection failed" ) ;
1388+ Error :: ChannelSplicingFailed
1389+ } ) ?;
14141390
1415- let fee_rate = self . fee_estimator . estimate_fee_rate ( ConfirmationTarget :: ChannelFunding ) ;
1416- let funding_feerate_per_kw: u32 = match fee_rate. to_sat_per_kwu ( ) . try_into ( ) {
1417- Ok ( fee_rate) => fee_rate,
1418- Err ( _) => {
1419- debug_assert ! ( false , "FeeRate should always fit within u32" ) ;
1420- log_error ! ( self . logger, "FeeRate should always fit within u32" ) ;
1421- fee_estimator:: get_fallback_rate_for_target ( ConfirmationTarget :: ChannelFunding )
1422- } ,
1423- } ;
1391+ // Persist wallet state after coin selection
1392+ self . wallet . persist ( ) ?;
14241393
1394+ // Phase 3: Submit contribution
14251395 self . channel_manager
1426- . splice_channel (
1396+ . funding_contributed (
14271397 & channel_details. channel_id ,
14281398 & counterparty_node_id,
14291399 contribution,
1430- funding_feerate_per_kw,
14311400 None ,
14321401 )
14331402 . map_err ( |e| {
0 commit comments