@@ -2,6 +2,7 @@ use bdk_chain::{spk_txout::SpkTxOutIndex, Indexer};
22use bitcoin:: {
33 absolute, transaction, Amount , OutPoint , ScriptBuf , SignedAmount , Transaction , TxIn , TxOut ,
44} ;
5+ use core:: ops:: Bound ;
56
67#[ test]
78fn spk_txout_sent_and_received ( ) {
@@ -122,3 +123,194 @@ fn unmark_used_does_not_result_in_invalid_representation() {
122123 assert ! ( !spk_index. unmark_used( & 2 ) ) ;
123124 assert ! ( spk_index. unused_spks( ..) . collect:: <Vec <_>>( ) . is_empty( ) ) ;
124125}
126+
127+ #[ test]
128+ fn outputs_in_range_excluded_bounds ( ) {
129+ let spk1 = ScriptBuf :: from_hex ( "001404f1e52ce2bab3423c6a8c63b7cd730d8f12542c" ) . unwrap ( ) ;
130+ let spk2 = ScriptBuf :: from_hex ( "00142b57404ae14f08c3a0c903feb2af7830605eb00f" ) . unwrap ( ) ;
131+ let spk3 = ScriptBuf :: from_hex ( "0014afa973f4364b2772d35f7a13ed83eb0c3330cf9c" ) . unwrap ( ) ;
132+ let spk4 = ScriptBuf :: from_hex ( "00140707d2493460cad9bb20f5f447a5a89d16d9e21c" ) . unwrap ( ) ;
133+ let spk5 = ScriptBuf :: from_hex ( "0014a10d9257489e685dda030662390dc177852faf13" ) . unwrap ( ) ;
134+
135+ let mut spk_index = SpkTxOutIndex :: default ( ) ;
136+ spk_index. insert_spk ( 1 , spk1. clone ( ) ) ;
137+ spk_index. insert_spk ( 2 , spk2. clone ( ) ) ;
138+ spk_index. insert_spk ( 3 , spk3. clone ( ) ) ;
139+ spk_index. insert_spk ( 4 , spk4. clone ( ) ) ;
140+ spk_index. insert_spk ( 5 , spk5. clone ( ) ) ;
141+
142+ let tx1 = Transaction {
143+ version : transaction:: Version :: TWO ,
144+ lock_time : absolute:: LockTime :: ZERO ,
145+ input : vec ! [ ] ,
146+ output : vec ! [ TxOut {
147+ value: Amount :: from_sat( 10_000 ) ,
148+ script_pubkey: spk1,
149+ } ] ,
150+ } ;
151+
152+ let tx2 = Transaction {
153+ version : transaction:: Version :: TWO ,
154+ lock_time : absolute:: LockTime :: ZERO ,
155+ input : vec ! [ ] ,
156+ output : vec ! [ TxOut {
157+ value: Amount :: from_sat( 20_000 ) ,
158+ script_pubkey: spk2,
159+ } ] ,
160+ } ;
161+
162+ let tx3 = Transaction {
163+ version : transaction:: Version :: TWO ,
164+ lock_time : absolute:: LockTime :: ZERO ,
165+ input : vec ! [ ] ,
166+ output : vec ! [ TxOut {
167+ value: Amount :: from_sat( 30_000 ) ,
168+ script_pubkey: spk3,
169+ } ] ,
170+ } ;
171+
172+ let tx4 = Transaction {
173+ version : transaction:: Version :: TWO ,
174+ lock_time : absolute:: LockTime :: ZERO ,
175+ input : vec ! [ ] ,
176+ output : vec ! [ TxOut {
177+ value: Amount :: from_sat( 40_000 ) ,
178+ script_pubkey: spk4,
179+ } ] ,
180+ } ;
181+
182+ let tx5 = Transaction {
183+ version : transaction:: Version :: TWO ,
184+ lock_time : absolute:: LockTime :: ZERO ,
185+ input : vec ! [ ] ,
186+ output : vec ! [ TxOut {
187+ value: Amount :: from_sat( 50_000 ) ,
188+ script_pubkey: spk5,
189+ } ] ,
190+ } ;
191+
192+ spk_index. index_tx ( & tx1) ;
193+ spk_index. index_tx ( & tx2) ;
194+ spk_index. index_tx ( & tx3) ;
195+ spk_index. index_tx ( & tx4) ;
196+ spk_index. index_tx ( & tx5) ;
197+
198+ let tx1_op = OutPoint {
199+ txid : tx1. compute_txid ( ) ,
200+ vout : 0 ,
201+ } ;
202+ let tx2_op = OutPoint {
203+ txid : tx2. compute_txid ( ) ,
204+ vout : 0 ,
205+ } ;
206+ let tx3_op = OutPoint {
207+ txid : tx3. compute_txid ( ) ,
208+ vout : 0 ,
209+ } ;
210+ let tx4_op = OutPoint {
211+ txid : tx4. compute_txid ( ) ,
212+ vout : 0 ,
213+ } ;
214+
215+ // Full range (unbounded)
216+ let all_outputs: Vec < _ > = spk_index
217+ . outputs_in_range ( ( Bound :: Unbounded :: < u32 > , Bound :: Unbounded :: < u32 > ) )
218+ . collect ( ) ;
219+ assert_eq ! ( all_outputs. len( ) , 5 ) ;
220+
221+ // Included start, included end
222+ let outputs_one_to_four: Vec < _ > = spk_index
223+ . outputs_in_range ( ( Bound :: Included ( 1u32 ) , Bound :: Included ( 4u32 ) ) )
224+ . collect ( ) ;
225+ assert_eq ! ( outputs_one_to_four. len( ) , 4 ) ;
226+ assert ! ( outputs_one_to_four
227+ . iter( )
228+ . any( |( i, op) | * * i == 1 && * op == tx1_op) ) ;
229+ assert ! ( outputs_one_to_four
230+ . iter( )
231+ . any( |( i, op) | * * i == 4 && * op == tx4_op) ) ;
232+ assert ! ( !outputs_one_to_four. iter( ) . any( |( i, _) | * * i == 5 ) ) ;
233+
234+ // Included start, Excluded end
235+ let outputs_one_to_four_excl: Vec < _ > = spk_index
236+ . outputs_in_range ( ( Bound :: Included ( 1u32 ) , Bound :: Excluded ( 4u32 ) ) )
237+ . collect ( ) ;
238+ assert_eq ! ( outputs_one_to_four_excl. len( ) , 3 ) ;
239+ assert ! ( outputs_one_to_four_excl. iter( ) . any( |( i, _) | * * i == 1 ) ) ;
240+ assert ! ( outputs_one_to_four_excl
241+ . iter( )
242+ . any( |( i, op) | * * i == 3 && * op == tx3_op) ) ;
243+ assert ! ( !outputs_one_to_four_excl. iter( ) . any( |( i, _) | * * i == 4 ) ) ;
244+
245+ // Excluded start, Included end
246+ let outputs_one_excl_to_four: Vec < _ > = spk_index
247+ . outputs_in_range ( ( Bound :: Excluded ( 1u32 ) , Bound :: Included ( 4u32 ) ) )
248+ . collect ( ) ;
249+ assert_eq ! ( outputs_one_excl_to_four. len( ) , 3 , ) ;
250+ assert ! ( !outputs_one_excl_to_four. iter( ) . any( |( i, _) | * * i == 1 ) ) ;
251+ assert ! ( outputs_one_excl_to_four
252+ . iter( )
253+ . any( |( i, op) | * * i == 2 && * op == tx2_op) ) ;
254+ assert ! ( outputs_one_excl_to_four. iter( ) . any( |( i, _) | * * i == 4 ) ) ;
255+
256+ // Excluded start, Excluded end
257+ let outputs_one_excl_to_four_excl: Vec < _ > = spk_index
258+ . outputs_in_range ( ( Bound :: Excluded ( 1u32 ) , Bound :: Excluded ( 4u32 ) ) )
259+ . collect ( ) ;
260+ assert_eq ! ( outputs_one_excl_to_four_excl. len( ) , 2 ) ;
261+ assert ! ( !outputs_one_excl_to_four_excl. iter( ) . any( |( i, _) | * * i == 1 ) ) ;
262+ assert ! ( outputs_one_excl_to_four_excl. iter( ) . any( |( i, _) | * * i == 2 ) ) ;
263+ assert ! ( outputs_one_excl_to_four_excl. iter( ) . any( |( i, _) | * * i == 3 ) ) ;
264+ assert ! ( !outputs_one_excl_to_four_excl. iter( ) . any( |( i, _) | * * i == 4 ) ) ;
265+
266+ // Unbounded start, Included end
267+ let outputs_to_three: Vec < _ > = spk_index
268+ . outputs_in_range ( ( Bound :: Unbounded :: < u32 > , Bound :: Included ( 3u32 ) ) )
269+ . collect ( ) ;
270+ assert_eq ! ( outputs_to_three. len( ) , 3 , ) ;
271+ assert ! ( outputs_to_three. iter( ) . any( |( i, _) | * * i == 1 ) ) ;
272+ assert ! ( outputs_to_three. iter( ) . any( |( i, _) | * * i == 3 ) ) ;
273+ assert ! ( !outputs_to_three. iter( ) . any( |( i, _) | * * i == 4 ) ) ;
274+
275+ // Unbounded start, excluded end
276+ let outputs_to_three_excl: Vec < _ > = spk_index
277+ . outputs_in_range ( ( Bound :: Unbounded :: < u32 > , Bound :: Excluded ( 3u32 ) ) )
278+ . collect ( ) ;
279+ assert_eq ! ( outputs_to_three_excl. len( ) , 2 , ) ;
280+ assert ! ( outputs_to_three_excl. iter( ) . any( |( i, _) | * * i == 1 ) ) ;
281+ assert ! ( outputs_to_three_excl. iter( ) . any( |( i, _) | * * i == 2 ) ) ;
282+ assert ! ( !outputs_to_three_excl. iter( ) . any( |( i, _) | * * i == 3 ) , ) ;
283+
284+ // Included start, Unbounded end
285+ let outputs_to_three: Vec < _ > = spk_index
286+ . outputs_in_range ( ( Bound :: Included ( 3u32 ) , Bound :: Unbounded :: < u32 > ) )
287+ . collect ( ) ;
288+ assert_eq ! ( outputs_to_three. len( ) , 3 , ) ;
289+ assert ! ( outputs_to_three. iter( ) . any( |( i, _) | * * i == 3 ) ) ;
290+ assert ! ( outputs_to_three. iter( ) . any( |( i, _) | * * i == 5 ) , ) ;
291+ assert ! ( !outputs_to_three. iter( ) . any( |( i, _) | * * i == 2 ) , ) ;
292+
293+ // Excluded start, Unbounded end
294+ let outputs_to_three_excl: Vec < _ > = spk_index
295+ . outputs_in_range ( ( Bound :: Excluded ( 3u32 ) , Bound :: Unbounded :: < u32 > ) )
296+ . collect ( ) ;
297+ assert_eq ! ( outputs_to_three_excl. len( ) , 2 , ) ;
298+ assert ! ( !outputs_to_three_excl. iter( ) . any( |( i, _) | * * i == 3 ) ) ;
299+ assert ! ( outputs_to_three_excl. iter( ) . any( |( i, _) | * * i == 5 ) , ) ;
300+ assert ! ( outputs_to_three_excl. iter( ) . any( |( i, _) | * * i == 4 ) ) ;
301+
302+ // Single element range
303+ let output_at_three: Vec < _ > = spk_index
304+ . outputs_in_range ( ( Bound :: Included ( 3u32 ) , Bound :: Included ( 3u32 ) ) )
305+ . collect ( ) ;
306+ assert_eq ! ( output_at_three. len( ) , 1 , ) ;
307+ assert ! ( output_at_three. iter( ) . any( |( i, _) | * * i == 3 ) ) ;
308+ assert ! ( !output_at_three. iter( ) . any( |( i, _) | * * i == 4 ) ) ;
309+ assert ! ( !output_at_three. iter( ) . any( |( i, _) | * * i == 2 ) ) ;
310+
311+ // Empty range with excluded bound
312+ let outputs_empty: Vec < _ > = spk_index
313+ . outputs_in_range ( ( Bound :: Included ( 3u32 ) , Bound :: Excluded ( 3u32 ) ) )
314+ . collect ( ) ;
315+ assert_eq ! ( outputs_empty. len( ) , 0 ) ;
316+ }
0 commit comments