@@ -1306,6 +1306,18 @@ async fn splice_channel() {
13061306 let payment =
13071307 payments. into_iter ( ) . find ( |p| p. id == PaymentId ( txo. txid . to_byte_array ( ) ) ) . unwrap ( ) ;
13081308 assert_eq ! ( payment. fee_paid_msat, Some ( expected_splice_out_fee_sat * 1_000 ) ) ;
1309+ // The splice-out graduated to a confirmed interactive-funding payment. Its `direction` is left
1310+ // unasserted on purpose: the destination is our own address, so it is a self-transfer (channel
1311+ // balance -> on-chain wallet) whose inbound/outbound sense is ambiguous.
1312+ assert_eq ! ( payment. status, PaymentStatus :: Succeeded ) ;
1313+ assert ! ( matches!(
1314+ payment. kind,
1315+ PaymentKind :: Onchain {
1316+ status: ConfirmationStatus :: Confirmed { .. } ,
1317+ tx_type: Some ( TransactionType :: InteractiveFunding { .. } ) ,
1318+ ..
1319+ }
1320+ ) ) ;
13091321
13101322 assert_eq ! (
13111323 node_a. list_balances( ) . total_onchain_balance_sats,
@@ -1601,6 +1613,80 @@ async fn funding_payment_graduates_without_channel_ready() {
16011613 node_b. stop ( ) . unwrap ( ) ;
16021614}
16031615
1616+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
1617+ async fn splice_payment_reorged_to_unconfirmed ( ) {
1618+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
1619+ let chain_source = random_chain_source ( & bitcoind, & electrsd) ;
1620+ let ( node_a, node_b) = setup_two_nodes ( & chain_source, false , true , false ) ;
1621+
1622+ let address_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
1623+ let address_b = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
1624+ let premine_amount_sat = 5_000_000 ;
1625+ premine_and_distribute_funds (
1626+ & bitcoind. client ,
1627+ & electrsd. client ,
1628+ vec ! [ address_a, address_b] ,
1629+ Amount :: from_sat ( premine_amount_sat) ,
1630+ )
1631+ . await ;
1632+
1633+ node_a. sync_wallets ( ) . unwrap ( ) ;
1634+ node_b. sync_wallets ( ) . unwrap ( ) ;
1635+
1636+ open_channel ( & node_a, & node_b, 4_000_000 , false , & electrsd) . await ;
1637+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
1638+ node_a. sync_wallets ( ) . unwrap ( ) ;
1639+ node_b. sync_wallets ( ) . unwrap ( ) ;
1640+
1641+ let _user_channel_id_a = expect_channel_ready_event ! ( node_a, node_b. node_id( ) ) ;
1642+ let user_channel_id_b = expect_channel_ready_event ! ( node_b, node_a. node_id( ) ) ;
1643+
1644+ // node_b splices in, recording a funding payment it contributed to.
1645+ node_b. splice_in ( & user_channel_id_b, node_a. node_id ( ) , 1_000_000 ) . unwrap ( ) ;
1646+ let splice_txo = expect_splice_negotiated_event ! ( node_a, node_b. node_id( ) ) ;
1647+ expect_splice_negotiated_event ! ( node_b, node_a. node_id( ) ) ;
1648+ wait_for_tx ( & electrsd. client , splice_txo. txid ) . await ;
1649+
1650+ // Confirm the splice with a single block — confirmed, but short of `ANTI_REORG_DELAY`, so the
1651+ // payment is `Confirmed`/`Pending` rather than graduated.
1652+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
1653+ node_b. sync_wallets ( ) . unwrap ( ) ;
1654+
1655+ let payment_id = PaymentId ( splice_txo. txid . to_byte_array ( ) ) ;
1656+ let payment = node_b. payment ( & payment_id) . expect ( "splice payment exists" ) ;
1657+ assert_eq ! ( payment. status, PaymentStatus :: Pending ) ;
1658+ assert ! ( matches!(
1659+ payment. kind,
1660+ PaymentKind :: Onchain { status: ConfirmationStatus :: Confirmed { .. } , .. }
1661+ ) ) ;
1662+
1663+ // Reorg the splice transaction out by replacing its block with a longer, transaction-free chain.
1664+ let original_height =
1665+ bitcoind. client . get_blockchain_info ( ) . expect ( "failed to get blockchain info" ) . blocks ;
1666+ invalidate_blocks ( & bitcoind. client , 1 ) ;
1667+ let replacement_address = bitcoind. client . new_address ( ) . expect ( "failed to get new address" ) ;
1668+ for _ in 0 ..2 {
1669+ let _res: serde_json:: Value = bitcoind
1670+ . client
1671+ . call ( "generateblock" , & [ json ! ( replacement_address. to_string( ) ) , json ! ( [ ] ) ] )
1672+ . expect ( "failed to generate empty block" ) ;
1673+ }
1674+ wait_for_block ( & electrsd. client , original_height as usize + 1 ) . await ;
1675+ node_b. sync_wallets ( ) . unwrap ( ) ;
1676+
1677+ // The funding payment returns to `Unconfirmed` and stays `Pending`, exercising the
1678+ // `TxUnconfirmed` arm for a funding payment.
1679+ let payment = node_b. payment ( & payment_id) . expect ( "splice payment still exists" ) ;
1680+ assert_eq ! ( payment. status, PaymentStatus :: Pending ) ;
1681+ assert ! ( matches!(
1682+ payment. kind,
1683+ PaymentKind :: Onchain { status: ConfirmationStatus :: Unconfirmed , .. }
1684+ ) ) ;
1685+
1686+ node_a. stop ( ) . unwrap ( ) ;
1687+ node_b. stop ( ) . unwrap ( ) ;
1688+ }
1689+
16041690#[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
16051691async fn simple_bolt12_send_receive ( ) {
16061692 let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
0 commit comments