@@ -5,9 +5,15 @@ use bdk_chain::{
5
5
spk_txout:: SpkTxOutIndex ,
6
6
Balance , ConfirmationBlockTime , IndexedTxGraph , Indexer , Merge , TxGraph ,
7
7
} ;
8
+ use bdk_core:: bitcoin:: Network ;
8
9
use bdk_electrum:: BdkElectrumClient ;
9
- use bdk_testenv:: { anyhow, bitcoincore_rpc:: RpcApi , TestEnv } ;
10
+ use bdk_testenv:: {
11
+ anyhow,
12
+ bitcoincore_rpc:: { json:: CreateRawTransactionInput , RawTx , RpcApi } ,
13
+ TestEnv ,
14
+ } ;
10
15
use core:: time:: Duration ;
16
+ use electrum_client:: ElectrumApi ;
11
17
use std:: collections:: { BTreeSet , HashSet } ;
12
18
use std:: str:: FromStr ;
13
19
54
60
Ok ( update)
55
61
}
56
62
63
+ /// If an spk history contains a tx that spends another unconfirmed tx (chained mempool history),
64
+ /// the Electrum API will return the tx with a negative height. This should succeed and not panic.
65
+ #[ test]
66
+ pub fn chained_mempool_tx_sync ( ) -> anyhow:: Result < ( ) > {
67
+ let env = TestEnv :: new ( ) ?;
68
+ let rpc_client = env. rpc_client ( ) ;
69
+ let electrum_client = electrum_client:: Client :: new ( env. electrsd . electrum_url . as_str ( ) ) ?;
70
+
71
+ let tracked_addr = rpc_client
72
+ . get_new_address ( None , None ) ?
73
+ . require_network ( Network :: Regtest ) ?;
74
+
75
+ env. mine_blocks ( 100 , None ) ?;
76
+
77
+ // First unconfirmed tx.
78
+ env. send ( & tracked_addr, Amount :: from_btc ( 1.0 ) ?) ?;
79
+
80
+ // Create second unconfirmed tx that spends the first.
81
+ let utxo = rpc_client
82
+ . list_unspent ( None , Some ( 0 ) , None , Some ( true ) , None ) ?
83
+ . into_iter ( )
84
+ . find ( |utxo| utxo. script_pub_key == tracked_addr. script_pubkey ( ) )
85
+ . expect ( "must find the newly created utxo" ) ;
86
+ let tx_that_spends_unconfirmed = rpc_client. create_raw_transaction (
87
+ & [ CreateRawTransactionInput {
88
+ txid : utxo. txid ,
89
+ vout : utxo. vout ,
90
+ sequence : None ,
91
+ } ] ,
92
+ & [ (
93
+ tracked_addr. to_string ( ) ,
94
+ utxo. amount - Amount :: from_sat ( 1000 ) ,
95
+ ) ]
96
+ . into ( ) ,
97
+ None ,
98
+ None ,
99
+ ) ?;
100
+ let signed_tx = rpc_client
101
+ . sign_raw_transaction_with_wallet ( tx_that_spends_unconfirmed. raw_hex ( ) , None , None ) ?
102
+ . transaction ( ) ?;
103
+ rpc_client. send_raw_transaction ( signed_tx. raw_hex ( ) ) ?;
104
+
105
+ env. wait_until_electrum_sees_txid ( signed_tx. compute_txid ( ) , Duration :: from_secs ( 5 ) ) ?;
106
+
107
+ let spk_history = electrum_client. script_get_history ( & tracked_addr. script_pubkey ( ) ) ?;
108
+ assert ! (
109
+ spk_history. into_iter( ) . any( |tx_res| tx_res. height < 0 ) ,
110
+ "must find tx with negative height"
111
+ ) ;
112
+
113
+ let client = BdkElectrumClient :: new ( electrum_client) ;
114
+ let request = SyncRequest :: builder ( ) . spks ( core:: iter:: once ( tracked_addr. script_pubkey ( ) ) ) ;
115
+ let _response = client. sync ( request, 1 , false ) ?;
116
+
117
+ Ok ( ( ) )
118
+ }
119
+
57
120
#[ test]
58
121
pub fn test_update_tx_graph_without_keychain ( ) -> anyhow:: Result < ( ) > {
59
122
let env = TestEnv :: new ( ) ?;
0 commit comments