@@ -13,24 +13,25 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
1313
1414use e2e_tests:: {
1515 assert_replacement, find_available_port, mine_and_sync, payment_for_tx, run_cli, run_cli_raw,
16- run_cli_with_config, setup_funded_channel, wait_for_event , wait_for_onchain_balance ,
17- wait_for_transaction, wait_for_usable_channel, wait_for_wallet_sync, LdkServerConfig ,
18- LdkServerHandle , TestBitcoind , TestConfigBuilder ,
16+ run_cli_with_config, setup_funded_channel, splice_txid , wait_for_event ,
17+ wait_for_onchain_balance , wait_for_transaction, wait_for_usable_channel, wait_for_wallet_sync,
18+ LdkServerConfig , LdkServerHandle , TestBitcoind , TestConfigBuilder ,
1919} ;
2020use hex_conservative:: { DisplayHex , FromHex } ;
2121use ldk_node:: bitcoin:: hashes:: { sha256, Hash } ;
2222use ldk_node:: lightning:: ln:: msgs:: SocketAddress ;
2323use ldk_node:: lightning:: offers:: offer:: Offer ;
2424use ldk_node:: lightning:: offers:: refund:: Refund ;
2525use ldk_node:: lightning_invoice:: Bolt11Invoice ;
26- use ldk_server_client:: error:: LdkServerErrorCode :: InvalidRequestError ;
26+ use ldk_server_client:: error:: LdkServerErrorCode :: { InvalidRequestError , LightningError } ;
2727use ldk_server_client:: ldk_server_grpc:: api:: {
2828 onchain_send_request, open_channel_request, Bolt11ClaimForIdRequest , Bolt11FailForIdRequest ,
29- Bolt11ReceiveRequest , Bolt11SendRequest , Bolt12ReceiveRequest , GetBalancesRequest ,
30- GetChannelForwardingStatsRequest , GetForwardedPaymentDetailsRequest , GetPaymentDetailsRequest ,
31- ListChannelForwardingStatsRequest , ListChannelPairForwardingStatsRequest ,
32- ListForwardedPaymentsRequest , ListPaymentsRequest , OnchainBumpFeeRequest ,
33- OnchainReceiveRequest , OnchainSendRequest , OpenChannelRequest ,
29+ Bolt11ReceiveRequest , Bolt11SendRequest , Bolt12ReceiveRequest , BumpChannelFundingFeeRequest ,
30+ GetBalancesRequest , GetChannelForwardingStatsRequest , GetForwardedPaymentDetailsRequest ,
31+ GetPaymentDetailsRequest , ListChannelForwardingStatsRequest ,
32+ ListChannelPairForwardingStatsRequest , ListChannelsRequest , ListForwardedPaymentsRequest ,
33+ ListPaymentsRequest , OnchainBumpFeeRequest , OnchainReceiveRequest , OnchainSendRequest ,
34+ OpenChannelRequest ,
3435} ;
3536use ldk_server_client:: ldk_server_grpc:: events:: event_envelope:: Event ;
3637use ldk_server_client:: ldk_server_grpc:: events:: {
@@ -567,6 +568,7 @@ async fn test_onchain_fee_bump_invalid_requests_and_ineligible_payments() {
567568 assert_eq ! ( error. error_code, InvalidRequestError ) ;
568569 assert_eq ! ( error. message, ldk_node:: NodeError :: InvalidFeeRate . to_string( ) ) ;
569570 }
571+
570572 let peer = LdkServerHandle :: start ( & bitcoind) . await ;
571573 let invoice = peer
572574 . client ( )
@@ -618,6 +620,7 @@ async fn test_onchain_fee_bump_invalid_requests_and_ineligible_payments() {
618620 . unwrap_err ( ) ;
619621 assert_eq ! ( error. error_code, InvalidRequestError ) ;
620622}
623+
621624#[ tokio:: test]
622625async fn test_cli_connect_peer ( ) {
623626 let bitcoind = TestBitcoind :: new ( ) ;
@@ -1541,6 +1544,132 @@ async fn test_cli_splice_out() {
15411544 assert ! ( address. starts_with( "bcrt1" ) , "Expected regtest address, got: {}" , address) ;
15421545}
15431546
1547+ #[ tokio:: test]
1548+ async fn test_pending_splice_fee_bump_client_cli ( ) {
1549+ let bitcoind = TestBitcoind :: new ( ) ;
1550+ let server = LdkServerHandle :: start ( & bitcoind) . await ;
1551+ let peer = LdkServerHandle :: start ( & bitcoind) . await ;
1552+ let channel = setup_funded_channel ( & bitcoind, & server, & peer, 100_000 ) . await ;
1553+ let request = BumpChannelFundingFeeRequest {
1554+ user_channel_id : channel. clone ( ) ,
1555+ counterparty_node_id : peer. node_id ( ) . into ( ) ,
1556+ } ;
1557+ let error = server. client ( ) . bump_channel_funding_fee ( request. clone ( ) ) . await . unwrap_err ( ) ;
1558+ assert_eq ! ( error. error_code, LightningError ) ;
1559+ let mut wrong_peer = request. clone ( ) ;
1560+ wrong_peer. counterparty_node_id = server. node_id ( ) . into ( ) ;
1561+ assert_eq ! (
1562+ server. client( ) . bump_channel_funding_fee( wrong_peer) . await . unwrap_err( ) . error_code,
1563+ LightningError
1564+ ) ;
1565+
1566+ let mut events = server. client ( ) . subscribe_events ( ) . await . unwrap ( ) ;
1567+ // Use the same funded channel and splice-in operation as the existing splice fixtures.
1568+ run_cli ( & server, & [ "splice-in" , & channel, peer. node_id ( ) , "50000sat" ] ) ;
1569+ let original = splice_txid ( & mut events) . await ;
1570+ let original_tx = wait_for_transaction ( & bitcoind, & original) . await ;
1571+ let funding_output = original_tx[ "vout" ]
1572+ . as_array ( )
1573+ . unwrap ( )
1574+ . iter ( )
1575+ . find ( |output| output[ "scriptPubKey" ] [ "type" ] == "witness_v0_scripthash" )
1576+ . unwrap ( ) ;
1577+ let expected_channel_value =
1578+ ldk_node:: bitcoin:: Amount :: from_btc ( funding_output[ "value" ] . as_f64 ( ) . unwrap ( ) )
1579+ . unwrap ( )
1580+ . to_sat ( ) ;
1581+ assert ! ( expected_channel_value >= 150_000 ) ;
1582+
1583+ let funding = payment_for_tx ( & server, & original) . await ;
1584+ let error = server
1585+ . client ( )
1586+ . onchain_bump_fee ( OnchainBumpFeeRequest {
1587+ payment_id : funding. payment_id ,
1588+ fee_rate_sat_per_vb : Some ( 10 ) ,
1589+ } )
1590+ . await
1591+ . unwrap_err ( ) ;
1592+ assert_eq ! ( error. error_code, InvalidRequestError ) ;
1593+
1594+ server. client ( ) . bump_channel_funding_fee ( request. clone ( ) ) . await . unwrap ( ) ;
1595+ let replacement = splice_txid ( & mut events) . await ;
1596+ assert_ne ! ( original, replacement) ;
1597+ wait_for_transaction ( & bitcoind, & replacement) . await ;
1598+ let cli = run_cli ( & server, & [ "bump-channel-funding-fee" , & channel, peer. node_id ( ) ] ) ;
1599+ assert_eq ! ( cli, json!( { } ) ) ;
1600+ let cli_txid = splice_txid ( & mut events) . await ;
1601+ assert_ne ! ( replacement, cli_txid) ;
1602+ let replacement_tx = wait_for_transaction ( & bitcoind, & cli_txid) . await ;
1603+ let replacement_output = replacement_tx[ "vout" ]
1604+ . as_array ( )
1605+ . unwrap ( )
1606+ . iter ( )
1607+ . find ( |output| output[ "scriptPubKey" ] == funding_output[ "scriptPubKey" ] )
1608+ . unwrap ( ) ;
1609+ assert_eq ! ( replacement_output[ "value" ] , funding_output[ "value" ] ) ;
1610+ let mempool: Vec < String > = bitcoind. bitcoind . client . call ( "getrawmempool" , & [ ] ) . unwrap ( ) ;
1611+ for old in [ & original, & replacement] {
1612+ assert ! ( !mempool. contains( old) ) ;
1613+ }
1614+ mine_and_sync ( & bitcoind, & [ & server, & peer] , 6 ) . await ;
1615+ tokio:: time:: timeout ( Duration :: from_secs ( 30 ) , async {
1616+ loop {
1617+ let channels = server. client ( ) . list_channels ( ListChannelsRequest { } ) . await . unwrap ( ) ;
1618+ if channels. channels . iter ( ) . any ( |c| {
1619+ c. user_channel_id == channel
1620+ && c. channel_value_sats == expected_channel_value
1621+ && c. is_usable
1622+ } ) {
1623+ break ;
1624+ }
1625+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
1626+ }
1627+ } )
1628+ . await
1629+ . expect ( "replacement splice did not confirm with the original amount" ) ;
1630+ assert_eq ! (
1631+ server. client( ) . bump_channel_funding_fee( request) . await . unwrap_err( ) . error_code,
1632+ LightningError
1633+ ) ;
1634+ }
1635+
1636+ #[ tokio:: test]
1637+ async fn test_pending_splice_fee_bump_invalid_requests ( ) {
1638+ let bitcoind = TestBitcoind :: new ( ) ;
1639+ let server = LdkServerHandle :: start ( & bitcoind) . await ;
1640+ for id in [ "" , "-1" , "xyz" , "340282366920938463463374607431768211456" ] {
1641+ let error = server
1642+ . client ( )
1643+ . bump_channel_funding_fee ( BumpChannelFundingFeeRequest {
1644+ user_channel_id : id. into ( ) ,
1645+ counterparty_node_id : server. node_id ( ) . into ( ) ,
1646+ } )
1647+ . await
1648+ . unwrap_err ( ) ;
1649+ assert_eq ! ( error. error_code, InvalidRequestError ) ;
1650+ }
1651+ for peer in [ "" , "invalid" , & "00" . repeat ( 33 ) ] {
1652+ let error = server
1653+ . client ( )
1654+ . bump_channel_funding_fee ( BumpChannelFundingFeeRequest {
1655+ user_channel_id : "1" . into ( ) ,
1656+ counterparty_node_id : peer. into ( ) ,
1657+ } )
1658+ . await
1659+ . unwrap_err ( ) ;
1660+ assert_eq ! ( error. error_code, InvalidRequestError ) ;
1661+ }
1662+ let error = server
1663+ . client ( )
1664+ . bump_channel_funding_fee ( BumpChannelFundingFeeRequest {
1665+ user_channel_id : u128:: MAX . to_string ( ) ,
1666+ counterparty_node_id : server. node_id ( ) . into ( ) ,
1667+ } )
1668+ . await
1669+ . unwrap_err ( ) ;
1670+ assert_eq ! ( error. error_code, LightningError ) ;
1671+ }
1672+
15441673#[ tokio:: test]
15451674async fn test_cli_graph_list_channels_empty ( ) {
15461675 let bitcoind = TestBitcoind :: new ( ) ;
0 commit comments