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