@@ -3,6 +3,7 @@ use bitcoin::{constants, Address, Amount, Network, ScriptBuf};
3
3
use bdk_bitcoind_rpc:: bip158:: { Event , FilterIter } ;
4
4
use bdk_core:: { BlockId , CheckPoint } ;
5
5
use bdk_testenv:: { anyhow, bitcoind, block_id, TestEnv } ;
6
+ use bitcoin:: secp256k1:: rand;
6
7
use bitcoincore_rpc:: RpcApi ;
7
8
8
9
fn testenv ( ) -> anyhow:: Result < TestEnv > {
@@ -169,34 +170,44 @@ fn test_reorg_handling() -> anyhow::Result<()> {
169
170
let env = testenv ( ) ?;
170
171
let rpc = env. rpc_client ( ) ;
171
172
172
- // Make sure we have a chain with sufficient height
173
+ let secp = bitcoin:: secp256k1:: Secp256k1 :: new ( ) ;
174
+
175
+ // Generate compressed key pair
176
+ let ( sk, _) = secp. generate_keypair ( & mut rand:: thread_rng ( ) ) ;
177
+ let secp_pubkey = bitcoin:: secp256k1:: PublicKey :: from_secret_key ( & secp, & sk) ;
178
+ let pubkey = bitcoin:: PublicKey :: new ( secp_pubkey) ;
179
+
180
+ // Get wpkh (will be compressed since from_secret_key creates compressed keys)
181
+ let wpkh = pubkey
182
+ . wpubkey_hash ( )
183
+ . expect ( "Public key should be compressed for wpkh" ) ;
184
+
185
+ let spk = ScriptBuf :: new_p2wpkh ( & wpkh) ;
186
+
187
+ // Mine initial chain up to height 99
173
188
while rpc. get_block_count ( ) ? < 99 {
174
189
env. mine_blocks ( 1 , None ) ?;
175
190
}
176
191
177
- // Mine initial chain: 100:A, 101:B
192
+ // Mine initial blocks 100:A, 101:B
178
193
let block_a_hash = env. mine_blocks ( 1 , None ) ?[ 0 ] ;
179
194
let _block_b_hash = env. mine_blocks ( 1 , None ) ?[ 0 ] ;
180
195
181
- // Create SPK to test with
182
- let dummy_spk = ScriptBuf :: new ( ) ;
183
-
196
+ // Create FilterIter starting at height 100
184
197
let mut iter = FilterIter :: new_with_height ( rpc, 100 ) ;
185
- iter. add_spks ( vec ! [ dummy_spk . clone( ) ] ) ;
198
+ iter. add_spk ( spk . clone ( ) ) ;
186
199
187
- // Process block 100:A
200
+ // Process block 100:A (NoMatch)
188
201
assert ! ( matches!(
189
202
iter. next( ) . transpose( ) ?,
190
203
Some ( Event :: NoMatch ( 100 ) )
191
204
) ) ;
192
205
193
- // Reorg to 100:A', 101:B'
194
- // 1. Invalidate existing blocks
206
+ // Reorg: Invalidate A, mine new chain A'->B' with a matching transaction
195
207
rpc. invalidate_block ( & block_a_hash) ?;
196
208
197
- // 2. Mine new chain with transaction matching our SPK
198
- // Create a transaction that matches our dummy SPK for block A'
199
- let address = Address :: from_script ( & dummy_spk, Network :: Regtest ) ?;
209
+ // Create transaction matching our SPK
210
+ let address = Address :: from_script ( & spk, Network :: Regtest ) ?;
200
211
rpc. send_to_address (
201
212
& address,
202
213
Amount :: from_sat ( 1000 ) ,
@@ -208,24 +219,27 @@ fn test_reorg_handling() -> anyhow::Result<()> {
208
219
None ,
209
220
) ?;
210
221
211
- // Mine new blocks
222
+ // Mine new blocks 100:A', 101:B'
212
223
let block_a_prime = env. mine_blocks ( 1 , None ) ?[ 0 ] ;
213
224
let _block_b_prime = env. mine_blocks ( 1 , None ) ?[ 0 ] ;
214
225
215
- // Process new blocks - should detect reorg and match the transaction
226
+ // Process reorged blocks
216
227
match iter. next ( ) . transpose ( ) ? {
217
228
Some ( Event :: Block ( inner) ) => {
218
229
assert_eq ! ( inner. height, 100 ) ;
219
230
assert_eq ! ( inner. block. block_hash( ) , block_a_prime) ;
231
+ // Verify transaction exists
232
+ assert ! ( inner
233
+ . block
234
+ . txdata
235
+ . iter( )
236
+ . any( |tx| tx. output. iter( ) . any( |o| o. script_pubkey == spk) ) ) ;
220
237
}
221
- other => panic ! ( "Expected block 100:A' , got {:?}" , other) ,
238
+ other => panic ! ( "Expected Block( 100) , got {:?}" , other) ,
222
239
}
223
240
224
- // The second block should be a NoMatch since we don't have a matching transaction
225
241
match iter. next ( ) . transpose ( ) ? {
226
- Some ( Event :: NoMatch ( 101 ) ) => { /* Expected */ }
242
+ Some ( Event :: NoMatch ( 101 ) ) => Ok ( ( ) ) ,
227
243
other => panic ! ( "Expected NoMatch(101), got {:?}" , other) ,
228
244
}
229
-
230
- Ok ( ( ) )
231
245
}
0 commit comments