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