1#![crate_name = "bitcoind_client"]
2
3#![forbid(unsafe_code)]
6#![allow(bare_trait_objects)]
7#![allow(ellipsis_inclusive_range_patterns)]
8#![warn(rustdoc::broken_intra_doc_links)]
9#![warn(missing_docs)]
10
11pub mod bitcoind_client;
13mod convert;
14#[cfg(feature = "dummy-source")]
15pub mod dummy;
17pub mod esplora_client;
19pub mod follower;
21#[cfg(test)]
22mod test_utils;
23pub mod txoo_follower;
25
26pub use self::bitcoind_client::{BitcoindClient, BlockSource};
27pub use self::convert::BlockchainInfo;
28pub use crate::bitcoind_client::bitcoind_client_from_url;
29use crate::esplora_client::EsploraClient;
30use async_trait::async_trait;
31use bitcoin::OutPoint;
32use bitcoin::{Network, Transaction};
33use core::fmt;
34use std::fmt::{Display, Formatter};
35use std::path::PathBuf;
36use url::Url;
37
38#[derive(Debug)]
40pub enum Error {
41 JsonRpc(jsonrpc_async::error::Error),
43 Json(serde_json::error::Error),
45 Io(std::io::Error),
47 Esplora(String),
49}
50
51impl Display for Error {
52 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
53 f.write_str(format!("{:?}", self).as_str())
54 }
55}
56
57impl std::error::Error for Error {}
58
59impl From<jsonrpc_async::error::Error> for Error {
60 fn from(e: jsonrpc_async::error::Error) -> Error {
61 Error::JsonRpc(e)
62 }
63}
64
65impl From<serde_json::error::Error> for Error {
66 fn from(e: serde_json::error::Error) -> Error {
67 Error::Json(e)
68 }
69}
70
71impl From<std::io::Error> for Error {
72 fn from(e: std::io::Error) -> Error {
73 Error::Io(e)
74 }
75}
76
77#[async_trait]
79pub trait Explorer {
80 async fn get_utxo_confirmations(&self, txout: &OutPoint) -> Result<Option<u64>, Error>;
83
84 async fn broadcast_transaction(&self, tx: &Transaction) -> Result<(), Error>;
86
87 async fn get_utxo_spending_tx(&self, txout: &OutPoint) -> Result<Option<Transaction>, Error>;
89}
90
91pub enum BlockExplorerType {
93 Bitcoind,
95 Esplora,
97}
98
99pub async fn explorer_from_url(
101 network: Network,
102 block_explorer_type: BlockExplorerType,
103 url: Url,
104) -> Box<dyn Explorer> {
105 match block_explorer_type {
106 BlockExplorerType::Bitcoind => Box::new(bitcoind_client_from_url(url, network).await),
107 BlockExplorerType::Esplora => Box::new(EsploraClient::new(url).await),
108 }
109}
110
111fn bitcoin_network_path(base_path: PathBuf, network: Network) -> PathBuf {
112 match network {
113 Network::Bitcoin => base_path,
114 Network::Testnet => base_path.join("testnet3"),
115 Network::Signet => base_path.join("signet"),
116 Network::Regtest => base_path.join("regtest"),
117 _ => unreachable!()
118 }
119}
120
121pub fn default_bitcoin_rpc_url(rpc: Option<String>, network: Network) -> String {
123 rpc.unwrap_or_else(|| {
124 match network {
125 Network::Bitcoin => "http://localhost:8332",
126 Network::Testnet => "http://localhost:18332",
127 Network::Signet => "http://localhost:38442",
128 Network::Regtest => "http://localhost:18443",
129 _ => unreachable!(),
130 }
131 .to_owned()
132 })
133}