]> Untitled Git - bdk/commitdiff
feat(chain)!: use custom return types for `ElectrumExt` methods
author志宇 <hello@evanlinjin.me>
Tue, 7 May 2024 04:43:02 +0000 (12:43 +0800)
committer志宇 <hello@evanlinjin.me>
Fri, 10 May 2024 06:54:29 +0000 (14:54 +0800)
This is more code, but a much more elegant solution than having
`ElectrumExt` methods return `SyncResult`/`FullScanResult` and having an
`ElectrumResultExt` extention trait.

crates/electrum/src/electrum_ext.rs
crates/electrum/tests/test_electrum.rs
example-crates/example_electrum/src/main.rs
example-crates/wallet_electrum/src/main.rs

index 4c6786557cd6444c623688c78e46a4251c367e81..806cabeb2dc4f15af581998cbd09e025db0b2e05 100644 (file)
@@ -29,7 +29,7 @@ pub trait ElectrumExt {
         request: FullScanRequest<K>,
         stop_gap: usize,
         batch_size: usize,
-    ) -> Result<FullScanResult<K, ConfirmationHeightAnchor>, Error>;
+    ) -> Result<ElectrumFullScanResult<K>, Error>;
 
     /// Sync a set of scripts with the blockchain (via an Electrum client) for the data specified
     /// and returns updates for [`bdk_chain`] data structures.
@@ -44,11 +44,7 @@ pub trait ElectrumExt {
     /// may include scripts that have been used, use [`full_scan`] with the keychain.
     ///
     /// [`full_scan`]: ElectrumExt::full_scan
-    fn sync(
-        &self,
-        request: SyncRequest,
-        batch_size: usize,
-    ) -> Result<SyncResult<ConfirmationHeightAnchor>, Error>;
+    fn sync(&self, request: SyncRequest, batch_size: usize) -> Result<ElectrumSyncResult, Error>;
 }
 
 impl<E: ElectrumApi> ElectrumExt for E {
@@ -57,7 +53,7 @@ impl<E: ElectrumApi> ElectrumExt for E {
         mut request: FullScanRequest<K>,
         stop_gap: usize,
         batch_size: usize,
-    ) -> Result<FullScanResult<K, ConfirmationHeightAnchor>, Error> {
+    ) -> Result<ElectrumFullScanResult<K>, Error> {
         let mut request_spks = request.spks_by_keychain;
 
         // 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 {
             };
         };
 
-        Ok(update)
+        Ok(ElectrumFullScanResult(update))
     }
 
-    fn sync(
-        &self,
-        request: SyncRequest,
-        batch_size: usize,
-    ) -> Result<SyncResult<ConfirmationHeightAnchor>, Error> {
+    fn sync(&self, request: SyncRequest, batch_size: usize) -> Result<ElectrumSyncResult, Error> {
         let mut tx_cache = request.tx_cache.clone();
 
         let full_scan_req = FullScanRequest::from_chain_tip(request.chain_tip.clone())
             .cache_txs(request.tx_cache)
             .set_spks_for_keychain((), request.spks.enumerate().map(|(i, spk)| (i as u32, spk)));
-        let mut full_scan_res = self.full_scan(full_scan_req, usize::MAX, batch_size)?;
+        let mut full_scan_res = self
+            .full_scan(full_scan_req, usize::MAX, batch_size)?
+            .with_confirmation_height_anchor();
 
         let (tip, _) = construct_update_tip(self, request.chain_tip)?;
         let cps = tip
@@ -171,53 +165,64 @@ impl<E: ElectrumApi> ElectrumExt for E {
             request.outpoints,
         )?;
 
-        Ok(SyncResult {
+        Ok(ElectrumSyncResult(SyncResult {
             chain_update: full_scan_res.chain_update,
             graph_update: full_scan_res.graph_update,
-        })
+        }))
     }
 }
 
-/// Trait that extends [`SyncResult`] and [`FullScanResult`] functionality.
+/// The result of [`ElectrumExt::full_scan`].
 ///
-/// Currently, only a single method exists that converts the update [`TxGraph`] to have an anchor
-/// type of [`ConfirmationTimeHeightAnchor`].
-pub trait ElectrumResultExt {
-    /// New result type with a [`TxGraph`] that contains the [`ConfirmationTimeHeightAnchor`].
-    type NewResult;
-
-    /// Convert result type to have an update [`TxGraph`]  that contains the [`ConfirmationTimeHeightAnchor`] .
-    fn try_into_confirmation_time_result(
-        self,
-        client: &impl ElectrumApi,
-    ) -> Result<Self::NewResult, Error>;
-}
-
-impl<K> ElectrumResultExt for FullScanResult<K, ConfirmationHeightAnchor> {
-    type NewResult = FullScanResult<K, ConfirmationTimeHeightAnchor>;
+/// This can be transformed into a [`FullScanResult`] with either [`ConfirmationHeightAnchor`] or
+/// [`ConfirmationTimeHeightAnchor`] anchor types.
+pub struct ElectrumFullScanResult<K>(FullScanResult<K, ConfirmationHeightAnchor>);
+
+impl<K> ElectrumFullScanResult<K> {
+    /// Return [`FullScanResult`] with [`ConfirmationHeightAnchor`].
+    pub fn with_confirmation_height_anchor(self) -> FullScanResult<K, ConfirmationHeightAnchor> {
+        self.0
+    }
 
-    fn try_into_confirmation_time_result(
+    /// Return [`FullScanResult`] with [`ConfirmationTimeHeightAnchor`].
+    ///
+    /// This requires additional calls to the Electrum server.
+    pub fn with_confirmation_time_height_anchor(
         self,
         client: &impl ElectrumApi,
-    ) -> Result<Self::NewResult, Error> {
-        Ok(FullScanResult::<K, ConfirmationTimeHeightAnchor> {
-            graph_update: try_into_confirmation_time_result(self.graph_update, client)?,
-            chain_update: self.chain_update,
-            last_active_indices: self.last_active_indices,
+    ) -> Result<FullScanResult<K, ConfirmationTimeHeightAnchor>, Error> {
+        let res = self.0;
+        Ok(FullScanResult {
+            graph_update: try_into_confirmation_time_result(res.graph_update, client)?,
+            chain_update: res.chain_update,
+            last_active_indices: res.last_active_indices,
         })
     }
 }
 
-impl ElectrumResultExt for SyncResult<ConfirmationHeightAnchor> {
-    type NewResult = SyncResult<ConfirmationTimeHeightAnchor>;
+/// The result of [`ElectrumExt::sync`].
+///
+/// This can be transformed into a [`SyncResult`] with either [`ConfirmationHeightAnchor`] or
+/// [`ConfirmationTimeHeightAnchor`] anchor types.
+pub struct ElectrumSyncResult(SyncResult<ConfirmationHeightAnchor>);
+
+impl ElectrumSyncResult {
+    /// Return [`SyncResult`] with [`ConfirmationHeightAnchor`].
+    pub fn with_confirmation_height_anchor(self) -> SyncResult<ConfirmationHeightAnchor> {
+        self.0
+    }
 
-    fn try_into_confirmation_time_result(
+    /// Return [`SyncResult`] with [`ConfirmationTimeHeightAnchor`].
+    ///
+    /// This requires additional calls to the Electrum server.
+    pub fn with_confirmation_time_height_anchor(
         self,
         client: &impl ElectrumApi,
-    ) -> Result<Self::NewResult, Error> {
+    ) -> Result<SyncResult<ConfirmationTimeHeightAnchor>, Error> {
+        let res = self.0;
         Ok(SyncResult {
-            graph_update: try_into_confirmation_time_result(self.graph_update, client)?,
-            chain_update: self.chain_update,
+            graph_update: try_into_confirmation_time_result(res.graph_update, client)?,
+            chain_update: res.chain_update,
         })
     }
 }
index aa4b87933cc4e48be6cca1d54fafb392cc250101..9905ab9cc268a0ec698f3e0fa49c1a53574514ab 100644 (file)
@@ -5,7 +5,7 @@ use bdk_chain::{
     spk_client::SyncRequest,
     ConfirmationTimeHeightAnchor, IndexedTxGraph, SpkTxOutIndex,
 };
-use bdk_electrum::{ElectrumExt, ElectrumResultExt};
+use bdk_electrum::ElectrumExt;
 use bdk_testenv::{anyhow, anyhow::Result, bitcoincore_rpc::RpcApi, TestEnv};
 
 fn get_balance(
@@ -67,7 +67,7 @@ fn scan_detects_confirmed_tx() -> Result<()> {
                 .chain_spks(core::iter::once(spk_to_track)),
             5,
         )?
-        .try_into_confirmation_time_result(&client)?;
+        .with_confirmation_time_height_anchor(&client)?;
 
     let _ = recv_chain
         .apply_update(update.chain_update)
@@ -133,7 +133,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> Result<()> {
             SyncRequest::from_chain_tip(recv_chain.tip()).chain_spks([spk_to_track.clone()]),
             5,
         )?
-        .try_into_confirmation_time_result(&client)?;
+        .with_confirmation_time_height_anchor(&client)?;
 
     let _ = recv_chain
         .apply_update(update.chain_update)
@@ -163,7 +163,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> Result<()> {
                 SyncRequest::from_chain_tip(recv_chain.tip()).chain_spks([spk_to_track.clone()]),
                 5,
             )?
-            .try_into_confirmation_time_result(&client)?;
+            .with_confirmation_time_height_anchor(&client)?;
 
         let _ = recv_chain
             .apply_update(update.chain_update)
index 58474668f5a95a609840dc101a9859427b5cdf24..237d140a1d3fa78d8d3b7575ebb1c375ba545880 100644 (file)
@@ -191,7 +191,8 @@ fn main() -> anyhow::Result<()> {
 
             let res = client
                 .full_scan::<_>(request, stop_gap, scan_options.batch_size)
-                .context("scanning the blockchain")?;
+                .context("scanning the blockchain")?
+                .with_confirmation_height_anchor();
             (
                 res.chain_update,
                 res.graph_update,
@@ -311,7 +312,8 @@ fn main() -> anyhow::Result<()> {
 
             let res = client
                 .sync(request, scan_options.batch_size)
-                .context("scanning the blockchain")?;
+                .context("scanning the blockchain")?
+                .with_confirmation_height_anchor();
 
             // drop lock on graph and chain
             drop((graph, chain));
index e1fe009847b574b12f97e2233fd17958ee47ad05..a9b194ce807eda1ffb5399e6dae27964f451162e 100644 (file)
@@ -10,7 +10,6 @@ use bdk::bitcoin::{Address, Amount};
 use bdk::chain::collections::HashSet;
 use bdk::{bitcoin::Network, Wallet};
 use bdk::{KeychainKind, SignOptions};
-use bdk_electrum::ElectrumResultExt;
 use bdk_electrum::{
     electrum_client::{self, ElectrumApi},
     ElectrumExt,
@@ -55,7 +54,7 @@ fn main() -> Result<(), anyhow::Error> {
 
     let mut update = client
         .full_scan(request, STOP_GAP, BATCH_SIZE)?
-        .try_into_confirmation_time_result(&client)?;
+        .with_confirmation_time_height_anchor(&client)?;
 
     let now = std::time::UNIX_EPOCH.elapsed().unwrap().as_secs();
     let _ = update.graph_update.update_last_seen_unconfirmed(now);