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 batch_transaction_get_merkle<I>(
149 &self,
150 txids_and_heights: I,
151 ) -> Result<Vec<GetMerkleRes>, Error>
152 where
153 I: IntoIterator + Clone,
154 I::Item: Borrow<(Txid, usize)>,
155 {
156 (**self).batch_transaction_get_merkle(txids_and_heights)
157 }
158
159 fn txid_from_pos(&self, height: usize, tx_pos: usize) -> Result<Txid, Error> {
160 (**self).txid_from_pos(height, tx_pos)
161 }
162
163 fn txid_from_pos_with_merkle(
164 &self,
165 height: usize,
166 tx_pos: usize,
167 ) -> Result<TxidFromPosRes, Error> {
168 (**self).txid_from_pos_with_merkle(height, tx_pos)
169 }
170
171 fn server_features(&self) -> Result<ServerFeaturesRes, Error> {
172 (**self).server_features()
173 }
174
175 fn ping(&self) -> Result<(), Error> {
176 (**self).ping()
177 }
178
179 #[cfg(feature = "debug-calls")]
180 fn calls_made(&self) -> Result<usize, Error> {
181 (**self).calls_made()
182 }
183}
184
185pub trait ElectrumApi {
187 fn block_header(&self, height: usize) -> Result<block::Header, Error> {
189 Ok(deserialize(&self.block_header_raw(height)?)?)
190 }
191
192 fn block_headers_subscribe(&self) -> Result<HeaderNotification, Error> {
194 self.block_headers_subscribe_raw()?.try_into()
195 }
196
197 fn block_headers_pop(&self) -> Result<Option<HeaderNotification>, Error> {
200 self.block_headers_pop_raw()?
201 .map(|raw| raw.try_into())
202 .transpose()
203 }
204
205 fn transaction_get(&self, txid: &Txid) -> Result<Transaction, Error> {
207 Ok(deserialize(&self.transaction_get_raw(txid)?)?)
208 }
209
210 fn batch_transaction_get<'t, I>(&self, txids: I) -> Result<Vec<Transaction>, Error>
214 where
215 I: IntoIterator + Clone,
216 I::Item: Borrow<&'t Txid>,
217 {
218 self.batch_transaction_get_raw(txids)?
219 .iter()
220 .map(|s| Ok(deserialize(s)?))
221 .collect()
222 }
223
224 fn batch_block_header<I>(&self, heights: I) -> Result<Vec<block::Header>, Error>
228 where
229 I: IntoIterator + Clone,
230 I::Item: Borrow<u32>,
231 {
232 self.batch_block_header_raw(heights)?
233 .iter()
234 .map(|s| Ok(deserialize(s)?))
235 .collect()
236 }
237
238 fn transaction_broadcast(&self, tx: &Transaction) -> Result<Txid, Error> {
240 let buffer: Vec<u8> = serialize(tx);
241 self.transaction_broadcast_raw(&buffer)
242 }
243
244 fn raw_call(
246 &self,
247 method_name: &str,
248 params: impl IntoIterator<Item = Param>,
249 ) -> Result<serde_json::Value, Error>;
250
251 fn batch_call(&self, batch: &Batch) -> Result<Vec<serde_json::Value>, Error>;
255
256 fn block_headers_subscribe_raw(&self) -> Result<RawHeaderNotification, Error>;
259
260 fn block_headers_pop_raw(&self) -> Result<Option<RawHeaderNotification>, Error>;
263
264 fn block_header_raw(&self, height: usize) -> Result<Vec<u8>, Error>;
266
267 fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;
269
270 fn estimate_fee(&self, number: usize) -> Result<f64, Error>;
272
273 fn relay_fee(&self) -> Result<f64, Error>;
275
276 fn script_subscribe(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
284
285 fn batch_script_subscribe<'s, I>(&self, scripts: I) -> Result<Vec<Option<ScriptStatus>>, Error>
291 where
292 I: IntoIterator + Clone,
293 I::Item: Borrow<&'s Script>;
294
295 fn script_unsubscribe(&self, script: &Script) -> Result<bool, Error>;
302
303 fn script_pop(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
305
306 fn script_get_balance(&self, script: &Script) -> Result<GetBalanceRes, Error>;
308
309 fn batch_script_get_balance<'s, I>(&self, scripts: I) -> Result<Vec<GetBalanceRes>, Error>
313 where
314 I: IntoIterator + Clone,
315 I::Item: Borrow<&'s Script>;
316
317 fn script_get_history(&self, script: &Script) -> Result<Vec<GetHistoryRes>, Error>;
319
320 fn batch_script_get_history<'s, I>(&self, scripts: I) -> Result<Vec<Vec<GetHistoryRes>>, Error>
324 where
325 I: IntoIterator + Clone,
326 I::Item: Borrow<&'s Script>;
327
328 fn script_list_unspent(&self, script: &Script) -> Result<Vec<ListUnspentRes>, Error>;
330
331 fn batch_script_list_unspent<'s, I>(
335 &self,
336 scripts: I,
337 ) -> Result<Vec<Vec<ListUnspentRes>>, Error>
338 where
339 I: IntoIterator + Clone,
340 I::Item: Borrow<&'s Script>;
341
342 fn transaction_get_raw(&self, txid: &Txid) -> Result<Vec<u8>, Error>;
344
345 fn batch_transaction_get_raw<'t, I>(&self, txids: I) -> Result<Vec<Vec<u8>>, Error>
349 where
350 I: IntoIterator + Clone,
351 I::Item: Borrow<&'t Txid>;
352
353 fn batch_block_header_raw<I>(&self, heights: I) -> Result<Vec<Vec<u8>>, Error>
357 where
358 I: IntoIterator + Clone,
359 I::Item: Borrow<u32>;
360
361 fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
366 where
367 I: IntoIterator + Clone,
368 I::Item: Borrow<usize>;
369
370 fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error>;
372
373 fn transaction_get_merkle(&self, txid: &Txid, height: usize) -> Result<GetMerkleRes, Error>;
375
376 fn batch_transaction_get_merkle<I>(
380 &self,
381 txids_and_heights: I,
382 ) -> Result<Vec<GetMerkleRes>, Error>
383 where
384 I: IntoIterator + Clone,
385 I::Item: Borrow<(Txid, usize)>;
386
387 fn txid_from_pos(&self, height: usize, tx_pos: usize) -> Result<Txid, Error>;
389
390 fn txid_from_pos_with_merkle(
393 &self,
394 height: usize,
395 tx_pos: usize,
396 ) -> Result<TxidFromPosRes, Error>;
397
398 fn server_features(&self) -> Result<ServerFeaturesRes, Error>;
400
401 fn ping(&self) -> Result<(), Error>;
404
405 #[cfg(feature = "debug-calls")]
406 fn calls_made(&self) -> Result<usize, Error>;
408}
409
410#[cfg(test)]
411mod test {
412 use std::{borrow::Cow, sync::Arc};
413
414 use super::ElectrumApi;
415
416 #[derive(Debug, Clone)]
417 struct FakeApi;
418
419 impl ElectrumApi for FakeApi {
420 fn raw_call(
421 &self,
422 _: &str,
423 _: impl IntoIterator<Item = super::Param>,
424 ) -> Result<serde_json::Value, super::Error> {
425 unreachable!()
426 }
427
428 fn batch_call(&self, _: &crate::Batch) -> Result<Vec<serde_json::Value>, super::Error> {
429 unreachable!()
430 }
431
432 fn block_headers_subscribe_raw(
433 &self,
434 ) -> Result<super::RawHeaderNotification, super::Error> {
435 unreachable!()
436 }
437
438 fn block_headers_pop_raw(
439 &self,
440 ) -> Result<Option<super::RawHeaderNotification>, super::Error> {
441 unreachable!()
442 }
443
444 fn block_header_raw(&self, _: usize) -> Result<Vec<u8>, super::Error> {
445 unreachable!()
446 }
447
448 fn block_headers(&self, _: usize, _: usize) -> Result<super::GetHeadersRes, super::Error> {
449 unreachable!()
450 }
451
452 fn estimate_fee(&self, _: usize) -> Result<f64, super::Error> {
453 unreachable!()
454 }
455
456 fn relay_fee(&self) -> Result<f64, super::Error> {
457 unreachable!()
458 }
459
460 fn script_subscribe(
461 &self,
462 _: &bitcoin::Script,
463 ) -> Result<Option<super::ScriptStatus>, super::Error> {
464 unreachable!()
465 }
466
467 fn batch_script_subscribe<'s, I>(
468 &self,
469 _: I,
470 ) -> Result<Vec<Option<super::ScriptStatus>>, super::Error>
471 where
472 I: IntoIterator + Clone,
473 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
474 {
475 unreachable!()
476 }
477
478 fn script_unsubscribe(&self, _: &bitcoin::Script) -> Result<bool, super::Error> {
479 unreachable!()
480 }
481
482 fn script_pop(
483 &self,
484 _: &bitcoin::Script,
485 ) -> Result<Option<super::ScriptStatus>, super::Error> {
486 unreachable!()
487 }
488
489 fn script_get_balance(
490 &self,
491 _: &bitcoin::Script,
492 ) -> Result<super::GetBalanceRes, super::Error> {
493 unreachable!()
494 }
495
496 fn batch_script_get_balance<'s, I>(
497 &self,
498 _: I,
499 ) -> Result<Vec<super::GetBalanceRes>, super::Error>
500 where
501 I: IntoIterator + Clone,
502 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
503 {
504 unreachable!()
505 }
506
507 fn script_get_history(
508 &self,
509 _: &bitcoin::Script,
510 ) -> Result<Vec<super::GetHistoryRes>, super::Error> {
511 unreachable!()
512 }
513
514 fn batch_script_get_history<'s, I>(
515 &self,
516 _: I,
517 ) -> Result<Vec<Vec<super::GetHistoryRes>>, super::Error>
518 where
519 I: IntoIterator + Clone,
520 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
521 {
522 unreachable!()
523 }
524
525 fn script_list_unspent(
526 &self,
527 _: &bitcoin::Script,
528 ) -> Result<Vec<super::ListUnspentRes>, super::Error> {
529 unreachable!()
530 }
531
532 fn batch_script_list_unspent<'s, I>(
533 &self,
534 _: I,
535 ) -> Result<Vec<Vec<super::ListUnspentRes>>, super::Error>
536 where
537 I: IntoIterator + Clone,
538 I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
539 {
540 unreachable!()
541 }
542
543 fn transaction_get_raw(&self, _: &bitcoin::Txid) -> Result<Vec<u8>, super::Error> {
544 unreachable!()
545 }
546
547 fn batch_transaction_get_raw<'t, I>(&self, _: I) -> Result<Vec<Vec<u8>>, super::Error>
548 where
549 I: IntoIterator + Clone,
550 I::Item: std::borrow::Borrow<&'t bitcoin::Txid>,
551 {
552 unreachable!()
553 }
554
555 fn batch_block_header_raw<I>(&self, _: I) -> Result<Vec<Vec<u8>>, super::Error>
556 where
557 I: IntoIterator + Clone,
558 I::Item: std::borrow::Borrow<u32>,
559 {
560 unreachable!()
561 }
562
563 fn batch_estimate_fee<I>(&self, _: I) -> Result<Vec<f64>, super::Error>
564 where
565 I: IntoIterator + Clone,
566 I::Item: std::borrow::Borrow<usize>,
567 {
568 unreachable!()
569 }
570
571 fn transaction_broadcast_raw(&self, _: &[u8]) -> Result<bitcoin::Txid, super::Error> {
572 unreachable!()
573 }
574
575 fn transaction_get_merkle(
576 &self,
577 _: &bitcoin::Txid,
578 _: usize,
579 ) -> Result<super::GetMerkleRes, super::Error> {
580 unreachable!()
581 }
582
583 fn batch_transaction_get_merkle<I>(
584 &self,
585 _: I,
586 ) -> Result<Vec<crate::GetMerkleRes>, crate::Error>
587 where
588 I: IntoIterator + Clone,
589 I::Item: std::borrow::Borrow<(bitcoin::Txid, usize)>,
590 {
591 unreachable!()
592 }
593
594 fn txid_from_pos(&self, _: usize, _: usize) -> Result<bitcoin::Txid, super::Error> {
595 unreachable!()
596 }
597
598 fn txid_from_pos_with_merkle(
599 &self,
600 _: usize,
601 _: usize,
602 ) -> Result<super::TxidFromPosRes, super::Error> {
603 unreachable!()
604 }
605
606 fn server_features(&self) -> Result<super::ServerFeaturesRes, super::Error> {
607 unreachable!()
608 }
609
610 fn ping(&self) -> Result<(), super::Error> {
611 unreachable!()
612 }
613
614 #[cfg(feature = "debug-calls")]
615 fn calls_made(&self) -> Result<usize, super::Error> {
616 unreachable!()
617 }
618 }
619
620 fn is_impl<A: ElectrumApi>() {}
621
622 #[test]
623 fn deref() {
624 is_impl::<FakeApi>();
625 is_impl::<&FakeApi>();
626 is_impl::<Arc<FakeApi>>();
627 is_impl::<Box<FakeApi>>();
628 is_impl::<Cow<FakeApi>>();
629 }
630}