1use bdk_wallet::bitcoin::Transaction;
2use tokio_util::sync::CancellationToken;
3
4use crate::error::Error;
5
6#[cfg(feature = "bitcoin-rpc")]
7pub mod bitcoin_rpc;
8#[cfg(feature = "esplora")]
9pub mod esplora;
10
11#[derive(Debug, Clone)]
13pub struct BitcoinRpcConfig {
14 pub host: String,
16 pub port: u16,
18 pub user: String,
20 pub password: String,
22}
23
24#[derive(Debug, Clone)]
26pub struct EsploraConfig {
27 pub url: String,
29 pub parallel_requests: usize,
31}
32
33#[derive(Debug, Clone)]
35pub enum ChainSource {
36 #[cfg(feature = "esplora")]
38 Esplora(EsploraConfig),
39 #[cfg(feature = "bitcoin-rpc")]
41 BitcoinRpc(BitcoinRpcConfig),
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub(crate) enum BroadcastOutcome {
47 Accepted,
49 AlreadyKnown,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub(crate) enum BroadcastErrorKind {
56 Rejected,
58 Transient,
60 Unknown,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
66pub(crate) struct BroadcastFailure {
67 pub kind: BroadcastErrorKind,
69 pub message: String,
71}
72
73impl BroadcastFailure {
74 pub(crate) fn new(kind: BroadcastErrorKind, message: String) -> Self {
75 Self { kind, message }
76 }
77}
78
79impl ChainSource {
80 pub async fn sync_wallet(
81 &self,
82 cdk_bdk: &crate::CdkBdk,
83 cancel_token: CancellationToken,
84 ) -> Result<(), Error> {
85 match self {
86 #[cfg(feature = "esplora")]
87 ChainSource::Esplora(config) => {
88 esplora::sync_esplora(cdk_bdk, config, cancel_token).await
89 }
90 #[cfg(feature = "bitcoin-rpc")]
91 ChainSource::BitcoinRpc(config) => {
92 bitcoin_rpc::sync_bitcoin_rpc(cdk_bdk, config, cancel_token).await
93 }
94 #[allow(unreachable_patterns)]
95 _ => unreachable!("ChainSource must have at least one feature enabled"),
96 }
97 }
98
99 pub(crate) async fn broadcast(
100 &self,
101 tx: Transaction,
102 ) -> Result<BroadcastOutcome, BroadcastFailure> {
103 match self {
104 #[cfg(feature = "esplora")]
105 ChainSource::Esplora(config) => esplora::broadcast_esplora(config, tx).await,
106 #[cfg(feature = "bitcoin-rpc")]
107 ChainSource::BitcoinRpc(config) => bitcoin_rpc::broadcast_bitcoin_rpc(config, tx).await,
108 #[allow(unreachable_patterns)]
109 _ => unreachable!("ChainSource must have at least one feature enabled"),
110 }
111 }
112
113 pub async fn fetch_fee_rate(&self, target_blocks: u16) -> Result<f64, Error> {
114 match self {
115 #[cfg(feature = "esplora")]
116 ChainSource::Esplora(config) => {
117 esplora::fetch_fee_rate_esplora(config, target_blocks).await
118 }
119 #[cfg(feature = "bitcoin-rpc")]
120 ChainSource::BitcoinRpc(config) => {
121 bitcoin_rpc::fetch_fee_rate_bitcoin_rpc(config, target_blocks).await
122 }
123 #[allow(unreachable_patterns)]
124 _ => unreachable!("ChainSource must have at least one feature enabled"),
125 }
126 }
127}