Skip to content

Sync a Wallet with Esplora

Syncing with Esplora uses what we refer to as SPK-based syncing (see our Full Scan vs Sync page for more information on this).

The workflow for a full scan or sync consists of a 3-step process:

  1. Ask the wallet for the data structure required.
  2. Pass it to your blockchain client and request a full scan or sync.
  3. The client returns an update, which you then apply to the wallet.

This workflow ensures that the wallet structure is not blocked while the syncing operation is performed.

Add required bdk dependencies to your Cargo.toml file

Cargo.toml
1
2
3
4
[dependencies]
bdk_wallet = { version = "1.0.0" }
bdk_esplora = { version = "0.20.1", features = ["blocking"] }
anyhow = "1"

Create and sync the wallet

main.rs
use anyhow::Error;
use bdk_esplora::esplora_client::Builder;
use bdk_esplora::{esplora_client, EsploraExt};
use bdk_wallet::bitcoin::Network;
use bdk_wallet::chain::spk_client::{
    FullScanRequestBuilder, FullScanResponse, SyncRequestBuilder, SyncResponse,
};
use bdk_wallet::AddressInfo;
use bdk_wallet::KeychainKind;
use bdk_wallet::Wallet;

const STOP_GAP: usize = 50;
const PARALLEL_REQUESTS: usize = 1;
const EXTERNAL_DESCRIPTOR: &str = "tr(tprv8ZgxMBicQKsPdrjwWCyXqqJ4YqcyG4DmKtjjsRt29v1PtD3r3PuFJAjWytzcvSTKnZAGAkPSmnrdnuHWxCAwy3i1iPhrtKAfXRH7dVCNGp6/86'/1'/0'/0/*)#g9xn7wf9";
const INTERNAL_DESCRIPTOR: &str = "tr(tprv8ZgxMBicQKsPdrjwWCyXqqJ4YqcyG4DmKtjjsRt29v1PtD3r3PuFJAjWytzcvSTKnZAGAkPSmnrdnuHWxCAwy3i1iPhrtKAfXRH7dVCNGp6/86'/1'/0'/1/*)#e3rjrmea";

fn main() -> Result<(), Error> {
    let mut wallet: Wallet = Wallet::create(EXTERNAL_DESCRIPTOR, INTERNAL_DESCRIPTOR)
        .network(Network::Signet)
        .create_wallet_no_persist()?;

    let address: AddressInfo = wallet.reveal_next_address(KeychainKind::External);
    println!(
        "Generated address {} at index {}",
        address.address, address.index
    );

    // Create the Esplora client
    let client: esplora_client::BlockingClient =
        Builder::new("http://signet.bitcoindevkit.net").build_blocking();

    // Full scan the wallet
    let full_scan_request: FullScanRequestBuilder<KeychainKind> = wallet.start_full_scan();
    let full_scan_response: FullScanResponse<KeychainKind> =
        client.full_scan(full_scan_request, STOP_GAP, PARALLEL_REQUESTS)?;

    // Apply the full scan response to the wallet
    wallet.apply_update(full_scan_response)?;

    // Sync the wallet
    let sync_request: SyncRequestBuilder<(KeychainKind, u32)> =
        wallet.start_sync_with_revealed_spks();
    let sync_response: SyncResponse = client.sync(sync_request, PARALLEL_REQUESTS)?;

    // Apply the sync response to the wallet
    wallet.apply_update(sync_response)?;

    let balance = wallet.balance();
    println!("Wallet balance: {} sat", balance.total().to_sat());

    Ok(())
}