Skip to content

Commit 7a69d35

Browse files
committed
feat(chain)!: use custom return types for ElectrumExt methods
This is more code, but a much more elegant solution than having `ElectrumExt` methods return `SyncResult`/`FullScanResult` and having an `ElectrumResultExt` extention trait.
1 parent fba125f commit 7a69d35

File tree

4 files changed

+58
-52
lines changed

4 files changed

+58
-52
lines changed

crates/electrum/src/electrum_ext.rs

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub trait ElectrumExt {
2929
request: FullScanRequest<K>,
3030
stop_gap: usize,
3131
batch_size: usize,
32-
) -> Result<FullScanResult<K, ConfirmationHeightAnchor>, Error>;
32+
) -> Result<ElectrumFullScanResult<K>, Error>;
3333

3434
/// Sync a set of scripts with the blockchain (via an Electrum client) for the data specified
3535
/// and returns updates for [`bdk_chain`] data structures.
@@ -44,11 +44,7 @@ pub trait ElectrumExt {
4444
/// may include scripts that have been used, use [`full_scan`] with the keychain.
4545
///
4646
/// [`full_scan`]: ElectrumExt::full_scan
47-
fn sync(
48-
&self,
49-
request: SyncRequest,
50-
batch_size: usize,
51-
) -> Result<SyncResult<ConfirmationHeightAnchor>, Error>;
47+
fn sync(&self, request: SyncRequest, batch_size: usize) -> Result<ElectrumSyncResult, Error>;
5248
}
5349

5450
impl<E: ElectrumApi> ElectrumExt for E {
@@ -57,7 +53,7 @@ impl<E: ElectrumApi> ElectrumExt for E {
5753
mut request: FullScanRequest<K>,
5854
stop_gap: usize,
5955
batch_size: usize,
60-
) -> Result<FullScanResult<K, ConfirmationHeightAnchor>, Error> {
56+
) -> Result<ElectrumFullScanResult<K>, Error> {
6157
let mut request_spks = request.spks_by_keychain;
6258

6359
// We keep track of already-scanned spks just in case a reorg happens and we need to do a
@@ -134,20 +130,18 @@ impl<E: ElectrumApi> ElectrumExt for E {
134130
};
135131
};
136132

137-
Ok(update)
133+
Ok(ElectrumFullScanResult(update))
138134
}
139135

140-
fn sync(
141-
&self,
142-
request: SyncRequest,
143-
batch_size: usize,
144-
) -> Result<SyncResult<ConfirmationHeightAnchor>, Error> {
136+
fn sync(&self, request: SyncRequest, batch_size: usize) -> Result<ElectrumSyncResult, Error> {
145137
let mut tx_cache = request.tx_cache.clone();
146138

147139
let full_scan_req = FullScanRequest::from_chain_tip(request.chain_tip.clone())
148140
.cache_txs(request.tx_cache)
149141
.set_spks_for_keychain((), request.spks.enumerate().map(|(i, spk)| (i as u32, spk)));
150-
let mut full_scan_res = self.full_scan(full_scan_req, usize::MAX, batch_size)?;
142+
let mut full_scan_res = self
143+
.full_scan(full_scan_req, usize::MAX, batch_size)?
144+
.with_confirmation_height_anchor();
151145

152146
let (tip, _) = construct_update_tip(self, request.chain_tip)?;
153147
let cps = tip
@@ -171,53 +165,64 @@ impl<E: ElectrumApi> ElectrumExt for E {
171165
request.outpoints,
172166
)?;
173167

174-
Ok(SyncResult {
168+
Ok(ElectrumSyncResult(SyncResult {
175169
chain_update: full_scan_res.chain_update,
176170
graph_update: full_scan_res.graph_update,
177-
})
171+
}))
178172
}
179173
}
180174

181-
/// Trait that extends [`SyncResult`] and [`FullScanResult`] functionality.
175+
/// The result of [`ElectrumExt::full_scan`].
182176
///
183-
/// Currently, only a single method exists that converts the update [`TxGraph`] to have an anchor
184-
/// type of [`ConfirmationTimeHeightAnchor`].
185-
pub trait ElectrumResultExt {
186-
/// New result type with a [`TxGraph`] that contains the [`ConfirmationTimeHeightAnchor`].
187-
type NewResult;
188-
189-
/// Convert result type to have an update [`TxGraph`] that contains the [`ConfirmationTimeHeightAnchor`] .
190-
fn try_into_confirmation_time_result(
191-
self,
192-
client: &impl ElectrumApi,
193-
) -> Result<Self::NewResult, Error>;
194-
}
195-
196-
impl<K> ElectrumResultExt for FullScanResult<K, ConfirmationHeightAnchor> {
197-
type NewResult = FullScanResult<K, ConfirmationTimeHeightAnchor>;
177+
/// This can be transformed into a [`FullScanResult`] with either [`ConfirmationHeightAnchor`] or
178+
/// [`ConfirmationTimeHeightAnchor`] anchor types.
179+
pub struct ElectrumFullScanResult<K>(FullScanResult<K, ConfirmationHeightAnchor>);
180+
181+
impl<K> ElectrumFullScanResult<K> {
182+
/// Return [`FullScanResult`] with [`ConfirmationHeightAnchor`].
183+
pub fn with_confirmation_height_anchor(self) -> FullScanResult<K, ConfirmationHeightAnchor> {
184+
self.0
185+
}
198186

199-
fn try_into_confirmation_time_result(
187+
/// Return [`FullScanResult`] with [`ConfirmationTimeHeightAnchor`].
188+
///
189+
/// This requires additional calls to the Electrum server.
190+
pub fn with_confirmation_time_height_anchor(
200191
self,
201192
client: &impl ElectrumApi,
202-
) -> Result<Self::NewResult, Error> {
203-
Ok(FullScanResult::<K, ConfirmationTimeHeightAnchor> {
204-
graph_update: try_into_confirmation_time_result(self.graph_update, client)?,
205-
chain_update: self.chain_update,
206-
last_active_indices: self.last_active_indices,
193+
) -> Result<FullScanResult<K, ConfirmationTimeHeightAnchor>, Error> {
194+
let res = self.0;
195+
Ok(FullScanResult {
196+
graph_update: try_into_confirmation_time_result(res.graph_update, client)?,
197+
chain_update: res.chain_update,
198+
last_active_indices: res.last_active_indices,
207199
})
208200
}
209201
}
210202

211-
impl ElectrumResultExt for SyncResult<ConfirmationHeightAnchor> {
212-
type NewResult = SyncResult<ConfirmationTimeHeightAnchor>;
203+
/// The result of [`ElectrumExt::sync`].
204+
///
205+
/// This can be transformed into a [`SyncResult`] with either [`ConfirmationHeightAnchor`] or
206+
/// [`ConfirmationTimeHeightAnchor`] anchor types.
207+
pub struct ElectrumSyncResult(SyncResult<ConfirmationHeightAnchor>);
208+
209+
impl ElectrumSyncResult {
210+
/// Return [`SyncResult`] with [`ConfirmationHeightAnchor`].
211+
pub fn with_confirmation_height_anchor(self) -> SyncResult<ConfirmationHeightAnchor> {
212+
self.0
213+
}
213214

214-
fn try_into_confirmation_time_result(
215+
/// Return [`SyncResult`] with [`ConfirmationTimeHeightAnchor`].
216+
///
217+
/// This requires additional calls to the Electrum server.
218+
pub fn with_confirmation_time_height_anchor(
215219
self,
216220
client: &impl ElectrumApi,
217-
) -> Result<Self::NewResult, Error> {
221+
) -> Result<SyncResult<ConfirmationTimeHeightAnchor>, Error> {
222+
let res = self.0;
218223
Ok(SyncResult {
219-
graph_update: try_into_confirmation_time_result(self.graph_update, client)?,
220-
chain_update: self.chain_update,
224+
graph_update: try_into_confirmation_time_result(res.graph_update, client)?,
225+
chain_update: res.chain_update,
221226
})
222227
}
223228
}

crates/electrum/tests/test_electrum.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use bdk_chain::{
55
spk_client::SyncRequest,
66
ConfirmationTimeHeightAnchor, IndexedTxGraph, SpkTxOutIndex,
77
};
8-
use bdk_electrum::{ElectrumExt, ElectrumResultExt};
8+
use bdk_electrum::ElectrumExt;
99
use bdk_testenv::{anyhow, anyhow::Result, bitcoincore_rpc::RpcApi, TestEnv};
1010

1111
fn get_balance(
@@ -67,7 +67,7 @@ fn scan_detects_confirmed_tx() -> Result<()> {
6767
.chain_spks(core::iter::once(spk_to_track)),
6868
5,
6969
)?
70-
.try_into_confirmation_time_result(&client)?;
70+
.with_confirmation_time_height_anchor(&client)?;
7171

7272
let _ = recv_chain
7373
.apply_update(update.chain_update)
@@ -133,7 +133,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> Result<()> {
133133
SyncRequest::from_chain_tip(recv_chain.tip()).chain_spks([spk_to_track.clone()]),
134134
5,
135135
)?
136-
.try_into_confirmation_time_result(&client)?;
136+
.with_confirmation_time_height_anchor(&client)?;
137137

138138
let _ = recv_chain
139139
.apply_update(update.chain_update)
@@ -163,7 +163,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> Result<()> {
163163
SyncRequest::from_chain_tip(recv_chain.tip()).chain_spks([spk_to_track.clone()]),
164164
5,
165165
)?
166-
.try_into_confirmation_time_result(&client)?;
166+
.with_confirmation_time_height_anchor(&client)?;
167167

168168
let _ = recv_chain
169169
.apply_update(update.chain_update)

example-crates/example_electrum/src/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ fn main() -> anyhow::Result<()> {
183183

184184
let res = client
185185
.full_scan::<_>(request, stop_gap, scan_options.batch_size)
186-
.context("scanning the blockchain")?;
186+
.context("scanning the blockchain")?
187+
.with_confirmation_height_anchor();
187188
(
188189
res.chain_update,
189190
res.graph_update,
@@ -303,7 +304,8 @@ fn main() -> anyhow::Result<()> {
303304

304305
let res = client
305306
.sync(request, scan_options.batch_size)
306-
.context("scanning the blockchain")?;
307+
.context("scanning the blockchain")?
308+
.with_confirmation_height_anchor();
307309

308310
// drop lock on graph and chain
309311
drop((graph, chain));

example-crates/wallet_electrum/src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use bdk::bitcoin::{Address, Amount};
1010
use bdk::chain::collections::HashSet;
1111
use bdk::{bitcoin::Network, Wallet};
1212
use bdk::{KeychainKind, SignOptions};
13-
use bdk_electrum::ElectrumResultExt;
1413
use bdk_electrum::{
1514
electrum_client::{self, ElectrumApi},
1615
ElectrumExt,
@@ -55,7 +54,7 @@ fn main() -> Result<(), anyhow::Error> {
5554

5655
let mut update = client
5756
.full_scan(request, STOP_GAP, BATCH_SIZE)?
58-
.try_into_confirmation_time_result(&client)?;
57+
.with_confirmation_time_height_anchor(&client)?;
5958

6059
let now = std::time::UNIX_EPOCH.elapsed().unwrap().as_secs();
6160
let _ = update.graph_update.update_last_seen_unconfirmed(now);

0 commit comments

Comments
 (0)