Update EsploraConfig, Blockchain broadcast, Wallet sync
This commit is contained in:
parent
907540d214
commit
4665c551dd
19
src/bdk.udl
19
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]
|
||||||
|
string 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,9 +136,7 @@ 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 {
|
||||||
|
125
src/lib.rs
125
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,76 @@ 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<String, Error> {
|
||||||
|
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
|
||||||
|
self.get_blockchain().broadcast(&tx)?;
|
||||||
|
// TODO move txid getter to PartiallySignedBitcoinTransaction
|
||||||
|
let txid = tx.txid();
|
||||||
|
Ok(txid.to_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>,
|
||||||
@ -137,46 +192,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 +218,20 @@ 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>>,
|
||||||
|
//progress_update: Box<dyn BdkProgress>,
|
||||||
|
//max_address_param: Option<u32>,
|
||||||
) -> 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 +270,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