11// #![allow(unused)]
22use bdk_kyoto:: { Idle , Single } ;
3+ use bdk_wallet:: chain:: { DescriptorExt , DescriptorId } ;
4+ use std:: collections:: BTreeMap ;
35use std:: net:: IpAddr ;
46use std:: path:: PathBuf ;
57use std:: time:: Duration ;
@@ -17,6 +19,8 @@ use bdk_wallet::Update;
1719
1820const EXTERNAL_DESCRIPTOR : & str = "tr([7d94197e/86'/1'/0']tpubDCyQVJj8KzjiQsFjmb3KwECVXPvMwvAxxZGCP9XmWSopmjW3bCV3wD7TgxrUhiGSueDS1MU5X1Vb1YjYcp8jitXc5fXfdC1z68hDDEyKRNr/0/*)" ;
1921const INTERNAL_DESCRIPTOR : & str = "tr([7d94197e/86'/1'/0']tpubDCyQVJj8KzjiQsFjmb3KwECVXPvMwvAxxZGCP9XmWSopmjW3bCV3wD7TgxrUhiGSueDS1MU5X1Vb1YjYcp8jitXc5fXfdC1z68hDDEyKRNr/1/*)" ;
22+ const RECV_TWO : & str = "wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/0/*)" ;
23+ const CHANGE_TWO : & str = "wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/1/*)" ;
2024
2125fn testenv ( ) -> anyhow:: Result < TestEnv > {
2226 use bdk_testenv:: Config ;
@@ -239,3 +243,92 @@ async fn update_handles_dormant_wallet() -> anyhow::Result<()> {
239243
240244 Ok ( ( ) )
241245}
246+
247+ #[ tokio:: test]
248+ async fn two_wallets_can_update ( ) -> anyhow:: Result < ( ) > {
249+ let env = testenv ( ) ?;
250+
251+ let mut wallet = CreateParams :: new ( EXTERNAL_DESCRIPTOR , INTERNAL_DESCRIPTOR )
252+ . network ( Network :: Regtest )
253+ . create_wallet_no_persist ( ) ?;
254+ let addr = wallet. peek_address ( KeychainKind :: External , 0 ) . address ;
255+
256+ let tempdir = tempfile:: tempdir ( ) ?. path ( ) . join ( "kyoto-data" ) ;
257+ let client = init_node ( & env, & wallet, tempdir. clone ( ) ) ?;
258+ let ( client, _, mut update_subscriber) = client. subscribe ( ) ;
259+ let client = client. start ( ) ;
260+ let requester = client. requester ( ) ;
261+
262+ // mine blocks
263+ let miner = env
264+ . rpc_client ( )
265+ . get_new_address ( None , None ) ?
266+ . assume_checked ( ) ;
267+ let _hashes = env. mine_blocks ( 100 , Some ( miner. clone ( ) ) ) ?;
268+ wait_for_height ( & env, 101 ) . await ?;
269+
270+ // send tx
271+ let amt = Amount :: from_btc ( 0.21 ) ?;
272+ let txid = env. send ( & addr, amt) ?;
273+ let hashes = env. mine_blocks ( 1 , Some ( miner. clone ( ) ) ) ?;
274+ let blockhash = hashes[ 0 ] ;
275+ wait_for_height ( & env, 102 ) . await ?;
276+
277+ // get update
278+ let res = update_subscriber. update ( ) . await ?;
279+ let ( anchor, anchor_txid) = * res. tx_update . anchors . iter ( ) . next ( ) . unwrap ( ) ;
280+ assert_eq ! ( anchor. block_id. hash, blockhash) ;
281+ assert_eq ! ( anchor_txid, txid) ;
282+ wallet. apply_update ( res) . unwrap ( ) ;
283+
284+ // shut down then reorg
285+ requester. shutdown ( ) ?;
286+
287+ let hashes = env. reorg ( 1 ) ?; // 102
288+ let new_blockhash = hashes[ 0 ] ;
289+ _ = env. mine_blocks ( 20 , Some ( miner) ) ?; // 122
290+ wait_for_height ( & env, 122 ) . await ?;
291+
292+ // add a new wallet to the sync request
293+ let wallet_two = CreateParams :: new ( RECV_TWO , CHANGE_TWO )
294+ . network ( Network :: Regtest )
295+ . create_wallet_no_persist ( ) ?;
296+ let peer = env. bitcoind . params . p2p_socket . unwrap ( ) ;
297+ let ip: IpAddr = ( * peer. ip ( ) ) . into ( ) ;
298+ let port = peer. port ( ) ;
299+ let mut peer = TrustedPeer :: from_ip ( ip) ;
300+ peer. port = Some ( port) ;
301+ let client = Builder :: new ( Network :: Regtest )
302+ . add_peer ( peer)
303+ . data_dir ( tempdir)
304+ . required_peers ( 1 )
305+ . build_with_wallets ( vec ! [
306+ ( & wallet, ScanType :: Sync ) ,
307+ ( & wallet_two, ScanType :: Sync ) ,
308+ ] ) ?;
309+ let ( client, _, mut update_subscriber) = client. subscribe ( ) ;
310+ let client = client. start ( ) ;
311+ let requester = client. requester ( ) ;
312+
313+ // expect tx to confirm at same height but different blockhash
314+ let results = update_subscriber. updates ( ) . await ?;
315+ let res = results
316+ . collect :: < BTreeMap < DescriptorId , Update > > ( )
317+ . get (
318+ & wallet
319+ . public_descriptor ( KeychainKind :: External )
320+ . descriptor_id ( ) ,
321+ )
322+ . unwrap ( )
323+ . clone ( ) ;
324+ let ( anchor, anchor_txid) = * res. tx_update . anchors . iter ( ) . next ( ) . unwrap ( ) ;
325+ assert_eq ! ( anchor_txid, txid) ;
326+ assert_eq ! ( anchor. block_id. height, 102 ) ;
327+ assert_ne ! ( anchor. block_id. hash, blockhash) ;
328+ assert_eq ! ( anchor. block_id. hash, new_blockhash) ;
329+ wallet. apply_update ( res) . unwrap ( ) ;
330+
331+ requester. shutdown ( ) ?;
332+
333+ Ok ( ( ) )
334+ }
0 commit comments