Skip to main content

electrum_client/
api.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Electrum APIs
4
5use std::borrow::Borrow;
6use std::convert::TryInto;
7use std::ops::Deref;
8
9use bitcoin::consensus::encode::{deserialize, serialize};
10use bitcoin::{block, Script, Transaction, Txid};
11
12use crate::batch::Batch;
13use crate::types::*;
14
15impl<E: Deref> ElectrumApi for E
16where
17    E::Target: ElectrumApi,
18{
19    fn raw_call(
20        &self,
21        method_name: &str,
22        params: impl IntoIterator<Item = Param>,
23    ) -> Result<serde_json::Value, Error> {
24        (**self).raw_call(method_name, params)
25    }
26
27    fn batch_call(&self, batch: &Batch) -> Result<Vec<serde_json::Value>, Error> {
28        (**self).batch_call(batch)
29    }
30
31    fn block_headers_subscribe_raw(&self) -> Result<RawHeaderNotification, Error> {
32        (**self).block_headers_subscribe_raw()
33    }
34
35    fn block_headers_pop_raw(&self) -> Result<Option<RawHeaderNotification>, Error> {
36        (**self).block_headers_pop_raw()
37    }
38
39    fn block_header_raw(&self, height: usize) -> Result<Vec<u8>, Error> {
40        (**self).block_header_raw(height)
41    }
42
43    fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error> {
44        (**self).block_headers(start_height, count)
45    }
46
47    fn estimate_fee(&self, number: usize, mode: Option<EstimationMode>) -> Result<f64, Error> {
48        (**self).estimate_fee(number, mode)
49    }
50
51    fn relay_fee(&self) -> Result<f64, Error> {
52        (**self).relay_fee()
53    }
54
55    fn script_subscribe(&self, script: &Script) -> Result<Option<ScriptStatus>, Error> {
56        (**self).script_subscribe(script)
57    }
58
59    fn batch_script_subscribe<'s, I>(&self, scripts: I) -> Result<Vec<Option<ScriptStatus>>, Error>
60    where
61        I: IntoIterator + Clone,
62        I::Item: Borrow<&'s Script>,
63    {
64        (**self).batch_script_subscribe(scripts)
65    }
66
67    fn script_unsubscribe(&self, script: &Script) -> Result<bool, Error> {
68        (**self).script_unsubscribe(script)
69    }
70
71    fn script_pop(&self, script: &Script) -> Result<Option<ScriptStatus>, Error> {
72        (**self).script_pop(script)
73    }
74
75    fn script_get_balance(&self, script: &Script) -> Result<GetBalanceRes, Error> {
76        (**self).script_get_balance(script)
77    }
78
79    fn batch_script_get_balance<'s, I>(&self, scripts: I) -> Result<Vec<GetBalanceRes>, Error>
80    where
81        I: IntoIterator + Clone,
82        I::Item: Borrow<&'s Script>,
83    {
84        (**self).batch_script_get_balance(scripts)
85    }
86
87    fn script_get_history(&self, script: &Script) -> Result<Vec<GetHistoryRes>, Error> {
88        (**self).script_get_history(script)
89    }
90
91    fn batch_script_get_history<'s, I>(&self, scripts: I) -> Result<Vec<Vec<GetHistoryRes>>, Error>
92    where
93        I: IntoIterator + Clone,
94        I::Item: Borrow<&'s Script>,
95    {
96        (**self).batch_script_get_history(scripts)
97    }
98
99    fn script_list_unspent(&self, script: &Script) -> Result<Vec<ListUnspentRes>, Error> {
100        (**self).script_list_unspent(script)
101    }
102
103    fn batch_script_list_unspent<'s, I>(
104        &self,
105        scripts: I,
106    ) -> Result<Vec<Vec<ListUnspentRes>>, Error>
107    where
108        I: IntoIterator + Clone,
109        I::Item: Borrow<&'s Script>,
110    {
111        (**self).batch_script_list_unspent(scripts)
112    }
113
114    fn transaction_get_raw(&self, txid: &Txid) -> Result<Vec<u8>, Error> {
115        (**self).transaction_get_raw(txid)
116    }
117
118    fn batch_transaction_get_raw<'t, I>(&self, txids: I) -> Result<Vec<Vec<u8>>, Error>
119    where
120        I: IntoIterator + Clone,
121        I::Item: Borrow<&'t Txid>,
122    {
123        (**self).batch_transaction_get_raw(txids)
124    }
125
126    fn batch_block_header_raw<I>(&self, heights: I) -> Result<Vec<Vec<u8>>, Error>
127    where
128        I: IntoIterator + Clone,
129        I::Item: Borrow<u32>,
130    {
131        (**self).batch_block_header_raw(heights)
132    }
133
134    fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
135    where
136        I: IntoIterator + Clone,
137        I::Item: Borrow<usize>,
138    {
139        (**self).batch_estimate_fee(numbers)
140    }
141
142    fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error> {
143        (**self).transaction_broadcast_raw(raw_tx)
144    }
145
146    fn transaction_broadcast_package_raw<T: AsRef<[u8]>>(
147        &self,
148        raw_txs: &[T],
149    ) -> Result<BroadcastPackageRes, Error> {
150        (**self).transaction_broadcast_package_raw(raw_txs)
151    }
152
153    fn transaction_get_merkle(&self, txid: &Txid, height: usize) -> Result<GetMerkleRes, Error> {
154        (**self).transaction_get_merkle(txid, height)
155    }
156
157    fn batch_transaction_get_merkle<I>(
158        &self,
159        txids_and_heights: I,
160    ) -> Result<Vec<GetMerkleRes>, Error>
161    where
162        I: IntoIterator + Clone,
163        I::Item: Borrow<(Txid, usize)>,
164    {
165        (**self).batch_transaction_get_merkle(txids_and_heights)
166    }
167
168    fn txid_from_pos(&self, height: usize, tx_pos: usize) -> Result<Txid, Error> {
169        (**self).txid_from_pos(height, tx_pos)
170    }
171
172    fn txid_from_pos_with_merkle(
173        &self,
174        height: usize,
175        tx_pos: usize,
176    ) -> Result<TxidFromPosRes, Error> {
177        (**self).txid_from_pos_with_merkle(height, tx_pos)
178    }
179
180    fn server_features(&self) -> Result<ServerFeaturesRes, Error> {
181        (**self).server_features()
182    }
183
184    fn mempool_get_info(&self) -> Result<MempoolInfoRes, Error> {
185        (**self).mempool_get_info()
186    }
187
188    fn ping(&self) -> Result<(), Error> {
189        (**self).ping()
190    }
191
192    fn calls_made(&self) -> Result<usize, Error> {
193        (**self).calls_made()
194    }
195}
196
197/// API calls exposed by an Electrum client
198pub trait ElectrumApi {
199    /// Gets the block header for height `height`.
200    fn block_header(&self, height: usize) -> Result<block::Header, Error> {
201        Ok(deserialize(&self.block_header_raw(height)?)?)
202    }
203
204    /// Subscribes to notifications for new block headers, by sending a `blockchain.headers.subscribe` call.
205    fn block_headers_subscribe(&self) -> Result<HeaderNotification, Error> {
206        self.block_headers_subscribe_raw()?.try_into()
207    }
208
209    /// Tries to pop one queued notification for a new block header that we might have received.
210    /// Returns `None` if there are no items in the queue.
211    fn block_headers_pop(&self) -> Result<Option<HeaderNotification>, Error> {
212        self.block_headers_pop_raw()?
213            .map(|raw| raw.try_into())
214            .transpose()
215    }
216
217    /// Gets the transaction with `txid`. Returns an error if not found.
218    fn transaction_get(&self, txid: &Txid) -> Result<Transaction, Error> {
219        Ok(deserialize(&self.transaction_get_raw(txid)?)?)
220    }
221
222    /// Batch version of [`transaction_get`](#method.transaction_get).
223    ///
224    /// Takes a list of `txids` and returns a list of transactions.
225    fn batch_transaction_get<'t, I>(&self, txids: I) -> Result<Vec<Transaction>, Error>
226    where
227        I: IntoIterator + Clone,
228        I::Item: Borrow<&'t Txid>,
229    {
230        self.batch_transaction_get_raw(txids)?
231            .iter()
232            .map(|s| Ok(deserialize(s)?))
233            .collect()
234    }
235
236    /// Batch version of [`block_header`](#method.block_header).
237    ///
238    /// Takes a list of `heights` of blocks and returns a list of headers.
239    fn batch_block_header<I>(&self, heights: I) -> Result<Vec<block::Header>, Error>
240    where
241        I: IntoIterator + Clone,
242        I::Item: Borrow<u32>,
243    {
244        self.batch_block_header_raw(heights)?
245            .iter()
246            .map(|s| Ok(deserialize(s)?))
247            .collect()
248    }
249
250    /// Broadcasts a transaction to the network.
251    fn transaction_broadcast(&self, tx: &Transaction) -> Result<Txid, Error> {
252        let buffer: Vec<u8> = serialize(tx);
253        self.transaction_broadcast_raw(&buffer)
254    }
255
256    /// Broadcasts a package of transactions to the network.
257    ///
258    /// The package must consist of a child with its parents, where none of the parents
259    /// depend on one another. The package must be topologically sorted, with the child
260    /// being the last element in the array.
261    ///
262    /// This method was added in protocol v1.6 for package relay support.
263    fn transaction_broadcast_package(
264        &self,
265        txs: &[Transaction],
266    ) -> Result<BroadcastPackageRes, Error> {
267        let raw_txs: Vec<Vec<u8>> = txs.iter().map(serialize).collect();
268        self.transaction_broadcast_package_raw(&raw_txs)
269    }
270
271    /// Executes the requested API call returning the raw answer.
272    fn raw_call(
273        &self,
274        method_name: &str,
275        params: impl IntoIterator<Item = Param>,
276    ) -> Result<serde_json::Value, Error>;
277
278    /// Execute a queue of calls stored in a [`Batch`](../batch/struct.Batch.html) struct. Returns
279    /// `Ok()` **only if** all of the calls are successful. The order of the JSON `Value`s returned
280    /// reflects the order in which the calls were made on the `Batch` struct.
281    fn batch_call(&self, batch: &Batch) -> Result<Vec<serde_json::Value>, Error>;
282
283    /// Subscribes to notifications for new block headers, by sending a `blockchain.headers.subscribe` call and
284    /// returns the current tip as raw bytes instead of deserializing them.
285    fn block_headers_subscribe_raw(&self) -> Result<RawHeaderNotification, Error>;
286
287    /// Tries to pop one queued notification for a new block header that we might have received.
288    /// Returns a the header in raw bytes if a notification is found in the queue, None otherwise.
289    fn block_headers_pop_raw(&self) -> Result<Option<RawHeaderNotification>, Error>;
290
291    /// Gets the raw bytes of block header for height `height`.
292    fn block_header_raw(&self, height: usize) -> Result<Vec<u8>, Error>;
293
294    /// Tries to fetch `count` block headers starting from `start_height`.
295    fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;
296
297    /// Estimates the fee required in **Bitcoin per kilobyte** to confirm a transaction in `number` blocks.
298    ///
299    /// Optionally takes an [`EstimationMode`] parameter to specify the fee estimation mode.
300    /// This parameter was added in protocol v1.6.
301    fn estimate_fee(&self, number: usize, mode: Option<EstimationMode>) -> Result<f64, Error>;
302
303    /// Returns the minimum accepted fee by the server's node in **Bitcoin, not Satoshi**.
304    ///
305    /// **Note:** This method was removed in protocol v1.6+. Use
306    /// [`mempool_get_info`](#method.mempool_get_info) instead, which provides `minrelaytxfee`
307    /// along with additional mempool fee information.
308    fn relay_fee(&self) -> Result<f64, Error>;
309
310    /// Subscribes to notifications for activity on a specific *scriptPubKey*.
311    ///
312    /// Returns a [`ScriptStatus`](../types/type.ScriptStatus.html) when successful that represents
313    /// the current status for the requested script.
314    ///
315    /// Returns [`Error::AlreadySubscribed`](../types/enum.Error.html#variant.AlreadySubscribed) if
316    /// already subscribed to the script.
317    fn script_subscribe(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
318
319    /// Batch version of [`script_subscribe`](#method.script_subscribe).
320    ///
321    /// Takes a list of scripts and returns a list of script status responses.
322    ///
323    /// Note you should pass a reference to a collection because otherwise an expensive clone is made
324    fn batch_script_subscribe<'s, I>(&self, scripts: I) -> Result<Vec<Option<ScriptStatus>>, Error>
325    where
326        I: IntoIterator + Clone,
327        I::Item: Borrow<&'s Script>;
328
329    /// Subscribes to notifications for activity on a specific *scriptPubKey*.
330    ///
331    /// Returns a `bool` with the server response when successful.
332    ///
333    /// Returns [`Error::NotSubscribed`](../types/enum.Error.html#variant.NotSubscribed) if
334    /// not subscribed to the script.
335    fn script_unsubscribe(&self, script: &Script) -> Result<bool, Error>;
336
337    /// Tries to pop one queued notification for a the requested script. Returns `None` if there are no items in the queue.
338    fn script_pop(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
339
340    /// Returns the balance for a *scriptPubKey*.
341    fn script_get_balance(&self, script: &Script) -> Result<GetBalanceRes, Error>;
342
343    /// Batch version of [`script_get_balance`](#method.script_get_balance).
344    ///
345    /// Takes a list of scripts and returns a list of balance responses.
346    fn batch_script_get_balance<'s, I>(&self, scripts: I) -> Result<Vec<GetBalanceRes>, Error>
347    where
348        I: IntoIterator + Clone,
349        I::Item: Borrow<&'s Script>;
350
351    /// Returns the history for a *scriptPubKey*
352    fn script_get_history(&self, script: &Script) -> Result<Vec<GetHistoryRes>, Error>;
353
354    /// Batch version of [`script_get_history`](#method.script_get_history).
355    ///
356    /// Takes a list of scripts and returns a list of history responses.
357    fn batch_script_get_history<'s, I>(&self, scripts: I) -> Result<Vec<Vec<GetHistoryRes>>, Error>
358    where
359        I: IntoIterator + Clone,
360        I::Item: Borrow<&'s Script>;
361
362    /// Returns the list of unspent outputs for a *scriptPubKey*
363    fn script_list_unspent(&self, script: &Script) -> Result<Vec<ListUnspentRes>, Error>;
364
365    /// Batch version of [`script_list_unspent`](#method.script_list_unspent).
366    ///
367    /// Takes a list of scripts and returns a list of a list of utxos.
368    fn batch_script_list_unspent<'s, I>(
369        &self,
370        scripts: I,
371    ) -> Result<Vec<Vec<ListUnspentRes>>, Error>
372    where
373        I: IntoIterator + Clone,
374        I::Item: Borrow<&'s Script>;
375
376    /// Gets the raw bytes of a transaction with `txid`. Returns an error if not found.
377    fn transaction_get_raw(&self, txid: &Txid) -> Result<Vec<u8>, Error>;
378
379    /// Batch version of [`transaction_get_raw`](#method.transaction_get_raw).
380    ///
381    /// Takes a list of `txids` and returns a list of transactions raw bytes.
382    fn batch_transaction_get_raw<'t, I>(&self, txids: I) -> Result<Vec<Vec<u8>>, Error>
383    where
384        I: IntoIterator + Clone,
385        I::Item: Borrow<&'t Txid>;
386
387    /// Batch version of [`block_header_raw`](#method.block_header_raw).
388    ///
389    /// Takes a list of `heights` of blocks and returns a list of block header raw bytes.
390    fn batch_block_header_raw<I>(&self, heights: I) -> Result<Vec<Vec<u8>>, Error>
391    where
392        I: IntoIterator + Clone,
393        I::Item: Borrow<u32>;
394
395    /// Batch version of [`estimate_fee`](#method.estimate_fee).
396    ///
397    /// Takes a list of `numbers` of blocks and returns a list of fee required in
398    /// **Satoshis per kilobyte** to confirm a transaction in the given number of blocks.
399    fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
400    where
401        I: IntoIterator + Clone,
402        I::Item: Borrow<usize>;
403
404    /// Broadcasts the raw bytes of a transaction to the network.
405    fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error>;
406
407    /// Broadcasts a package of raw transactions to the network.
408    ///
409    /// The package must consist of a child with its parents, where none of the parents
410    /// depend on one another. The package must be topologically sorted, with the child
411    /// being the last element in the array.
412    ///
413    /// This method was added in protocol v1.6 for package relay support.
414    fn transaction_broadcast_package_raw<T: AsRef<[u8]>>(
415        &self,
416        raw_txs: &[T],
417    ) -> Result<BroadcastPackageRes, Error>;
418
419    /// Returns the merkle path for the transaction `txid` confirmed in the block at `height`.
420    fn transaction_get_merkle(&self, txid: &Txid, height: usize) -> Result<GetMerkleRes, Error>;
421
422    /// Batch version of [`transaction_get_merkle`](#method.transaction_get_merkle).
423    ///
424    /// Take a list of `(txid, height)`, for transactions with `txid` confirmed in the block at `height`.
425    fn batch_transaction_get_merkle<I>(
426        &self,
427        txids_and_heights: I,
428    ) -> Result<Vec<GetMerkleRes>, Error>
429    where
430        I: IntoIterator + Clone,
431        I::Item: Borrow<(Txid, usize)>;
432
433    /// Returns a transaction hash, given a block `height` and a `tx_pos` in the block.
434    fn txid_from_pos(&self, height: usize, tx_pos: usize) -> Result<Txid, Error>;
435
436    /// Returns a transaction hash and a merkle path, given a block `height` and a `tx_pos` in the
437    /// block.
438    fn txid_from_pos_with_merkle(
439        &self,
440        height: usize,
441        tx_pos: usize,
442    ) -> Result<TxidFromPosRes, Error>;
443
444    /// Returns the capabilities of the server.
445    fn server_features(&self) -> Result<ServerFeaturesRes, Error>;
446
447    /// Returns information about the current state of the mempool.
448    ///
449    /// This method was added in protocol v1.6 and replaces `relay_fee` by providing
450    /// `minrelaytxfee` along with additional mempool fee information.
451    fn mempool_get_info(&self) -> Result<MempoolInfoRes, Error>;
452
453    /// Pings the server. This method can also be used as a "dummy" call to trigger the processing
454    /// of incoming block header or script notifications.
455    fn ping(&self) -> Result<(), Error>;
456
457    /// Returns the number of network calls made since the creation of the client.
458    fn calls_made(&self) -> Result<usize, Error>;
459}
460
461#[cfg(test)]
462mod test {
463    use std::{borrow::Cow, sync::Arc};
464
465    use super::ElectrumApi;
466
467    #[derive(Debug, Clone)]
468    struct FakeApi;
469
470    impl ElectrumApi for FakeApi {
471        fn raw_call(
472            &self,
473            _: &str,
474            _: impl IntoIterator<Item = super::Param>,
475        ) -> Result<serde_json::Value, super::Error> {
476            unreachable!()
477        }
478
479        fn batch_call(&self, _: &crate::Batch) -> Result<Vec<serde_json::Value>, super::Error> {
480            unreachable!()
481        }
482
483        fn block_headers_subscribe_raw(
484            &self,
485        ) -> Result<super::RawHeaderNotification, super::Error> {
486            unreachable!()
487        }
488
489        fn block_headers_pop_raw(
490            &self,
491        ) -> Result<Option<super::RawHeaderNotification>, super::Error> {
492            unreachable!()
493        }
494
495        fn block_header_raw(&self, _: usize) -> Result<Vec<u8>, super::Error> {
496            unreachable!()
497        }
498
499        fn block_headers(&self, _: usize, _: usize) -> Result<super::GetHeadersRes, super::Error> {
500            unreachable!()
501        }
502
503        fn estimate_fee(
504            &self,
505            _: usize,
506            _: Option<super::EstimationMode>,
507        ) -> Result<f64, super::Error> {
508            unreachable!()
509        }
510
511        fn relay_fee(&self) -> Result<f64, super::Error> {
512            unreachable!()
513        }
514
515        fn script_subscribe(
516            &self,
517            _: &bitcoin::Script,
518        ) -> Result<Option<super::ScriptStatus>, super::Error> {
519            unreachable!()
520        }
521
522        fn batch_script_subscribe<'s, I>(
523            &self,
524            _: I,
525        ) -> Result<Vec<Option<super::ScriptStatus>>, super::Error>
526        where
527            I: IntoIterator + Clone,
528            I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
529        {
530            unreachable!()
531        }
532
533        fn script_unsubscribe(&self, _: &bitcoin::Script) -> Result<bool, super::Error> {
534            unreachable!()
535        }
536
537        fn script_pop(
538            &self,
539            _: &bitcoin::Script,
540        ) -> Result<Option<super::ScriptStatus>, super::Error> {
541            unreachable!()
542        }
543
544        fn script_get_balance(
545            &self,
546            _: &bitcoin::Script,
547        ) -> Result<super::GetBalanceRes, super::Error> {
548            unreachable!()
549        }
550
551        fn batch_script_get_balance<'s, I>(
552            &self,
553            _: I,
554        ) -> Result<Vec<super::GetBalanceRes>, super::Error>
555        where
556            I: IntoIterator + Clone,
557            I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
558        {
559            unreachable!()
560        }
561
562        fn script_get_history(
563            &self,
564            _: &bitcoin::Script,
565        ) -> Result<Vec<super::GetHistoryRes>, super::Error> {
566            unreachable!()
567        }
568
569        fn batch_script_get_history<'s, I>(
570            &self,
571            _: I,
572        ) -> Result<Vec<Vec<super::GetHistoryRes>>, super::Error>
573        where
574            I: IntoIterator + Clone,
575            I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
576        {
577            unreachable!()
578        }
579
580        fn script_list_unspent(
581            &self,
582            _: &bitcoin::Script,
583        ) -> Result<Vec<super::ListUnspentRes>, super::Error> {
584            unreachable!()
585        }
586
587        fn batch_script_list_unspent<'s, I>(
588            &self,
589            _: I,
590        ) -> Result<Vec<Vec<super::ListUnspentRes>>, super::Error>
591        where
592            I: IntoIterator + Clone,
593            I::Item: std::borrow::Borrow<&'s bitcoin::Script>,
594        {
595            unreachable!()
596        }
597
598        fn transaction_get_raw(&self, _: &bitcoin::Txid) -> Result<Vec<u8>, super::Error> {
599            unreachable!()
600        }
601
602        fn batch_transaction_get_raw<'t, I>(&self, _: I) -> Result<Vec<Vec<u8>>, super::Error>
603        where
604            I: IntoIterator + Clone,
605            I::Item: std::borrow::Borrow<&'t bitcoin::Txid>,
606        {
607            unreachable!()
608        }
609
610        fn batch_block_header_raw<I>(&self, _: I) -> Result<Vec<Vec<u8>>, super::Error>
611        where
612            I: IntoIterator + Clone,
613            I::Item: std::borrow::Borrow<u32>,
614        {
615            unreachable!()
616        }
617
618        fn batch_estimate_fee<I>(&self, _: I) -> Result<Vec<f64>, super::Error>
619        where
620            I: IntoIterator + Clone,
621            I::Item: std::borrow::Borrow<usize>,
622        {
623            unreachable!()
624        }
625
626        fn transaction_broadcast_raw(&self, _: &[u8]) -> Result<bitcoin::Txid, super::Error> {
627            unreachable!()
628        }
629
630        fn transaction_broadcast_package_raw<T: AsRef<[u8]>>(
631            &self,
632            _: &[T],
633        ) -> Result<super::BroadcastPackageRes, super::Error> {
634            unreachable!()
635        }
636
637        fn transaction_get_merkle(
638            &self,
639            _: &bitcoin::Txid,
640            _: usize,
641        ) -> Result<super::GetMerkleRes, super::Error> {
642            unreachable!()
643        }
644
645        fn batch_transaction_get_merkle<I>(
646            &self,
647            _: I,
648        ) -> Result<Vec<crate::GetMerkleRes>, crate::Error>
649        where
650            I: IntoIterator + Clone,
651            I::Item: std::borrow::Borrow<(bitcoin::Txid, usize)>,
652        {
653            unreachable!()
654        }
655
656        fn txid_from_pos(&self, _: usize, _: usize) -> Result<bitcoin::Txid, super::Error> {
657            unreachable!()
658        }
659
660        fn txid_from_pos_with_merkle(
661            &self,
662            _: usize,
663            _: usize,
664        ) -> Result<super::TxidFromPosRes, super::Error> {
665            unreachable!()
666        }
667
668        fn server_features(&self) -> Result<super::ServerFeaturesRes, super::Error> {
669            unreachable!()
670        }
671
672        fn mempool_get_info(&self) -> Result<super::MempoolInfoRes, super::Error> {
673            unreachable!()
674        }
675
676        fn ping(&self) -> Result<(), super::Error> {
677            unreachable!()
678        }
679
680        fn calls_made(&self) -> Result<usize, super::Error> {
681            unreachable!()
682        }
683    }
684
685    fn is_impl<A: ElectrumApi>() {}
686
687    #[test]
688    fn deref() {
689        is_impl::<FakeApi>();
690        is_impl::<&FakeApi>();
691        is_impl::<Arc<FakeApi>>();
692        is_impl::<Box<FakeApi>>();
693        is_impl::<Cow<FakeApi>>();
694    }
695}