@@ -18,6 +18,7 @@ use bitcoin;
18
18
use jsonrpc;
19
19
use serde;
20
20
use serde_json;
21
+ use serde_json:: value:: RawValue ;
21
22
22
23
use bitcoin:: hashes:: hex:: { FromHex , ToHex } ;
23
24
use bitcoin:: secp256k1:: Signature ;
@@ -215,14 +216,46 @@ impl Auth {
215
216
}
216
217
}
217
218
218
- pub trait RpcApi : Sized {
219
+ pub struct Request < ' c , T : ' static > {
220
+ method : & ' static str ,
221
+ args : Vec < serde_json:: Value > , //TODO(stevenroose) something more efficient?
222
+ converter : & ' static dyn Fn ( & RawValue ) -> Result < T > ,
223
+ client : & ' c dyn RpcClient ,
224
+ }
225
+
226
+ impl < ' c , T > Request < ' c , T > {
227
+ pub fn sync ( self ) -> Result < T > {
228
+ let raw = self . client . call ( self . method , & self . args ) ?;
229
+ let conv = self . converter ;
230
+ conv ( & raw )
231
+ }
232
+
233
+ fn async ( self ) -> Result < T > {
234
+ // use the async function of the client
235
+ unimplemented ! ( )
236
+ }
237
+
238
+ fn batch ( self , batch : & mut Batch < Self > ) {
239
+ batch. insert ( self ) ;
240
+ }
241
+ }
242
+
243
+ fn converter_hex < T : bitcoin:: consensus:: encode:: Decodable > ( raw : & RawValue ) -> Result < T > {
244
+ let hex: & str = serde_json:: from_str ( raw. get ( ) ) ?;
245
+ let bytes = Vec :: < u8 > :: from_hex ( & hex) ?;
246
+ Ok ( bitcoin:: consensus:: encode:: deserialize ( & bytes) ?)
247
+ }
248
+
249
+ fn converter_json < T : serde:: de:: DeserializeOwned > ( raw : & RawValue ) -> Result < T > {
250
+ Ok ( serde_json:: from_str ( raw. get ( ) ) ?)
251
+ }
252
+
253
+ pub trait RpcClient {
219
254
/// Call a `cmd` rpc with given `args` list
220
- fn call < T : for < ' a > serde:: de:: Deserialize < ' a > > (
221
- & self ,
222
- cmd : & str ,
223
- args : & [ serde_json:: Value ] ,
224
- ) -> Result < T > ;
255
+ fn call ( & self , cmd : & str , args : & [ serde_json:: Value ] ) -> Result < Box < RawValue > > ;
256
+ }
225
257
258
+ pub trait RpcApi : RpcClient + Sized {
226
259
/// Query an object implementing `Querable` type
227
260
fn get_by_id < T : queryable:: Queryable < Self > > (
228
261
& self ,
@@ -231,17 +264,58 @@ pub trait RpcApi: Sized {
231
264
T :: query ( & self , & id)
232
265
}
233
266
267
+ // this method could be moved outside of the trait
268
+ fn get_network_info_request ( & self ) -> Request < json:: GetNetworkInfoResult > {
269
+ Request {
270
+ method : "getnetworkinfo" ,
271
+ args : vec ! [ ] ,
272
+ converter : & |raw| converter_json :: < json:: GetNetworkInfoResult > ( raw) ,
273
+ client : self ,
274
+ }
275
+ }
276
+ #[ cfg( not( feature = "async" ) ) ]
234
277
fn get_network_info ( & self ) -> Result < json:: GetNetworkInfoResult > {
235
- self . call ( "getnetworkinfo" , & [ ] )
278
+ self . get_network_info_request ( ) . sync ( )
279
+ }
280
+ #[ cfg( feature = "async" ) ]
281
+ async fn get_network_info ( & self ) -> Result < json:: GetNetworkInfoResult > {
282
+ self . get_network_info_request ( ) . async ( )
283
+ }
284
+ // this is some way through which it would be possible to have an API with both sync and async
285
+ // methods when async is supported
286
+ #[ cfg( feature = "both-sync-async" ) ]
287
+ fn get_network_info_sync ( & self ) -> Result < json:: GetNetworkInfoResult > {
288
+ self . get_network_info_request ( ) . sync ( )
289
+ }
290
+ fn batch_get_network_info < R > ( & self , batch : & mut Batch < R > ) where Self : Sized {
291
+ self . get_network_info_request ( ) . batch ( batch) ;
236
292
}
237
293
238
- fn version ( & self ) -> Result < usize > {
239
- #[ derive( Deserialize ) ]
240
- struct Response {
241
- pub version : usize ,
294
+ fn version_request ( & self ) -> Request < usize > {
295
+ Request {
296
+ method : "getnetworkinfo" ,
297
+ args : vec ! [ ] ,
298
+ converter : & |raw| {
299
+ #[ derive( Deserialize ) ]
300
+ struct Response {
301
+ pub version : usize ,
302
+ }
303
+ let ret: Response = serde_json:: from_str ( raw. get ( ) ) ?;
304
+ Ok ( ret. version )
305
+ } ,
306
+ client : self ,
242
307
}
243
- let res: Response = self . call ( "getnetworkinfo" , & [ ] ) ?;
244
- Ok ( res. version )
308
+ }
309
+ #[ cfg( not( feature = "async" ) ) ]
310
+ fn version ( & self ) -> Result < usize > {
311
+ self . version_request ( ) . sync ( )
312
+ }
313
+ #[ cfg( feature = "async" ) ]
314
+ fn version ( & self ) -> Result < usize > {
315
+ self . version_request ( ) . async ( )
316
+ }
317
+ fn batch_version < R > ( & self , batch : & mut Batch < R > ) where Self : Sized {
318
+ self . version_request ( ) . batch ( batch) ;
245
319
}
246
320
247
321
fn add_multisig_address (
@@ -747,7 +821,7 @@ pub trait RpcApi: Sized {
747
821
tx : R ,
748
822
options : Option < & json:: FundRawTransactionOptions > ,
749
823
is_witness : Option < bool > ,
750
- ) -> Result < json:: FundRawTransactionResult > {
824
+ ) -> Result < json:: FundRawTransactionResult > where Self : Sized {
751
825
let mut args = [ tx. raw_hex ( ) . into ( ) , opt_into_json ( options) ?, opt_into_json ( is_witness) ?] ;
752
826
let defaults = [ empty_obj ( ) , null ( ) ] ;
753
827
self . call ( "fundrawtransaction" , handle_defaults ( & mut args, & defaults) )
@@ -760,7 +834,7 @@ pub trait RpcApi: Sized {
760
834
utxos : Option < & [ json:: SignRawTransactionInput ] > ,
761
835
private_keys : Option < & [ PrivateKey ] > ,
762
836
sighash_type : Option < json:: SigHashType > ,
763
- ) -> Result < json:: SignRawTransactionResult > {
837
+ ) -> Result < json:: SignRawTransactionResult > where Self : Sized {
764
838
let mut args = [
765
839
tx. raw_hex ( ) . into ( ) ,
766
840
opt_into_json ( utxos) ?,
@@ -776,7 +850,7 @@ pub trait RpcApi: Sized {
776
850
tx : R ,
777
851
utxos : Option < & [ json:: SignRawTransactionInput ] > ,
778
852
sighash_type : Option < json:: SigHashType > ,
779
- ) -> Result < json:: SignRawTransactionResult > {
853
+ ) -> Result < json:: SignRawTransactionResult > where Self : Sized {
780
854
let mut args = [ tx. raw_hex ( ) . into ( ) , opt_into_json ( utxos) ?, opt_into_json ( sighash_type) ?] ;
781
855
let defaults = [ empty_arr ( ) , null ( ) ] ;
782
856
self . call ( "signrawtransactionwithwallet" , handle_defaults ( & mut args, & defaults) )
@@ -788,7 +862,7 @@ pub trait RpcApi: Sized {
788
862
privkeys : & [ PrivateKey ] ,
789
863
prevtxs : Option < & [ json:: SignRawTransactionInput ] > ,
790
864
sighash_type : Option < json:: SigHashType > ,
791
- ) -> Result < json:: SignRawTransactionResult > {
865
+ ) -> Result < json:: SignRawTransactionResult > where Self : Sized {
792
866
let mut args = [
793
867
tx. raw_hex ( ) . into ( ) ,
794
868
into_json ( privkeys) ?,
@@ -802,7 +876,7 @@ pub trait RpcApi: Sized {
802
876
fn test_mempool_accept < R : RawTx > (
803
877
& self ,
804
878
rawtxs : & [ R ] ,
805
- ) -> Result < Vec < json:: TestMempoolAcceptResult > > {
879
+ ) -> Result < Vec < json:: TestMempoolAcceptResult > > where Self : Sized {
806
880
let hexes: Vec < serde_json:: Value > =
807
881
rawtxs. to_vec ( ) . into_iter ( ) . map ( |r| r. raw_hex ( ) . into ( ) ) . collect ( ) ;
808
882
self . call ( "testmempoolaccept" , & [ hexes. into ( ) ] )
@@ -999,7 +1073,7 @@ pub trait RpcApi: Sized {
999
1073
self . call ( "ping" , & [ ] )
1000
1074
}
1001
1075
1002
- fn send_raw_transaction < R : RawTx > ( & self , tx : R ) -> Result < bitcoin:: Txid > {
1076
+ fn send_raw_transaction < R : RawTx > ( & self , tx : R ) -> Result < bitcoin:: Txid > where Self : Sized {
1003
1077
self . call ( "sendrawtransaction" , & [ tx. raw_hex ( ) . into ( ) ] )
1004
1078
}
1005
1079
@@ -1188,13 +1262,9 @@ impl Client {
1188
1262
}
1189
1263
}
1190
1264
1191
- impl RpcApi for Client {
1265
+ impl RpcClient for Client {
1192
1266
/// Call an `cmd` rpc with given `args` list
1193
- fn call < T : for < ' a > serde:: de:: Deserialize < ' a > > (
1194
- & self ,
1195
- cmd : & str ,
1196
- args : & [ serde_json:: Value ] ,
1197
- ) -> Result < T > {
1267
+ fn call ( & self , cmd : & str , args : & [ serde_json:: Value ] ) -> Result < Box < RawValue > > {
1198
1268
let raw_args: Vec < _ > = args
1199
1269
. iter ( )
1200
1270
. map ( |a| {
@@ -1213,6 +1283,8 @@ impl RpcApi for Client {
1213
1283
Ok ( resp?. result ( ) ?)
1214
1284
}
1215
1285
}
1286
+ impl RpcApi for Client {
1287
+ }
1216
1288
1217
1289
fn log_response ( cmd : & str , resp : & Result < jsonrpc:: Response > ) {
1218
1290
if log_enabled ! ( Warn ) || log_enabled ! ( Debug ) || log_enabled ! ( Trace ) {
0 commit comments