@@ -3,6 +3,7 @@ use electrsd::bitcoind::bitcoincore_rpc::RpcApi;
33use electrsd:: bitcoind:: { self , anyhow, BitcoinD } ;
44use electrsd:: { Conf , ElectrsD } ;
55use esplora_client:: { self , BlockingClient , Builder } ;
6+ use std:: collections:: { BTreeMap , HashSet } ;
67use std:: str:: FromStr ;
78use std:: thread:: sleep;
89use std:: time:: Duration ;
@@ -110,5 +111,118 @@ pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
110111 let mut expected_txids = vec ! [ txid1, txid2] ;
111112 expected_txids. sort ( ) ;
112113 assert_eq ! ( graph_update_txids, expected_txids) ;
114+
115+ Ok ( ( ) )
116+ }
117+
118+ /// Test the bounds of the address scan depending on the gap limit.
119+ #[ test]
120+ pub fn test_update_tx_graph_gap_limit ( ) -> anyhow:: Result < ( ) > {
121+ let env = TestEnv :: new ( ) ?;
122+ let _block_hashes = env. mine_blocks ( 101 , None ) ?;
123+
124+ // Now let's test the gap limit. First of all get a chain of 10 addresses.
125+ let addresses = [
126+ "bcrt1qj9f7r8r3p2y0sqf4r3r62qysmkuh0fzep473d2ar7rcz64wqvhssjgf0z4" ,
127+ "bcrt1qmm5t0ch7vh2hryx9ctq3mswexcugqe4atkpkl2tetm8merqkthas3w7q30" ,
128+ "bcrt1qut9p7ej7l7lhyvekj28xknn8gnugtym4d5qvnp5shrsr4nksmfqsmyn87g" ,
129+ "bcrt1qqz0xtn3m235p2k96f5wa2dqukg6shxn9n3txe8arlrhjh5p744hsd957ww" ,
130+ "bcrt1q9c0t62a8l6wfytmf2t9lfj35avadk3mm8g4p3l84tp6rl66m48sqrme7wu" ,
131+ "bcrt1qkmh8yrk2v47cklt8dytk8f3ammcwa4q7dzattedzfhqzvfwwgyzsg59zrh" ,
132+ "bcrt1qvgrsrzy07gjkkfr5luplt0azxtfwmwq5t62gum5jr7zwcvep2acs8hhnp2" ,
133+ "bcrt1qw57edarcg50ansq8mk3guyrk78rk0fwvrds5xvqeupteu848zayq549av8" ,
134+ "bcrt1qvtve5ekf6e5kzs68knvnt2phfw6a0yjqrlgat392m6zt9jsvyxhqfx67ef" ,
135+ "bcrt1qw03ddumfs9z0kcu76ln7jrjfdwam20qtffmkcral3qtza90sp9kqm787uk" ,
136+ ] ;
137+ let addresses: Vec < _ > = addresses
138+ . into_iter ( )
139+ . map ( |s| Address :: from_str ( s) . unwrap ( ) . assume_checked ( ) )
140+ . collect ( ) ;
141+ let spks: Vec < _ > = addresses
142+ . iter ( )
143+ . enumerate ( )
144+ . map ( |( i, addr) | ( i as u32 , addr. script_pubkey ( ) ) )
145+ . collect ( ) ;
146+ let mut keychains = BTreeMap :: new ( ) ;
147+ keychains. insert ( 0 , spks) ;
148+
149+ // Then receive coins on the 4th address.
150+ let txid_4th_addr = env. bitcoind . client . send_to_address (
151+ & addresses[ 3 ] ,
152+ Amount :: from_sat ( 10000 ) ,
153+ None ,
154+ None ,
155+ None ,
156+ None ,
157+ Some ( 1 ) ,
158+ None ,
159+ ) ?;
160+ let _block_hashes = env. mine_blocks ( 1 , None ) ?;
161+ while env. client . get_height ( ) . unwrap ( ) < 103 {
162+ sleep ( Duration :: from_millis ( 10 ) )
163+ }
164+
165+ // A scan with a gap limit of 1 won't find the transaction, but a scan with a gap limit of 2
166+ // will.
167+ let ( graph_update, active_indices) = env. client . scan_txs_with_keychains (
168+ keychains. clone ( ) ,
169+ vec ! [ ] . into_iter ( ) ,
170+ vec ! [ ] . into_iter ( ) ,
171+ 1 ,
172+ 1 ,
173+ ) ?;
174+ assert ! ( graph_update. full_txs( ) . next( ) . is_none( ) ) ;
175+ assert ! ( active_indices. is_empty( ) ) ;
176+ let ( graph_update, active_indices) = env. client . scan_txs_with_keychains (
177+ keychains. clone ( ) ,
178+ vec ! [ ] . into_iter ( ) ,
179+ vec ! [ ] . into_iter ( ) ,
180+ 2 ,
181+ 1 ,
182+ ) ?;
183+ assert_eq ! ( graph_update. full_txs( ) . next( ) . unwrap( ) . txid, txid_4th_addr) ;
184+ assert_eq ! ( active_indices[ & 0 ] , 3 ) ;
185+
186+ // Now receive a coin on the last address.
187+ let txid_last_addr = env. bitcoind . client . send_to_address (
188+ & addresses[ addresses. len ( ) - 1 ] ,
189+ Amount :: from_sat ( 10000 ) ,
190+ None ,
191+ None ,
192+ None ,
193+ None ,
194+ Some ( 1 ) ,
195+ None ,
196+ ) ?;
197+ let _block_hashes = env. mine_blocks ( 1 , None ) ?;
198+ while env. client . get_height ( ) . unwrap ( ) < 104 {
199+ sleep ( Duration :: from_millis ( 10 ) )
200+ }
201+
202+ // A scan with gap limit 4 won't find the second transaction, but a scan with gap limit 5 will.
203+ // The last active indice won't be updated in the first case but will in the second one.
204+ let ( graph_update, active_indices) = env. client . scan_txs_with_keychains (
205+ keychains. clone ( ) ,
206+ vec ! [ ] . into_iter ( ) ,
207+ vec ! [ ] . into_iter ( ) ,
208+ 4 ,
209+ 1 ,
210+ ) ?;
211+ let txs: HashSet < _ > = graph_update. full_txs ( ) . map ( |tx| tx. txid ) . collect ( ) ;
212+ assert_eq ! ( txs. len( ) , 1 ) ;
213+ assert ! ( txs. contains( & txid_4th_addr) ) ;
214+ assert_eq ! ( active_indices[ & 0 ] , 3 ) ;
215+ let ( graph_update, active_indices) = env. client . scan_txs_with_keychains (
216+ keychains,
217+ vec ! [ ] . into_iter ( ) ,
218+ vec ! [ ] . into_iter ( ) ,
219+ 5 ,
220+ 1 ,
221+ ) ?;
222+ let txs: HashSet < _ > = graph_update. full_txs ( ) . map ( |tx| tx. txid ) . collect ( ) ;
223+ assert_eq ! ( txs. len( ) , 2 ) ;
224+ assert ! ( txs. contains( & txid_4th_addr) && txs. contains( & txid_last_addr) ) ;
225+ assert_eq ! ( active_indices[ & 0 ] , 9 ) ;
226+
113227 Ok ( ( ) )
114228}
0 commit comments