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