feat(wallet): add scan method on blocking esplora client

This commit is contained in:
thunderbiscuit 2023-10-23 14:14:39 -04:00
parent 7463fa7720
commit 00cd55bb46
No known key found for this signature in database
GPG Key ID: 88253696EB836462
7 changed files with 137 additions and 69 deletions

56
bdk-ffi/Cargo.lock generated
View File

@ -90,9 +90,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.4"
version = "0.21.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
[[package]]
name = "bdk"
@ -248,9 +248,9 @@ dependencies = [
[[package]]
name = "cargo-platform"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479"
checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36"
dependencies = [
"serde",
]
@ -463,9 +463,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.148"
version = "0.2.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
[[package]]
name = "log"
@ -551,9 +551,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "os_str_bytes"
version = "6.5.1"
version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
[[package]]
name = "paste"
@ -605,9 +605,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.67"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
@ -717,7 +717,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
"syn 2.0.38",
]
[[package]]
@ -753,31 +753,31 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.188"
version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.188"
version = "1.0.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
"syn 2.0.38",
]
[[package]]
@ -848,9 +848,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.37"
version = "2.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
dependencies = [
"proc-macro2",
"quote",
@ -874,22 +874,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
version = "1.0.49"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.49"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
"syn 2.0.38",
]
[[package]]
@ -1064,7 +1064,7 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3"
dependencies = [
"base64 0.21.4",
"base64 0.21.5",
"flate2",
"log",
"once_cell",
@ -1121,7 +1121,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.37",
"syn 2.0.38",
"wasm-bindgen-shared",
]
@ -1143,7 +1143,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
"syn 2.0.38",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]

View File

@ -86,36 +86,6 @@ interface Wallet {
interface Update {};
// ------------------------------------------------------------------------
// bdk crate - bitcoin reexports
// ------------------------------------------------------------------------
enum Network {
"Bitcoin",
"Testnet",
"Signet",
"Regtest",
};
enum WordCount {
"Words12",
"Words15",
"Words18",
"Words21",
"Words24",
};
interface Address {
[Throws=BdkError]
constructor(string address, Network network);
Network network();
string to_qr_uri();
string as_string();
};
// ------------------------------------------------------------------------
// bdk crate - descriptor module
// ------------------------------------------------------------------------
@ -208,4 +178,43 @@ interface Descriptor {
interface EsploraClient {
constructor(string url);
[Throws=BdkError]
Update scan(Wallet wallet, u64 stop_gap, u64 parallel_requests);
};
// ------------------------------------------------------------------------
// bdk crate - bitcoin re-exports
// ------------------------------------------------------------------------
interface Script {
constructor(sequence<u8> raw_output_script);
sequence<u8> to_bytes();
};
enum Network {
"Bitcoin",
"Testnet",
"Signet",
"Regtest",
};
enum WordCount {
"Words12",
"Words15",
"Words18",
"Words21",
"Words24",
};
interface Address {
[Throws=BdkError]
constructor(string address, Network network);
Network network();
string to_qr_uri();
string as_string();
};

22
bdk-ffi/src/bitcoin.rs Normal file
View File

@ -0,0 +1,22 @@
use bdk::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf;
/// A Bitcoin script.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Script(pub(crate) BdkScriptBuf);
impl Script {
pub fn new(raw_output_script: Vec<u8>) -> Self {
let script: BdkScriptBuf = raw_output_script.into();
Script(script)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes()
}
}
impl From<BdkScriptBuf> for Script {
fn from(script: BdkScriptBuf) -> Self {
Script(script)
}
}

View File

@ -1,4 +1,9 @@
use crate::wallet::{Update, 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);
@ -8,7 +13,44 @@ impl EsploraClient {
Self(client)
}
// pub fn scan();
// This is a temporary solution for scanning. The long-term solution involves not passing
// the wallet to the client at all.
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();

View File

@ -1,3 +1,4 @@
mod bitcoin;
mod descriptor;
mod esplora;
mod keys;
@ -15,6 +16,7 @@ use bdk::KeychainKind;
use std::sync::Arc;
// TODO 6: Why are these imports required?
use crate::bitcoin::Script;
use crate::descriptor::Descriptor;
use crate::esplora::EsploraClient;
use crate::keys::DerivationPath;
@ -24,7 +26,6 @@ use crate::keys::Mnemonic;
use crate::wallet::Update;
use crate::wallet::Wallet;
use bdk::keys::bip39::WordCount;
// use bdk_esplora::EsploraExt;
uniffi::include_scaffolding!("bdk");

View File

@ -62,7 +62,6 @@ impl Wallet {
}
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()))
@ -639,7 +638,7 @@ pub struct Update(pub(crate) BdkUpdate);
// .map(Arc::new)
// }
// }
//
// // The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
// // These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
// // crate.

View File

@ -1,11 +1,6 @@
package org.bitcoindevkit
import org.junit.Assert.*
import org.junit.Test
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.nio.file.Files
class WalletTest {
@Test
@ -39,7 +34,7 @@ class WalletTest {
// @Test
// fun testSyncedBalance() {
// val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET)
// val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET, WalletType.MEMORY)
// val wallet = Wallet.newNoPersist(descriptor, null, Network.TESTNET)
// val esploraClient = EsploraClient("https://mempool.space/testnet/api")
// // val esploraClient = EsploraClient("https://blockstream.info/testnet/api")
// val update = esploraClient.scan(wallet, 10uL, 1uL)