Skip to content

Commit

Permalink
Temp 20: Add blocking esplora client with scan method
Browse files Browse the repository at this point in the history
  • Loading branch information
thunderbiscuit committed Oct 12, 2023
1 parent 6589695 commit 4c8818c
Show file tree
Hide file tree
Showing 8 changed files with 1,231 additions and 94 deletions.
1,143 changes: 1,103 additions & 40 deletions bdk-ffi/Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions bdk-ffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bdk-ffi"
version = "1.0.0-alpha.1"
version = "1.0.0-alpha.2"
authors = ["Steve Myers <[email protected]>", "Sudarsan Balaji <[email protected]>"]
edition = "2018"
license = "MIT OR Apache-2.0"
Expand All @@ -17,9 +17,9 @@ path = "uniffi-bindgen.rs"
default = ["uniffi/cli"]

[dependencies]
bdk = { git = "https://github.com/bitcoindevkit/bdk.git", rev = "59fc1b341ba94212b2ea3e888e51fb6fcd00589f", features = ["all-keys", "keys-bip39"] }
bdk_file_store = { git = "https://github.com/bitcoindevkit/bdk.git", rev = "59fc1b341ba94212b2ea3e888e51fb6fcd00589f" }
# bdk_chain = { git = "https://github.com/bitcoindevkit/bdk.git", rev = "59fc1b341ba94212b2ea3e888e51fb6fcd00589f" }
bdk = { version = "1.0.0-alpha.2", features = ["all-keys", "keys-bip39"] }
bdk_file_store = { version = "0.2.0" }
bdk_esplora = { version = "0.4.0" }
uniffi = { version = "=0.23.0" }

[build-dependencies]
Expand Down
50 changes: 34 additions & 16 deletions bdk-ffi/src/bdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ enum BdkError {
"Psbt",
};



enum Network {
"Bitcoin",
"Testnet",
Expand Down Expand Up @@ -132,22 +134,6 @@ interface Descriptor {
string as_string_private();
};

interface Wallet {
[Throws=BdkError]
constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network, WalletType wallet_type);

AddressInfo get_address(AddressIndex address_index);

Network network();

Balance get_balance();
};

enum WalletType {
"Memory",
"FlatFile",
};

interface Address {
[Throws=BdkError]
constructor(string address, Network network);
Expand Down Expand Up @@ -185,3 +171,35 @@ interface Balance {

u64 total();
};

interface EsploraClient {
constructor(string url);

[Throws=BdkError]
Update scan(Wallet wallet, u64 stop_gap, u64 parallel_requests);
};

// ------------------------------------------------------------------------
// Wallet crate
// ------------------------------------------------------------------------

interface Wallet {
[Throws=BdkError]
constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network, WalletType wallet_type);

AddressInfo get_address(AddressIndex address_index);

Network network();

Balance get_balance();

[Throws=BdkError]
void apply_update(Update update);
};

enum WalletType {
"Memory",
"FlatFile",
};

interface Update {};
2 changes: 1 addition & 1 deletion bdk-ffi/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::keys::DescriptorSecretKey;
use crate::Network;

#[derive(Debug)]
pub(crate) struct Descriptor {
pub struct Descriptor {
pub extended_descriptor: ExtendedDescriptor,
pub key_map: KeyMap,
}
Expand Down
59 changes: 59 additions & 0 deletions bdk-ffi/src/esplora.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::wallet::Update;
use crate::wallet::Wallet;
use bdk::wallet::Update as BdkUpdate;
use bdk::Error as BdkError;
use bdk_esplora::esplora_client::{BlockingClient, Builder};
use bdk_esplora::EsploraExt;
use std::sync::Arc;

pub struct EsploraClient(BlockingClient);

impl EsploraClient {
pub fn new(url: String) -> Self {
let client = Builder::new(url.as_str()).build_blocking().unwrap();
Self(client)
}

pub fn scan(
&self,
wallet: Arc<Wallet>,
stop_gap: u64,
parallel_requests: u64,
) -> Result<Arc<Update>, BdkError> {
let wallet = wallet.get_wallet();

let previous_tip = wallet.latest_checkpoint();
let keychain_spks = wallet.spks_of_all_keychains().into_iter().collect();

let (update_graph, last_active_indices) = self
.0
.scan_txs_with_keychains(
keychain_spks,
None,
None,
stop_gap as usize,
parallel_requests as usize,
)
.unwrap();

let missing_heights = update_graph.missing_heights(wallet.local_chain());
let chain_update = self
.0
.update_local_chain(previous_tip, missing_heights)
.unwrap();

let update = BdkUpdate {
last_active_indices,
graph: update_graph,
chain: Some(chain_update),
};

Ok(Arc::new(Update(update)))
}

// pub fn sync();

// pub fn broadcast();

// pub fn estimate_fee();
}
4 changes: 4 additions & 0 deletions bdk-ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod blockchain;
mod database;
mod descriptor;
mod esplora;
mod keys;
mod psbt;
mod wallet;
Expand All @@ -17,13 +18,16 @@ use std::sync::Arc;

// TODO 6: Why are these imports required?
use crate::descriptor::Descriptor;
use crate::esplora::EsploraClient;
use crate::keys::DerivationPath;
use crate::keys::DescriptorPublicKey;
use crate::keys::DescriptorSecretKey;
use crate::keys::Mnemonic;
use crate::wallet::Update;
use crate::wallet::Wallet;
use crate::wallet::WalletType;
use bdk::keys::bip39::WordCount;
// use bdk_esplora::EsploraExt;

uniffi::include_scaffolding!("bdk");

Expand Down
48 changes: 15 additions & 33 deletions bdk-ffi/src/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,15 @@
// use bdk::bitcoin::blockdata::script::Script as BdkScript;
// use bdk::bitcoin::{Address as BdkAddress, Network, OutPoint as BdkOutPoint, Sequence, Txid};
// // use bdk::database::any::AnyDatabase;
// // use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
// use bdk::wallet::tx_builder::ChangeSpendPolicy;
// use bdk::{
// FeeRate, LocalUtxo as BdkLocalUtxo,
// SignOptions as BdkSignOptions,
// // SyncOptions as BdkSyncOptions,
// Wallet as BdkWallet,
// };
// use std::collections::HashSet;
// use std::ops::Deref;
// use std::str::FromStr;
// use std::sync::{Arc, Mutex, MutexGuard};
// use bdk::chain::PersistBackend;
// // use bdk::wallet::ChangeSet;
// // use bdk_file_store::Store;
// use bdk::wallet::AddressIndex as BdkAddressIndex;
// use bdk::wallet::AddressInfo as BdkAddressInfo;
//
// use crate::blockchain::Blockchain;
// // use crate::database::DatabaseConfig;
// use crate::descriptor::Descriptor;
// use crate::psbt::PartiallySignedTransaction;
// use crate::{
// AddressIndex, AddressInfo, Balance, BdkError, LocalUtxo, OutPoint, Progress, ProgressHolder,
// RbfValue, Script, ScriptAmount, TransactionDetails, TxBuilderResult,
// };

use crate::descriptor::Descriptor;
use crate::Balance;
use crate::{AddressIndex, AddressInfo, Network};
use bdk::wallet::Update as BdkUpdate;
use bdk::Error as BdkError;
use bdk::Wallet as BdkWallet;
use std::sync::{Arc, Mutex, MutexGuard};

#[derive(Debug)]
pub(crate) struct Wallet {
pub struct Wallet {
// TODO 8: Do we really need the mutex on the wallet? Could this be an Arc?
pub inner_mutex: Mutex<BdkWallet>,
inner_mutex: Mutex<BdkWallet>,
}

pub enum WalletType {
Expand Down Expand Up @@ -74,7 +45,7 @@ impl Wallet {
}

// TODO 10: Do we need this mutex
fn get_wallet(&self) -> MutexGuard<BdkWallet> {
pub(crate) fn get_wallet(&self) -> MutexGuard<BdkWallet> {
self.inner_mutex.lock().expect("wallet")
}

Expand Down Expand Up @@ -105,11 +76,22 @@ impl Wallet {
Arc::new(balance)
}

pub fn apply_update(&self, update: Arc<Update>) -> Result<(), BdkError> {
// self.get_wallet(). .apply_update(update.0).map_err(|e| BdkError::Generic(e.to_string()))
self.get_wallet()
.apply_update(update.0.clone())
.map_err(|e| BdkError::Generic(e.to_string()))
}

// pub fn commit(&self) -> Result<(), BdkError> {}

// fn is_mine(&self, script: Arc<Script>) -> bool {
// self.get_wallet().is_mine(&script.inner)
// }
}

pub struct Update(pub(crate) BdkUpdate);

// /// A Bitcoin wallet.
// /// The Wallet acts as a way of coherently interfacing with output descriptors and related transactions. Its main components are:
// /// 1. Output descriptors from which it can derive addresses.
Expand Down
11 changes: 11 additions & 0 deletions bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/WalletTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,15 @@ class WalletTest {

assert(wallet.getBalance().total() == 0uL)
}

@Test
fun testSyncedBalance() {
val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
val wallet = Wallet(descriptor, null, Network.TESTNET, WalletType.MEMORY)
val esploraClient = EsploraClient("https://mempool.space/testnet/api")
// val esploraClient = EsploraClient("https://blockstream.info/testnet/api")
val update = esploraClient.scan(wallet, 10uL, 1uL)
wallet.applyUpdate(update)
println("Balance: ${wallet.getBalance().total()}")
}
}

0 comments on commit 4c8818c

Please sign in to comment.