@@ -2,6 +2,7 @@ use bdk_chain::{spk_txout::SpkTxOutIndex, Indexer};
2
2
use bitcoin:: {
3
3
absolute, transaction, Amount , OutPoint , ScriptBuf , SignedAmount , Transaction , TxIn , TxOut ,
4
4
} ;
5
+ use core:: ops:: Bound ;
5
6
6
7
#[ test]
7
8
fn spk_txout_sent_and_received ( ) {
@@ -122,3 +123,194 @@ fn unmark_used_does_not_result_in_invalid_representation() {
122
123
assert ! ( !spk_index. unmark_used( & 2 ) ) ;
123
124
assert ! ( spk_index. unused_spks( ..) . collect:: <Vec <_>>( ) . is_empty( ) ) ;
124
125
}
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