@@ -11,9 +11,10 @@ use std::io::{BufRead, BufReader, Write};
1111use std:: net:: TcpListener ;
1212use std:: path:: { Path , PathBuf } ;
1313use std:: process:: { Child , Command , Stdio } ;
14- use std:: time:: { Duration , Instant } ;
14+ use std:: time:: { Duration , Instant , SystemTime , UNIX_EPOCH } ;
1515
1616use corepc_node:: Node ;
17+ use ldk_node:: bitcoin:: Amount ;
1718use ldk_server_client:: client:: { EventStream , LdkServerClient } ;
1819use ldk_server_client:: error:: LdkServerErrorCode ;
1920use ldk_server_client:: ldk_server_grpc:: api:: { GetNodeInfoRequest , GetNodeInfoResponse } ;
@@ -30,7 +31,7 @@ use ldk_server_grpc::types::{
3031 ClaimableAwaitingConfirmations , ForwardedPayment , LightningBalance , Payment , PaymentDirection ,
3132 PaymentStatus ,
3233} ;
33- use serde_json:: Value ;
34+ use serde_json:: { json , Value } ;
3435
3536const EVENT_TIMEOUT : Duration = Duration :: from_secs ( 15 ) ;
3637
@@ -58,6 +59,8 @@ impl TestBitcoind {
5859
5960 fn with_extra_args ( extra_args : & [ & str ] ) -> Self {
6061 let mut conf = corepc_node:: Conf :: default ( ) ;
62+ // Match the pinned LDK Node splice fixtures' 0.1 sat/vB relay fee increase.
63+ conf. args . push ( "-incrementalrelayfee=0.00000100" ) ;
6164 conf. args . extend_from_slice ( extra_args) ;
6265
6366 let bitcoind = match std:: env:: var ( "BITCOIND_EXE" ) {
@@ -585,6 +588,17 @@ pub async fn wait_for_event(
585588 . expect ( "Timed out waiting for event" )
586589}
587590
591+ /// Wait for a negotiated splice and return its funding transaction ID.
592+ pub async fn splice_txid ( events : & mut EventStream ) -> String {
593+ let event = wait_for_event ( events, |e| matches ! ( e, Event :: SpliceNegotiated ( _) ) ) . await ;
594+ match event. event . unwrap ( ) {
595+ Event :: SpliceNegotiated ( splice) => {
596+ splice. new_funding_txo . split ( ':' ) . next ( ) . unwrap ( ) . to_string ( )
597+ } ,
598+ _ => unreachable ! ( ) ,
599+ }
600+ }
601+
588602/// Poll get_node_info until the server responds successfully.
589603async fn wait_for_server_ready ( handle : & LdkServerHandle , timeout : Duration ) -> GetNodeInfoResponse {
590604 let start = std:: time:: Instant :: now ( ) ;
@@ -772,6 +786,81 @@ pub async fn mine_and_sync(
772786 }
773787}
774788
789+ /// Wait for a transaction to enter the mempool and return its decoded details.
790+ pub async fn wait_for_transaction ( bitcoind : & TestBitcoind , txid : & str ) -> Value {
791+ tokio:: time:: timeout ( Duration :: from_secs ( 30 ) , async {
792+ loop {
793+ let mempool: Vec < String > = bitcoind. bitcoind . client . call ( "getrawmempool" , & [ ] ) . unwrap ( ) ;
794+ if mempool. iter ( ) . any ( |id| id == txid) {
795+ return bitcoind
796+ . bitcoind
797+ . client
798+ . call ( "getrawtransaction" , & [ json ! ( txid) , json ! ( true ) ] )
799+ . unwrap ( ) ;
800+ }
801+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
802+ }
803+ } )
804+ . await
805+ . expect ( "transaction did not enter the mempool" )
806+ }
807+
808+ /// Wait for the on-chain wallet to complete another sync.
809+ ///
810+ /// The pinned wallet records a replacement before its background sync sees the transaction.
811+ pub async fn wait_for_wallet_sync ( server : & LdkServerHandle ) {
812+ let after = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . unwrap ( ) . as_secs ( ) ;
813+ tokio:: time:: timeout ( Duration :: from_secs ( 30 ) , async {
814+ loop {
815+ let info = server. client ( ) . get_node_info ( GetNodeInfoRequest { } ) . await . unwrap ( ) ;
816+ if info. latest_onchain_wallet_sync_timestamp . is_some_and ( |timestamp| timestamp > after)
817+ {
818+ break ;
819+ }
820+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
821+ }
822+ } )
823+ . await
824+ . expect ( "wallet did not sync after the replacement" ) ;
825+ }
826+
827+ /// Wait for a transaction to appear in the node's payment history.
828+ pub async fn payment_for_tx ( server : & LdkServerHandle , txid : & str ) -> Payment {
829+ tokio:: time:: timeout ( Duration :: from_secs ( 30 ) , async {
830+ loop {
831+ for payment in list_payments ( server) . await {
832+ if let Some ( payment_kind:: Kind :: Onchain ( onchain) ) =
833+ payment. kind . as_ref ( ) . and_then ( |kind| kind. kind . as_ref ( ) )
834+ {
835+ if onchain. txid == txid {
836+ return payment;
837+ }
838+ }
839+ }
840+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
841+ }
842+ } )
843+ . await
844+ . expect ( "payment was not recorded" )
845+ }
846+
847+ /// Check that a replacement preserves the recipient amount.
848+ pub async fn assert_replacement (
849+ bitcoind : & TestBitcoind , old : & str , new : & str , address : & str , amount : Amount ,
850+ ) {
851+ assert_ne ! ( old, new) ;
852+ let tx = wait_for_transaction ( bitcoind, new) . await ;
853+ let recipient = tx[ "vout" ]
854+ . as_array ( )
855+ . unwrap ( )
856+ . iter ( )
857+ . find ( |output| output[ "scriptPubKey" ] [ "address" ] == address)
858+ . unwrap ( ) ;
859+ assert_eq ! ( Amount :: from_btc( recipient[ "value" ] . as_f64( ) . unwrap( ) ) . unwrap( ) , amount) ;
860+ let mempool: Vec < String > = bitcoind. bitcoind . client . call ( "getrawmempool" , & [ ] ) . unwrap ( ) ;
861+ assert ! ( !mempool. iter( ) . any( |id| id == old) ) ;
862+ }
863+
775864/// Wait until the given client has at least one usable channel,
776865/// periodically mining blocks to trigger chain sync.
777866pub async fn wait_for_usable_channel (
0 commit comments