@@ -3,11 +3,20 @@ use crate::Config;
3
3
use lightning:: util:: persist:: KVStorePersister ;
4
4
use lightning:: util:: ser:: Writeable ;
5
5
6
+ use bitcoin:: { Address , Amount , OutPoint , Txid } ;
7
+
8
+ use bitcoind:: bitcoincore_rpc:: RpcApi ;
9
+ use electrsd:: bitcoind:: bitcoincore_rpc:: bitcoincore_rpc_json:: AddressType ;
10
+ use electrsd:: { bitcoind, bitcoind:: BitcoinD , ElectrsD } ;
11
+ use electrum_client:: ElectrumApi ;
12
+
6
13
use rand:: distributions:: Alphanumeric ;
7
14
use rand:: { thread_rng, Rng } ;
8
15
use std:: collections:: HashMap ;
16
+ use std:: env;
9
17
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
10
18
use std:: sync:: Mutex ;
19
+ use std:: time:: Duration ;
11
20
12
21
macro_rules! expect_event {
13
22
( $node: expr, $event_type: ident) => { {
@@ -94,3 +103,125 @@ pub fn random_config(esplora_url: &str) -> Config {
94
103
95
104
config
96
105
}
106
+
107
+ pub fn setup_bitcoind_and_electrsd ( ) -> ( BitcoinD , ElectrsD ) {
108
+ let bitcoind_exe =
109
+ env:: var ( "BITCOIND_EXE" ) . ok ( ) . or_else ( || bitcoind:: downloaded_exe_path ( ) . ok ( ) ) . expect (
110
+ "you need to provide an env var BITCOIND_EXE or specify a bitcoind version feature" ,
111
+ ) ;
112
+ let mut bitcoind_conf = bitcoind:: Conf :: default ( ) ;
113
+ bitcoind_conf. network = "regtest" ;
114
+ let bitcoind = BitcoinD :: with_conf ( bitcoind_exe, & bitcoind_conf) . unwrap ( ) ;
115
+
116
+ let electrs_exe = env:: var ( "ELECTRS_EXE" )
117
+ . ok ( )
118
+ . or_else ( electrsd:: downloaded_exe_path)
119
+ . expect ( "you need to provide env var ELECTRS_EXE or specify an electrsd version feature" ) ;
120
+ let mut electrsd_conf = electrsd:: Conf :: default ( ) ;
121
+ electrsd_conf. http_enabled = true ;
122
+ electrsd_conf. network = "regtest" ;
123
+ let electrsd = ElectrsD :: with_conf ( electrs_exe, & bitcoind, & electrsd_conf) . unwrap ( ) ;
124
+ ( bitcoind, electrsd)
125
+ }
126
+
127
+ pub fn generate_blocks_and_wait ( bitcoind : & BitcoinD , electrsd : & ElectrsD , num : usize ) {
128
+ let cur_height = bitcoind. client . get_block_count ( ) . expect ( "failed to get current block height" ) ;
129
+ let address = bitcoind
130
+ . client
131
+ . get_new_address ( Some ( "test" ) , Some ( AddressType :: Legacy ) )
132
+ . expect ( "failed to get new address" ) ;
133
+ // TODO: expect this Result once the WouldBlock issue is resolved upstream.
134
+ let _block_hashes_res = bitcoind. client . generate_to_address ( num as u64 , & address) ;
135
+ wait_for_block ( electrsd, cur_height as usize + num) ;
136
+ }
137
+
138
+ pub fn wait_for_block ( electrsd : & ElectrsD , min_height : usize ) {
139
+ let mut header = match electrsd. client . block_headers_subscribe ( ) {
140
+ Ok ( header) => header,
141
+ Err ( _) => {
142
+ // While subscribing should succeed the first time around, we ran into some cases where
143
+ // it didn't. Since we can't proceed without subscribing, we try again after a delay
144
+ // and panic if it still fails.
145
+ std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
146
+ electrsd. client . block_headers_subscribe ( ) . expect ( "failed to subscribe to block headers" )
147
+ }
148
+ } ;
149
+ loop {
150
+ if header. height >= min_height {
151
+ break ;
152
+ }
153
+ header = exponential_backoff_poll ( || {
154
+ electrsd. trigger ( ) . expect ( "failed to trigger electrsd" ) ;
155
+ electrsd. client . ping ( ) . expect ( "failed to ping electrsd" ) ;
156
+ electrsd. client . block_headers_pop ( ) . expect ( "failed to pop block header" )
157
+ } ) ;
158
+ }
159
+ }
160
+
161
+ pub fn wait_for_tx ( electrsd : & ElectrsD , txid : Txid ) {
162
+ let mut tx_res = electrsd. client . transaction_get ( & txid) ;
163
+ loop {
164
+ if tx_res. is_ok ( ) {
165
+ break ;
166
+ }
167
+ tx_res = exponential_backoff_poll ( || {
168
+ electrsd. trigger ( ) . unwrap ( ) ;
169
+ electrsd. client . ping ( ) . unwrap ( ) ;
170
+ Some ( electrsd. client . transaction_get ( & txid) )
171
+ } ) ;
172
+ }
173
+ }
174
+
175
+ pub fn wait_for_outpoint_spend ( electrsd : & ElectrsD , outpoint : OutPoint ) {
176
+ let tx = electrsd. client . transaction_get ( & outpoint. txid ) . unwrap ( ) ;
177
+ let txout_script = tx. output . get ( outpoint. vout as usize ) . unwrap ( ) . clone ( ) . script_pubkey ;
178
+ let mut is_spent = !electrsd. client . script_get_history ( & txout_script) . unwrap ( ) . is_empty ( ) ;
179
+ loop {
180
+ if is_spent {
181
+ break ;
182
+ }
183
+
184
+ is_spent = exponential_backoff_poll ( || {
185
+ electrsd. trigger ( ) . unwrap ( ) ;
186
+ electrsd. client . ping ( ) . unwrap ( ) ;
187
+ Some ( !electrsd. client . script_get_history ( & txout_script) . unwrap ( ) . is_empty ( ) )
188
+ } ) ;
189
+ }
190
+ }
191
+
192
+ pub fn exponential_backoff_poll < T , F > ( mut poll : F ) -> T
193
+ where
194
+ F : FnMut ( ) -> Option < T > ,
195
+ {
196
+ let mut delay = Duration :: from_millis ( 64 ) ;
197
+ let mut tries = 0 ;
198
+ loop {
199
+ match poll ( ) {
200
+ Some ( data) => break data,
201
+ None if delay. as_millis ( ) < 512 => {
202
+ delay = delay. mul_f32 ( 2.0 ) ;
203
+ }
204
+
205
+ None => { }
206
+ }
207
+ assert ! ( tries < 10 , "Reached max tries." ) ;
208
+ tries += 1 ;
209
+ std:: thread:: sleep ( delay) ;
210
+ }
211
+ }
212
+
213
+ pub fn premine_and_distribute_funds (
214
+ bitcoind : & BitcoinD , electrsd : & ElectrsD , addrs : Vec < Address > , amount : Amount ,
215
+ ) {
216
+ generate_blocks_and_wait ( bitcoind, electrsd, 101 ) ;
217
+
218
+ for addr in addrs {
219
+ let txid = bitcoind
220
+ . client
221
+ . send_to_address ( & addr, amount, None , None , None , None , None , None )
222
+ . unwrap ( ) ;
223
+ wait_for_tx ( electrsd, txid) ;
224
+ }
225
+
226
+ generate_blocks_and_wait ( bitcoind, electrsd, 1 ) ;
227
+ }
0 commit comments