1use std::borrow::Borrow;
4use std::convert::TryInto;
5use std::ops::Deref;
6
7use bitcoin::consensus::encode::{deserialize, serialize};
8use bitcoin::{block, Script, Transaction, Txid};
9
10use crate::batch::Batch;
11use crate::types::*;
12
13impl<E: Deref> ElectrumApi for E
14where
15 E::Target: ElectrumApi,
16{
17 fn raw_call(
18 &self,
19 method_name: &str,
20 params: impl IntoIterator<Item = Param>,
21 ) -> Result<serde_json::Value, Error> {
22 (**self).raw_call(method_name, params)
23 }
24
25 fn batch_call(&self, batch: &Batch) -> Result<Vec<serde_json::Value>, Error> {
26 (**self).batch_call(batch)
27 }
28
29 fn block_headers_subscribe_raw(&self) -> Result<RawHeaderNotification, Error> {
30 (**self).block_headers_subscribe_raw()
31 }
32
33 fn block_headers_pop_raw(&self) -> Result<Option<RawHeaderNotification>, Error> {
34 (**self).block_headers_pop_raw()
35 }
36
37 fn block_header_raw(&self, height: usize) -> Result<Vec<u8>, Error> {
38 (**self).block_header_raw(height)
39 }
40
41 fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error> {
42 (**self).block_headers(start_height, count)
43 }
44
45 fn estimate_fee(&self, number: usize) -> Result<f64, Error> {
46 (**self).estimate_fee(number)
47 }
48
49 fn relay_fee(&self) -> Result<f64, Error> {
50 (**self).relay_fee()
51 }
52
53 fn script_subscribe(&self, script: &Script) -> Result<Option<ScriptStatus>, Error> {
54 (**self).script_subscribe(script)
55 }
56
57 fn batch_script_subscribe<'s, I>(&self, scripts: I) -> Result<Vec<Option<ScriptStatus>>, Error>
58 where
59 I: IntoIterator + Clone,
60 I::Item: Borrow<&'s Script>,
61 {
62 (**self).batch_script_subscribe(scripts)
63 }
64
65 fn script_unsubscribe(&self, script: &Script) -> Result<bool, Error> {
66 (**self).script_unsubscribe(script)
67 }
68
69 fn script_pop(&self, script: &Script) -> Result<Option<ScriptStatus>, Error> {
70 (**self).script_pop(script)
71 }
72
73 fn script_get_balance(&self, script: &Script) -> Result<GetBalanceRes, Error> {
74 (**self).script_get_balance(script)
75 }
76
77 fn batch_script_get_balance<'s, I>(&self, scripts: I) -> Result<Vec<GetBalanceRes>, Error>
78 where
79 I: IntoIterator + Clone,
80 I::Item: Borrow<&'s Script>,
81 {
82 (**self).batch_script_get_balance(scripts)
83 }
84
85 fn script_get_history(&self, script: &Script) -> Result<Vec<GetHistoryRes>, Error> {
86 (**self).script_get_history(script)
87 }
88
89 fn batch_script_get_history<'s, I>(&self, scripts: I) -> Result<Vec<Vec<GetHistoryRes>>, Error>
90 where
91 I: IntoIterator + Clone,
92 I::Item: Borrow<&'s Script>,
93 {
94 (**self).batch_script_get_history(scripts)
95 }
96
97 fn script_list_unspent(&self, script: &Script) -> Result<Vec<ListUnspentRes>, Error> {
98 (**self).script_list_unspent(script)
99 }
100
101 fn batch_script_list_unspent<'s, I>(
102 &self,
103 scripts: I,
104 ) -> Result<Vec<Vec<ListUnspentRes>>, Error>
105 where
106 I: IntoIterator + Clone,
107 I::Item: Borrow<&'s Script>,
108 {
109 (**self).batch_script_list_unspent(scripts)
110 }
111
112 fn transaction_get_raw(&self, txid: &Txid) -> Result<Vec<u8>, Error> {
113 (**self).transaction_get_raw(txid)
114 }
115
116 fn batch_transaction_get_raw<'t, I>(&self, txids: I) -> Result<Vec<Vec<u8>>, Error>
117 where
118 I: IntoIterator + Clone,
119 I::Item: Borrow<&'t Txid>,
120 {
121 (**self).batch_transaction_get_raw(txids)
122 }
123
124 fn batch_block_header_raw<I>(&self, heights: I) -> Result<Vec<Vec<u8>>, Error>
125 where
126 I: IntoIterator + Clone,
127 I::Item: Borrow<u32>,
128 {
129 (**self).batch_block_header_raw(heights)
130 }
131
132 fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
133 where
134 I: IntoIterator + Clone,
135 I::Item: Borrow<usize>,
136 {
137 (**self).batch_estimate_fee(numbers)
138 }
139
140 fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error> {
141 (**self).transaction_broadcast_raw(raw_tx)
142 }
143
144 fn transaction_get_merkle(&self, txid: &Txid, height: usize) -> Result<GetMerkleRes, Error> {
145 (**self).transaction_get_merkle(txid, height)
146 }
147
148 fn txid_from_pos(&self, height: usize, tx_pos: usize) -> Result<Txid, Error> {
149 (**self).txid_from_pos(height, tx_pos)
150 }
151
152 fn txid_from_pos_with_merkle(
153 &self,
154 height: usize,
155 tx_pos: usize,
156 ) -> Result<TxidFromPosRes, Error> {
157 (**self).txid_from_pos_with_merkle(height, tx_pos)
158 }
159
160 fn server_features(&self) -> Result<ServerFeaturesRes, Error> {
161 (**self).server_features()
162 }
163
164 fn ping(&self) -> Result<(), Error> {
165 (**self).ping()
166 }
167
168 #[cfg(feature = "debug-calls")]
169 fn calls_made(&self) -> Result<usize, Error> {
170 (**self).calls_made()
171 }
172}
173
174pub trait ElectrumApi {
176 fn block_header(&self, height: usize) -> Result<block::Header, Error> {
178 Ok(deserialize(&self.block_header_raw(height)?)?)
179 }
180
181 fn block_headers_subscribe(&self) -> Result<HeaderNotification, Error> {
183 self.block_headers_subscribe_raw()?.try_into()
184 }
185
186 fn block_headers_pop(&self) -> Result<Option<HeaderNotification>, Error> {
189 self.block_headers_pop_raw()?
190 .map(|raw| raw.try_into())
191 .transpose()
192 }
193
194 fn transaction_get(&self, txid: &Txid) -> Result<Transaction, Error> {
196 Ok(deserialize(&self.transaction_get_raw(txid)?)?)
197 }
198
199 fn batch_transaction_get<'t, I>(&self, txids: I) -> Result<Vec<Transaction>, Error>
203 where
204 I: IntoIterator + Clone,
205 I::Item: Borrow<&'t Txid>,
206 {
207 self.batch_transaction_get_raw(txids)?
208 .iter()
209 .map(|s| Ok(deserialize(s)?))
210 .collect()
211 }
212
213 fn batch_block_header<I>(&self, heights: I) -> Result<Vec<block::Header>, Error>
217 where
218 I: IntoIterator + Clone,
219 I::Item: Borrow<u32>,
220 {
221 self.batch_block_header_raw(heights)?
222 .iter()
223 .map(|s| Ok(deserialize(s)?))
224 .collect()
225 }
226
227 fn transaction_broadcast(&self, tx: &Transaction) -> Result<Txid, Error> {
229 let buffer: Vec<u8> = serialize(tx);
230 self.transaction_broadcast_raw(&buffer)
231 }
232
233 fn raw_call(
235 &self,
236 method_name: &str,
237 params: impl IntoIterator<Item = Param>,
238 ) -> Result<serde_json::Value, Error>;
239
240 fn batch_call(&self, batch: &Batch) -> Result<Vec<serde_json::Value>, Error>;
244
245 fn block_headers_subscribe_raw(&self) -> Result<RawHeaderNotification, Error>;
248
249 fn block_headers_pop_raw(&self) -> Result<Option<RawHeaderNotification>, Error>;
252
253 fn block_header_raw(&self, height: usize) -> Result<Vec<u8>, Error>;
255
256 fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;
258
259 fn estimate_fee(&self, number: usize) -> Result<f64, Error>;
261
262 fn relay_fee(&self) -> Result<f64, Error>;
264
265 fn script_subscribe(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
273
274 fn batch_script_subscribe<'s, I>(&self, scripts: I) -> Result<Vec<Option<ScriptStatus>>, Error>
280 where
281 I: IntoIterator + Clone,
282 I::Item: Borrow<&'s Script>;
283
284 fn script_unsubscribe(&self, script: &Script) -> Result<bool, Error>;
291
292 fn script_pop(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
294
295 fn script_get_balance(&self, script: &Script) -> Result<GetBalanceRes, Error>;
297
298 fn batch_script_get_balance<'s, I>(&self, scripts: I) -> Result<Vec<GetBalanceRes>, Error>
302 where
303 I: IntoIterator + Clone,
304 I::Item: Borrow<&'s Script>;
305
306 fn script_get_history(&self, script: &Script) -> Result<Vec<GetHistoryRes>, Error>;
308
309 fn batch_script_get_history<'s, I>(&self, scripts: I) -> Result<Vec<Vec<GetHistoryRes>>, Error>
313 where
314 I: IntoIterator + Clone,
315 I::Item: Borrow<&'s Script>;
316
317 fn script_list_unspent(&self, script: &Script) -> Result<Vec<ListUnspentRes>, Error>;
319
320 fn batch_script_list_unspent<'s, I>(
324 &self,
325 scripts: I,
326 ) -> Result<Vec<Vec<ListUnspentRes>>, Error>
327 where
328 I: IntoIterator + Clone,
329 I::Item: Borrow<&'s Script>;
330
331 fn transaction_get_raw(&self, txid: &Txid) -> Result<Vec<u8>, Error>;
333
334 fn batch_transaction_get_raw<'t, I>(&self, txids: I) -> Result<Vec<Vec<u8>>, Error>
338 where
339 I: IntoIterator + Clone,
340 I::Item: Borrow<&'t Txid>;
341
342 fn batch_block_header_raw<I>(&self, heights: I) -> Result<Vec<Vec<u8>>, Error>
346 where
347 I: IntoIterator + Clone,
348 I::Item: Borrow<u32>;
349
350 fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
355 where
356 I: IntoIterator + Clone,
357 I::Item: Borrow<usize>;
358
359 fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error>;
361
362 fn transaction_get_merkle(&self, txid: &Txid, height: usize) -> Result<GetMerkleRes, Error>;
364
365 fn txid_from_pos(&self, height: usize, tx_pos: usize) -> Result<Txid, Error>;
367
368 fn txid_from_pos_with_merkle(
371 &self,
372 height: usize,
373 tx_pos: usize,
374 ) -> Result<TxidFromPosRes, Error>;
375
376 fn server_features(&self) -> Result<ServerFeaturesRes, Error>;
378
379 fn ping(&self) -> Result<(), Error>;
382
383 #[cfg(feature = "debug-calls")]
384 fn calls_made(&self) -> Result<usize, Error>;
386}
387
388#[cfg(test)]
389mod test {
390 use std::{borrow::Cow, sync::Arc};
391
392 use super::ElectrumApi;
393
394 #[derive(Debug, Clone)]
395 struct FakeApi;
396
397 impl ElectrumApi for FakeApi {
398 fn raw_call(
399 &self,
400 _: &str,
401 _: impl IntoIterator<Item = super::Param>,
402 ) -> Result<serde_json::Value, super::Error> {
403 unreachable!()
404 }
405
406 fn batch_call(&self, _: &crate::Batch) -> Result<Vec<serde_json::Value>, super::Error> {
407 unreachable!()
408 }
409
410 fn block_headers_subscribe_raw(
411 &self,
412 ) -> Result<super::RawHeaderNotification, super::Error> {
413 unreachable!()
414 }
415
416 fn block_headers_pop_raw(
417 &self,
418 ) -> Result<Option<super::RawHeaderNotification>, super::Error> {
419 unreachable!()
420 }
421
422 fn block_header_raw(&self, _: usize) -> Result<Vec<u8>, super::Error> {
423 unreachable!()
424 }
425
426 fn block_headers(&self, _: usize, _: usize) -> Result<super::GetHeadersRes, super::Error> {
427 unreachable!()
428 }
429
430 fn estimate_fee(&self, _: usize) -> Result<f64, super::Error> {
431 unreachable!()
432 }
433
434 fn relay_fee(&self) -> Result<f64, super::Error> {
435 unreachable!()
436 }
437
438 fn script_subscribe(
439 &self,
440 _: &bitcoin::Script,
441 ) -> Result<Option<super::ScriptStatus>, super::Error> {
442 unreachable!()
443 }
444
445 fn batch_script_subscribe<'s, I>(
446 &self,
447 _: I,
448 ) -> Result<Vec<Option<super::ScriptStatus>>, super::Error>
449 where
450 I: IntoIterator + Clone,
451 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
452 {
453 unreachable!()
454 }
455
456 fn script_unsubscribe(&self, _: &bitcoin::Script) -> Result<bool, super::Error> {
457 unreachable!()
458 }
459
460 fn script_pop(
461 &self,
462 _: &bitcoin::Script,
463 ) -> Result<Option<super::ScriptStatus>, super::Error> {
464 unreachable!()
465 }
466
467 fn script_get_balance(
468 &self,
469 _: &bitcoin::Script,
470 ) -> Result<super::GetBalanceRes, super::Error> {
471 unreachable!()
472 }
473
474 fn batch_script_get_balance<'s, I>(
475 &self,
476 _: I,
477 ) -> Result<Vec<super::GetBalanceRes>, super::Error>
478 where
479 I: IntoIterator + Clone,
480 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
481 {
482 unreachable!()
483 }
484
485 fn script_get_history(
486 &self,
487 _: &bitcoin::Script,
488 ) -> Result<Vec<super::GetHistoryRes>, super::Error> {
489 unreachable!()
490 }
491
492 fn batch_script_get_history<'s, I>(
493 &self,
494 _: I,
495 ) -> Result<Vec<Vec<super::GetHistoryRes>>, super::Error>
496 where
497 I: IntoIterator + Clone,
498 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
499 {
500 unreachable!()
501 }
502
503 fn script_list_unspent(
504 &self,
505 _: &bitcoin::Script,
506 ) -> Result<Vec<super::ListUnspentRes>, super::Error> {
507 unreachable!()
508 }
509
510 fn batch_script_list_unspent<'s, I>(
511 &self,
512 _: I,
513 ) -> Result<Vec<Vec<super::ListUnspentRes>>, super::Error>
514 where
515 I: IntoIterator + Clone,
516 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
517 {
518 unreachable!()
519 }
520
521 fn transaction_get_raw(&self, _: &bitcoin::Txid) -> Result<Vec<u8>, super::Error> {
522 unreachable!()
523 }
524
525 fn batch_transaction_get_raw<'t, I>(&self, _: I) -> Result<Vec<Vec<u8>>, super::Error>
526 where
527 I: IntoIterator + Clone,
528 I::Item: std::borrow::Borrow<&'t bitcoin::Txid>,
529 {
530 unreachable!()
531 }
532
533 fn batch_block_header_raw<I>(&self, _: I) -> Result<Vec<Vec<u8>>, super::Error>
534 where
535 I: IntoIterator + Clone,
536 I::Item: std::borrow::Borrow<u32>,
537 {
538 unreachable!()
539 }
540
541 fn batch_estimate_fee<I>(&self, _: I) -> Result<Vec<f64>, super::Error>
542 where
543 I: IntoIterator + Clone,
544 I::Item: std::borrow::Borrow<usize>,
545 {
546 unreachable!()
547 }
548
549 fn transaction_broadcast_raw(&self, _: &[u8]) -> Result<bitcoin::Txid, super::Error> {
550 unreachable!()
551 }
552
553 fn transaction_get_merkle(
554 &self,
555 _: &bitcoin::Txid,
556 _: usize,
557 ) -> Result<super::GetMerkleRes, super::Error> {
558 unreachable!()
559 }
560
561 fn txid_from_pos(&self, _: usize, _: usize) -> Result<bitcoin::Txid, super::Error> {
562 unreachable!()
563 }
564
565 fn txid_from_pos_with_merkle(
566 &self,
567 _: usize,
568 _: usize,
569 ) -> Result<super::TxidFromPosRes, super::Error> {
570 unreachable!()
571 }
572
573 fn server_features(&self) -> Result<super::ServerFeaturesRes, super::Error> {
574 unreachable!()
575 }
576
577 fn ping(&self) -> Result<(), super::Error> {
578 unreachable!()
579 }
580
581 #[cfg(feature = "debug-calls")]
582 fn calls_made(&self) -> Result<usize, super::Error> {
583 unreachable!()
584 }
585 }
586
587 fn is_impl<A: ElectrumApi>() {}
588
589 #[test]
590 fn deref() {
591 is_impl::<FakeApi>();
592 is_impl::<&FakeApi>();
593 is_impl::<Arc<FakeApi>>();
594 is_impl::<Box<FakeApi>>();
595 is_impl::<Cow<FakeApi>>();
596 }
597}