Merge bitcoindevkit/bdk-ffi#149: Update to bdk 0.18.0
f38f4c6197ec95376beeb2f444f85bd6a8a12fbd Update CHANGELOG (Steve Myers) 11ba16ec1bec922e5ffd7fcf3903eec9caf227e7 Move txid getter to PartiallySignedBitcoinTransaction (Steve Myers) 4665c551dd67f38fe91011e41ed5d3e8de404fcf Update EsploraConfig, Blockchain broadcast, Wallet sync (Steve Myers) 907540d2143b4eff4146643259a068b2f0c8696a Update bdk to 0.18.0 with sqlite-bundled feature (Steve Myers) Pull request description: Changes that were needed to match updated bdk APIs: * new bdk-ffi `Blockchain` interface with `constructo(BlockchainConfig)` and `broadcast()` functions * `Blockchain.broadcast()` function is now void (doesn't return txid) * added `PartiallySignedBitcoinTransaction.txid()` getter function * `Wallet.sync()` function now takes a `Blockchain` and optional `Progress` callback interface Tests performed: * from `bdk-kotlin/bdk-ffi` added local remote to this branch, ran build.sh script * fixed broken `bdk-kotlin` jvm and android tests and confirmed tests all pass Top commit has no ACKs. Tree-SHA512: d50633bbc8fd8a0d141597b30122c72957d2a0d64fc1537b649eeb8a5df1b1fb9a78ee1f03b9c606f47dee3952c9a91ae09eb47eb7a66d5f0fcb5545c86d906b
This commit is contained in:
commit
3b243efefd
@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
- Update BDK to version 0.18.0
|
||||||
|
|
||||||
## [v0.5.0]
|
## [v0.5.0]
|
||||||
|
|
||||||
- Fix Wallet.broadcast function, now returns a tx id as a hex string
|
- Fix Wallet.broadcast function, now returns a tx id as a hex string
|
||||||
|
@ -14,10 +14,7 @@ crate-type = ["staticlib", "cdylib"]
|
|||||||
name = "bdkffi"
|
name = "bdkffi"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bdk = { version = "0.14", features = ["all-keys", "use-esplora-ureq", "sqlite"] }
|
bdk = { version = "0.18", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled"] }
|
||||||
|
|
||||||
# TODO remove when bdk "sqlite-bundled" feature added
|
|
||||||
rusqlite = { version = "0.25.3", features = ["bundled"] }
|
|
||||||
|
|
||||||
uniffi_macros = { version = "0.16.0", features = ["builtin-bindgen"] }
|
uniffi_macros = { version = "0.16.0", features = ["builtin-bindgen"] }
|
||||||
uniffi = { version = "0.16.0", features = ["builtin-bindgen"] }
|
uniffi = { version = "0.16.0", features = ["builtin-bindgen"] }
|
||||||
|
20
src/bdk.udl
20
src/bdk.udl
@ -101,9 +101,9 @@ dictionary ElectrumConfig {
|
|||||||
dictionary EsploraConfig {
|
dictionary EsploraConfig {
|
||||||
string base_url;
|
string base_url;
|
||||||
string? proxy;
|
string? proxy;
|
||||||
u64 timeout_read;
|
u8? concurrency;
|
||||||
u64 timeout_write;
|
|
||||||
u64 stop_gap;
|
u64 stop_gap;
|
||||||
|
u64? timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
[Enum]
|
[Enum]
|
||||||
@ -112,13 +112,20 @@ interface BlockchainConfig {
|
|||||||
Esplora(EsploraConfig config);
|
Esplora(EsploraConfig config);
|
||||||
};
|
};
|
||||||
|
|
||||||
callback interface BdkProgress {
|
interface Blockchain {
|
||||||
|
[Throws=BdkError]
|
||||||
|
constructor(BlockchainConfig config);
|
||||||
|
[Throws=BdkError]
|
||||||
|
void broadcast([ByRef] PartiallySignedBitcoinTransaction psbt);
|
||||||
|
};
|
||||||
|
|
||||||
|
callback interface Progress {
|
||||||
void update(f32 progress, string? message);
|
void update(f32 progress, string? message);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Wallet {
|
interface Wallet {
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
constructor(string descriptor, string? change_descriptor, Network network, DatabaseConfig database_config, BlockchainConfig blockchain_config);
|
constructor(string descriptor, string? change_descriptor, Network network, DatabaseConfig database_config);
|
||||||
string get_new_address();
|
string get_new_address();
|
||||||
string get_last_unused_address();
|
string get_last_unused_address();
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
@ -129,15 +136,14 @@ interface Wallet {
|
|||||||
sequence<Transaction> get_transactions();
|
sequence<Transaction> get_transactions();
|
||||||
Network get_network();
|
Network get_network();
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
void sync(BdkProgress progress_update, u32? max_address_param);
|
void sync([ByRef] Blockchain blockchain, Progress? progress);
|
||||||
[Throws=BdkError]
|
|
||||||
string broadcast([ByRef] PartiallySignedBitcoinTransaction psbt);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface PartiallySignedBitcoinTransaction {
|
interface PartiallySignedBitcoinTransaction {
|
||||||
[Throws=BdkError]
|
[Throws=BdkError]
|
||||||
constructor(string psbt_base64);
|
constructor(string psbt_base64);
|
||||||
string serialize();
|
string serialize();
|
||||||
|
string txid();
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TxBuilder {
|
interface TxBuilder {
|
||||||
|
126
src/lib.rs
126
src/lib.rs
@ -3,18 +3,22 @@ use bdk::bitcoin::secp256k1::Secp256k1;
|
|||||||
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
|
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
|
||||||
use bdk::bitcoin::{Address, Network, Script};
|
use bdk::bitcoin::{Address, Network, Script};
|
||||||
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
||||||
use bdk::blockchain::Progress;
|
|
||||||
use bdk::blockchain::{
|
use bdk::blockchain::{
|
||||||
electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain,
|
electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain,
|
||||||
};
|
};
|
||||||
|
use bdk::blockchain::{Blockchain as BdkBlockchain, Progress as BdkProgress};
|
||||||
use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration};
|
use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration};
|
||||||
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
||||||
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
|
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
|
||||||
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
|
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
|
||||||
use bdk::miniscript::BareCtx;
|
use bdk::miniscript::BareCtx;
|
||||||
use bdk::wallet::AddressIndex;
|
use bdk::wallet::AddressIndex;
|
||||||
use bdk::{BlockTime, Error, FeeRate, SignOptions, Wallet as BdkWallet};
|
use bdk::{
|
||||||
|
BlockTime, Error, FeeRate, SignOptions, SyncOptions as BdkSyncOptions, Wallet as BdkWallet,
|
||||||
|
};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
|
|
||||||
@ -39,9 +43,9 @@ pub struct ElectrumConfig {
|
|||||||
pub struct EsploraConfig {
|
pub struct EsploraConfig {
|
||||||
pub base_url: String,
|
pub base_url: String,
|
||||||
pub proxy: Option<String>,
|
pub proxy: Option<String>,
|
||||||
pub timeout_read: u64,
|
pub concurrency: Option<u8>,
|
||||||
pub timeout_write: u64,
|
|
||||||
pub stop_gap: u64,
|
pub stop_gap: u64,
|
||||||
|
pub timeout: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BlockchainConfig {
|
pub enum BlockchainConfig {
|
||||||
@ -93,25 +97,73 @@ impl From<&bdk::TransactionDetails> for Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Wallet {
|
struct Blockchain {
|
||||||
wallet_mutex: Mutex<BdkWallet<AnyBlockchain, AnyDatabase>>,
|
blockchain_mutex: Mutex<AnyBlockchain>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BdkProgress: Send + Sync {
|
impl Blockchain {
|
||||||
|
fn new(blockchain_config: BlockchainConfig) -> Result<Self, BdkError> {
|
||||||
|
let any_blockchain_config = match blockchain_config {
|
||||||
|
BlockchainConfig::Electrum { config } => {
|
||||||
|
AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
|
||||||
|
retry: config.retry,
|
||||||
|
socks5: config.socks5,
|
||||||
|
timeout: config.timeout,
|
||||||
|
url: config.url,
|
||||||
|
stop_gap: usize::try_from(config.stop_gap).unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlockchainConfig::Esplora { config } => {
|
||||||
|
AnyBlockchainConfig::Esplora(EsploraBlockchainConfig {
|
||||||
|
base_url: config.base_url,
|
||||||
|
proxy: config.proxy,
|
||||||
|
concurrency: config.concurrency,
|
||||||
|
stop_gap: usize::try_from(config.stop_gap).unwrap(),
|
||||||
|
timeout: config.timeout,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let blockchain = AnyBlockchain::from_config(&any_blockchain_config)?;
|
||||||
|
Ok(Self {
|
||||||
|
blockchain_mutex: Mutex::new(blockchain),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_blockchain(&self) -> MutexGuard<AnyBlockchain> {
|
||||||
|
self.blockchain_mutex.lock().expect("blockchain")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn broadcast(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<(), Error> {
|
||||||
|
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
|
||||||
|
self.get_blockchain().broadcast(&tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Wallet {
|
||||||
|
wallet_mutex: Mutex<BdkWallet<AnyDatabase>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Progress: Send + Sync + 'static {
|
||||||
fn update(&self, progress: f32, message: Option<String>);
|
fn update(&self, progress: f32, message: Option<String>);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BdkProgressHolder {
|
struct ProgressHolder {
|
||||||
progress_update: Box<dyn BdkProgress>,
|
progress: Box<dyn Progress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Progress for BdkProgressHolder {
|
impl BdkProgress for ProgressHolder {
|
||||||
fn update(&self, progress: f32, message: Option<String>) -> Result<(), Error> {
|
fn update(&self, progress: f32, message: Option<String>) -> Result<(), Error> {
|
||||||
self.progress_update.update(progress, message);
|
self.progress.update(progress, message);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for ProgressHolder {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ProgressHolder").finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct PartiallySignedBitcoinTransaction {
|
struct PartiallySignedBitcoinTransaction {
|
||||||
internal: Mutex<PartiallySignedTransaction>,
|
internal: Mutex<PartiallySignedTransaction>,
|
||||||
@ -129,6 +181,12 @@ impl PartiallySignedBitcoinTransaction {
|
|||||||
let psbt = self.internal.lock().unwrap().clone();
|
let psbt = self.internal.lock().unwrap().clone();
|
||||||
psbt.to_string()
|
psbt.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn txid(&self) -> String {
|
||||||
|
let tx = self.internal.lock().unwrap().clone().extract_tx();
|
||||||
|
let txid = tx.txid();
|
||||||
|
txid.to_hex()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wallet {
|
impl Wallet {
|
||||||
@ -137,46 +195,23 @@ impl Wallet {
|
|||||||
change_descriptor: Option<String>,
|
change_descriptor: Option<String>,
|
||||||
network: Network,
|
network: Network,
|
||||||
database_config: DatabaseConfig,
|
database_config: DatabaseConfig,
|
||||||
blockchain_config: BlockchainConfig,
|
|
||||||
) -> Result<Self, BdkError> {
|
) -> Result<Self, BdkError> {
|
||||||
let any_database_config = match database_config {
|
let any_database_config = match database_config {
|
||||||
DatabaseConfig::Memory => AnyDatabaseConfig::Memory(()),
|
DatabaseConfig::Memory => AnyDatabaseConfig::Memory(()),
|
||||||
DatabaseConfig::Sled { config } => AnyDatabaseConfig::Sled(config),
|
DatabaseConfig::Sled { config } => AnyDatabaseConfig::Sled(config),
|
||||||
DatabaseConfig::Sqlite { config } => AnyDatabaseConfig::Sqlite(config),
|
DatabaseConfig::Sqlite { config } => AnyDatabaseConfig::Sqlite(config),
|
||||||
};
|
};
|
||||||
let any_blockchain_config = match blockchain_config {
|
|
||||||
BlockchainConfig::Electrum { config } => {
|
|
||||||
AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
|
|
||||||
retry: config.retry,
|
|
||||||
socks5: config.socks5,
|
|
||||||
timeout: config.timeout,
|
|
||||||
url: config.url,
|
|
||||||
stop_gap: usize::try_from(config.stop_gap).unwrap(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
BlockchainConfig::Esplora { config } => {
|
|
||||||
AnyBlockchainConfig::Esplora(EsploraBlockchainConfig {
|
|
||||||
base_url: config.base_url,
|
|
||||||
proxy: config.proxy,
|
|
||||||
timeout_read: config.timeout_read,
|
|
||||||
timeout_write: config.timeout_write,
|
|
||||||
stop_gap: usize::try_from(config.stop_gap).unwrap(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let database = AnyDatabase::from_config(&any_database_config)?;
|
let database = AnyDatabase::from_config(&any_database_config)?;
|
||||||
let blockchain = AnyBlockchain::from_config(&any_blockchain_config)?;
|
|
||||||
let wallet_mutex = Mutex::new(BdkWallet::new(
|
let wallet_mutex = Mutex::new(BdkWallet::new(
|
||||||
&descriptor,
|
&descriptor,
|
||||||
change_descriptor.as_ref(),
|
change_descriptor.as_ref(),
|
||||||
network,
|
network,
|
||||||
database,
|
database,
|
||||||
blockchain,
|
|
||||||
)?);
|
)?);
|
||||||
Ok(Wallet { wallet_mutex })
|
Ok(Wallet { wallet_mutex })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_wallet(&self) -> MutexGuard<BdkWallet<AnyBlockchain, AnyDatabase>> {
|
fn get_wallet(&self) -> MutexGuard<BdkWallet<AnyDatabase>> {
|
||||||
self.wallet_mutex.lock().expect("wallet")
|
self.wallet_mutex.lock().expect("wallet")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,11 +221,18 @@ impl Wallet {
|
|||||||
|
|
||||||
fn sync(
|
fn sync(
|
||||||
&self,
|
&self,
|
||||||
progress_update: Box<dyn BdkProgress>,
|
blockchain: &Blockchain,
|
||||||
max_address_param: Option<u32>,
|
progress: Option<Box<dyn Progress>>,
|
||||||
) -> Result<(), BdkError> {
|
) -> Result<(), BdkError> {
|
||||||
self.get_wallet()
|
let bdk_sync_opts = BdkSyncOptions {
|
||||||
.sync(BdkProgressHolder { progress_update }, max_address_param)
|
progress: progress.map(|p| {
|
||||||
|
Box::new(ProgressHolder { progress: p })
|
||||||
|
as Box<(dyn bdk::blockchain::Progress + 'static)>
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
let blockchain = blockchain.get_blockchain();
|
||||||
|
self.get_wallet().sync(blockchain.deref(), bdk_sync_opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_new_address(&self) -> String {
|
fn get_new_address(&self) -> String {
|
||||||
@ -229,12 +271,6 @@ impl Wallet {
|
|||||||
let transactions = self.get_wallet().list_transactions(true)?;
|
let transactions = self.get_wallet().list_transactions(true)?;
|
||||||
Ok(transactions.iter().map(Transaction::from).collect())
|
Ok(transactions.iter().map(Transaction::from).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn broadcast(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<String, Error> {
|
|
||||||
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
|
|
||||||
let txid = self.get_wallet().broadcast(&tx)?;
|
|
||||||
Ok(txid.to_hex())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtendedKeyInfo {
|
pub struct ExtendedKeyInfo {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user