1
1
use crate :: convert:: { BlockchainInfo , FeeResponse , FundedTx , NewAddress , RawTx , SignedTx } ;
2
2
use base64;
3
- use bitcoin:: blockdata:: block:: { Block , BlockHeader } ;
3
+ use bitcoin:: blockdata:: block:: Block ;
4
4
use bitcoin:: blockdata:: transaction:: Transaction ;
5
5
use bitcoin:: consensus:: encode;
6
6
use bitcoin:: hash_types:: BlockHash ;
@@ -12,82 +12,161 @@ use lightning_block_sync::{AsyncBlockSourceResult, BlockHeaderData, BlockSource}
12
12
use serde_json;
13
13
use std:: collections:: HashMap ;
14
14
use std:: str:: FromStr ;
15
- use std:: sync:: { Arc , Mutex } ;
15
+ use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
16
+ use std:: sync:: Arc ;
17
+ use std:: time:: Duration ;
18
+ use tokio:: sync:: Mutex ;
16
19
17
20
pub struct BitcoindClient {
18
- // bitcoind_rpc_client: RpcClient,
19
- bitcoind_rpc_client : Mutex < RpcClient > ,
21
+ bitcoind_rpc_client : Arc < Mutex < RpcClient > > ,
20
22
host : String ,
21
23
port : u16 ,
22
24
rpc_user : String ,
23
25
rpc_password : String ,
24
- fees : Arc < HashMap < String , u32 > > ,
26
+ fees : Arc < HashMap < Target , AtomicU32 > > ,
27
+ }
28
+
29
+ #[ derive( Clone , Eq , Hash , PartialEq ) ]
30
+ pub enum Target {
31
+ Background ,
32
+ Normal ,
33
+ HighPriority ,
25
34
}
26
35
27
36
impl BlockSource for & BitcoindClient {
28
37
fn get_header < ' a > (
29
38
& ' a mut self , header_hash : & ' a BlockHash , height_hint : Option < u32 > ,
30
39
) -> AsyncBlockSourceResult < ' a , BlockHeaderData > {
31
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
32
- // self.bitcoind_rpc_client.get_header(header_hash, height_hint)
33
- rpc. get_header ( header_hash, height_hint)
40
+ Box :: pin ( async move {
41
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
42
+ rpc. get_header ( header_hash, height_hint) . await
43
+ } )
34
44
}
45
+
35
46
fn get_block < ' a > (
36
47
& ' a mut self , header_hash : & ' a BlockHash ,
37
48
) -> AsyncBlockSourceResult < ' a , Block > {
38
- // self.bitcoind_rpc_client.get_block(header_hash)
39
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
40
- rpc. get_block ( header_hash)
49
+ Box :: pin ( async move {
50
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
51
+ rpc. get_block ( header_hash) . await
52
+ } )
41
53
}
54
+
42
55
fn get_best_block < ' a > ( & ' a mut self ) -> AsyncBlockSourceResult < ( BlockHash , Option < u32 > ) > {
43
- // self.bitcoind_rpc_client.get_best_block()
44
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
45
- rpc. get_best_block ( )
56
+ Box :: pin ( async move {
57
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
58
+ rpc. get_best_block ( ) . await
59
+ } )
46
60
}
47
61
}
48
62
49
63
impl BitcoindClient {
50
- pub fn new (
64
+ pub async fn new (
51
65
host : String , port : u16 , rpc_user : String , rpc_password : String ,
52
66
) -> std:: io:: Result < Self > {
53
67
let http_endpoint = HttpEndpoint :: for_host ( host. clone ( ) ) . with_port ( port) ;
54
68
let rpc_credentials =
55
69
base64:: encode ( format ! ( "{}:{}" , rpc_user. clone( ) , rpc_password. clone( ) ) ) ;
56
70
let bitcoind_rpc_client = RpcClient :: new ( & rpc_credentials, http_endpoint) ?;
71
+ let mut fees: HashMap < Target , AtomicU32 > = HashMap :: new ( ) ;
72
+ fees. insert ( Target :: Background , AtomicU32 :: new ( 253 ) ) ;
73
+ fees. insert ( Target :: Normal , AtomicU32 :: new ( 2000 ) ) ;
74
+ fees. insert ( Target :: HighPriority , AtomicU32 :: new ( 5000 ) ) ;
57
75
let client = Self {
58
- // bitcoind_rpc_client,
59
- bitcoind_rpc_client : Mutex :: new ( bitcoind_rpc_client) ,
76
+ bitcoind_rpc_client : Arc :: new ( Mutex :: new ( bitcoind_rpc_client) ) ,
60
77
host,
61
78
port,
62
79
rpc_user,
63
80
rpc_password,
64
- fees : Arc :: new ( HashMap :: new ( ) ) ,
81
+ fees : Arc :: new ( fees ) ,
65
82
} ;
66
- client. poll_for_fee_estimates ( ) ;
83
+ BitcoindClient :: poll_for_fee_estimates (
84
+ client. fees . clone ( ) ,
85
+ client. bitcoind_rpc_client . clone ( ) ,
86
+ )
87
+ . await ;
67
88
Ok ( client)
68
89
}
69
90
70
- fn poll_for_fee_estimates ( & self ) {
71
- let bitcoind_rpc_client = self . get_new_rpc_client ( ) . unwrap ( ) ;
72
- let mut rpc = self . get_new_rpc_client ( ) . unwrap ( ) ;
73
- let mut fees = self . fees . clone ( ) ;
74
- tokio:: spawn ( async {
91
+ async fn poll_for_fee_estimates (
92
+ fees : Arc < HashMap < Target , AtomicU32 > > , rpc_client : Arc < Mutex < RpcClient > > ,
93
+ ) {
94
+ tokio:: spawn ( async move {
75
95
loop {
76
- let background_conf_target = serde_json:: json!( 144 ) ;
77
- let background_estimate_mode = serde_json:: json!( "ECONOMICAL" ) ;
78
-
79
- let background_estimate = bitcoind_rpc_client
80
- . call_method :: < FeeResponse > (
81
- "estimatesmartfee" ,
82
- & vec ! [ background_conf_target, background_estimate_mode] ,
83
- )
84
- . await
85
- . unwrap ( ) ;
86
- match background_estimate. feerate {
87
- Some ( fee) => fees. insert ( "background" . to_string ( ) , fee) ,
88
- None => fees. insert ( "background" . to_string ( ) , 253 ) ,
96
+ let background_estimate = {
97
+ let mut rpc = rpc_client. lock ( ) . await ;
98
+ let background_conf_target = serde_json:: json!( 144 ) ;
99
+ let background_estimate_mode = serde_json:: json!( "ECONOMICAL" ) ;
100
+ let resp = rpc
101
+ . call_method :: < FeeResponse > (
102
+ "estimatesmartfee" ,
103
+ & vec ! [ background_conf_target, background_estimate_mode] ,
104
+ )
105
+ . await
106
+ . unwrap ( ) ;
107
+ match resp. feerate {
108
+ Some ( fee) => fee,
109
+ None => 253 ,
110
+ }
111
+ } ;
112
+ // if background_estimate.
113
+
114
+ let normal_estimate = {
115
+ let mut rpc = rpc_client. lock ( ) . await ;
116
+ let normal_conf_target = serde_json:: json!( 18 ) ;
117
+ let normal_estimate_mode = serde_json:: json!( "ECONOMICAL" ) ;
118
+ let resp = rpc
119
+ . call_method :: < FeeResponse > (
120
+ "estimatesmartfee" ,
121
+ & vec ! [ normal_conf_target, normal_estimate_mode] ,
122
+ )
123
+ . await
124
+ . unwrap ( ) ;
125
+ match resp. feerate {
126
+ Some ( fee) => fee,
127
+ None => 2000 ,
128
+ }
89
129
} ;
90
- // fees.insert("background".to_string(), background_estimate);
130
+
131
+ let high_prio_estimate = {
132
+ let mut rpc = rpc_client. lock ( ) . await ;
133
+ let high_prio_conf_target = serde_json:: json!( 6 ) ;
134
+ let high_prio_estimate_mode = serde_json:: json!( "CONSERVATIVE" ) ;
135
+ let resp = rpc
136
+ . call_method :: < FeeResponse > (
137
+ "estimatesmartfee" ,
138
+ & vec ! [ high_prio_conf_target, high_prio_estimate_mode] ,
139
+ )
140
+ . await
141
+ . unwrap ( ) ;
142
+
143
+ match resp. feerate {
144
+ Some ( fee) => fee,
145
+ None => 5000 ,
146
+ }
147
+ } ;
148
+
149
+ fees. get ( & Target :: Background )
150
+ . unwrap ( )
151
+ . store ( background_estimate, Ordering :: Release ) ;
152
+ fees. get ( & Target :: Normal ) . unwrap ( ) . store ( normal_estimate, Ordering :: Release ) ;
153
+ fees. get ( & Target :: HighPriority )
154
+ . unwrap ( )
155
+ . store ( high_prio_estimate, Ordering :: Release ) ;
156
+ // match fees.get(Target::Background) {
157
+ // Some(fee) => fee.store(background_estimate, Ordering::Release),
158
+ // None =>
159
+ // }
160
+ // if let Some(fee) = background_estimate.feerate {
161
+ // fees.get("background").unwrap().store(fee, Ordering::Release);
162
+ // }
163
+ // if let Some(fee) = normal_estimate.feerate {
164
+ // fees.get("normal").unwrap().store(fee, Ordering::Release);
165
+ // }
166
+ // if let Some(fee) = high_prio_estimate.feerate {
167
+ // fees.get("high_prio").unwrap().store(fee, Ordering::Release);
168
+ // }
169
+ tokio:: time:: sleep ( Duration :: from_secs ( 60 ) ) . await ;
91
170
}
92
171
} ) ;
93
172
}
@@ -99,58 +178,68 @@ impl BitcoindClient {
99
178
RpcClient :: new ( & rpc_credentials, http_endpoint)
100
179
}
101
180
102
- // pub async fn create_raw_transaction(&mut self, outputs: Vec<HashMap<String, f64>>) -> RawTx {
103
181
pub async fn create_raw_transaction ( & self , outputs : Vec < HashMap < String , f64 > > ) -> RawTx {
104
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
182
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
105
183
106
184
let outputs_json = serde_json:: json!( outputs) ;
107
- // self.bitcoind_rpc_client
108
185
rpc. call_method :: < RawTx > ( "createrawtransaction" , & vec ! [ serde_json:: json!( [ ] ) , outputs_json] )
109
186
. await
110
187
. unwrap ( )
111
188
}
112
189
113
- // pub async fn fund_raw_transaction(&mut self, raw_tx: RawTx) -> FundedTx {
114
190
pub async fn fund_raw_transaction ( & self , raw_tx : RawTx ) -> FundedTx {
115
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
191
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
116
192
117
193
let raw_tx_json = serde_json:: json!( raw_tx. 0 ) ;
118
- // self.bitcoind_rpc_client.call_method("fundrawtransaction", &[raw_tx_json]).await.unwrap()
119
194
rpc. call_method ( "fundrawtransaction" , & [ raw_tx_json] ) . await . unwrap ( )
120
195
}
121
196
122
- // pub async fn sign_raw_transaction_with_wallet(&mut self, tx_hex: String) -> SignedTx {
197
+ pub async fn send_raw_transaction ( & self , raw_tx : RawTx ) {
198
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
199
+
200
+ let raw_tx_json = serde_json:: json!( raw_tx. 0 ) ;
201
+ rpc. call_method :: < RawTx > ( "sendrawtransaction" , & [ raw_tx_json] ) . await . unwrap ( ) ;
202
+ }
203
+
123
204
pub async fn sign_raw_transaction_with_wallet ( & self , tx_hex : String ) -> SignedTx {
124
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
205
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
125
206
126
207
let tx_hex_json = serde_json:: json!( tx_hex) ;
127
- // self.bitcoind_rpc_client
128
208
rpc. call_method ( "signrawtransactionwithwallet" , & vec ! [ tx_hex_json] ) . await . unwrap ( )
129
209
}
130
210
131
- // pub async fn get_new_address(&mut self) -> Address {
132
211
pub async fn get_new_address ( & self ) -> Address {
133
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
212
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
134
213
135
214
let addr_args = vec ! [ serde_json:: json!( "LDK output address" ) ] ;
136
- // let addr = self
137
- // .bitcoind_rpc_client
138
215
let addr = rpc. call_method :: < NewAddress > ( "getnewaddress" , & addr_args) . await . unwrap ( ) ;
139
216
Address :: from_str ( addr. 0 . as_str ( ) ) . unwrap ( )
140
217
}
141
218
142
- // pub async fn get_blockchain_info(&mut self) -> BlockchainInfo {
143
219
pub async fn get_blockchain_info ( & self ) -> BlockchainInfo {
144
- let mut rpc = self . bitcoind_rpc_client . lock ( ) . unwrap ( ) ;
145
-
146
- // self.bitcoind_rpc_client
220
+ let mut rpc = self . bitcoind_rpc_client . lock ( ) . await ;
147
221
rpc. call_method :: < BlockchainInfo > ( "getblockchaininfo" , & vec ! [ ] ) . await . unwrap ( )
148
222
}
149
223
}
150
224
151
225
impl FeeEstimator for BitcoindClient {
152
226
fn get_est_sat_per_1000_weight ( & self , confirmation_target : ConfirmationTarget ) -> u32 {
153
- 253
227
+ match confirmation_target {
228
+ ConfirmationTarget :: Background => {
229
+ self . fees . get ( & Target :: Background ) . unwrap ( ) . load ( Ordering :: Acquire )
230
+ }
231
+ ConfirmationTarget :: Normal => {
232
+ self . fees . get ( & Target :: Normal ) . unwrap ( ) . load ( Ordering :: Acquire )
233
+ }
234
+ ConfirmationTarget :: HighPriority => {
235
+ self . fees . get ( & Target :: HighPriority ) . unwrap ( ) . load ( Ordering :: Acquire )
236
+ }
237
+ }
238
+ // self.fees.g
239
+ // 253
240
+ // match confirmation_target {
241
+ // ConfirmationTarget::Background =>
242
+ // }
154
243
// let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
155
244
156
245
// let (conf_target, estimate_mode, default) = match confirmation_target {
@@ -188,6 +277,17 @@ impl FeeEstimator for BitcoindClient {
188
277
189
278
impl BroadcasterInterface for BitcoindClient {
190
279
fn broadcast_transaction ( & self , tx : & Transaction ) {
280
+ let bitcoind_rpc_client = self . bitcoind_rpc_client . clone ( ) ;
281
+ let tx_serialized = serde_json:: json!( encode:: serialize_hex( tx) ) ;
282
+ tokio:: spawn ( async move {
283
+ let mut rpc = bitcoind_rpc_client. lock ( ) . await ;
284
+ rpc. call_method :: < RawTx > ( "sendrawtransaction" , & vec ! [ tx_serialized] ) . await . unwrap ( ) ;
285
+ } ) ;
286
+ // let bitcoind_rpc_client = self.bitcoind_rpc_client.clone();
287
+ // tokio::spawn(async move {
288
+ // let rpc = bitcoind_rpc_client.lock().await;
289
+ // rpc.call_method::<R>
290
+ // });
191
291
// let mut rpc = self.bitcoind_rpc_client.lock().unwrap();
192
292
// let runtime = self.runtime.lock().unwrap();
193
293
0 commit comments