diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt index 9ed1255..b42789a 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt @@ -26,7 +26,8 @@ class LiveTxBuilderTest { val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET) val wallet = Wallet(descriptor, null, persistenceFilePath, Network.TESTNET) val esploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") @@ -48,7 +49,8 @@ class LiveTxBuilderTest { val changeDescriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/1/*)", Network.TESTNET) val wallet = Wallet(externalDescriptor, changeDescriptor, persistenceFilePath, Network.TESTNET) val esploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt index 5e38242..cd40a44 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt @@ -26,7 +26,8 @@ class LiveWalletTest { val descriptor: Descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET) val wallet: Wallet = Wallet(descriptor, null, persistenceFilePath, Network.TESTNET) val esploraClient: EsploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") val balance: Balance = wallet.getBalance() @@ -49,14 +50,15 @@ class LiveWalletTest { val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET) val wallet = Wallet(descriptor, null, persistenceFilePath, Network.TESTNET) val esploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") - println("New address: ${wallet.getAddress(AddressIndex.New).address}") + println("New address: ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address}") assert(wallet.getBalance().total > 0uL) { - "Wallet balance must be greater than 0! Please send funds to ${wallet.getAddress(AddressIndex.New).address} and try again." + "Wallet balance must be greater than 0! Please send funds to ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address} and try again." } val recipient: Address = Address("tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", Network.TESTNET) diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt index 4f66969..17afe75 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt @@ -44,7 +44,7 @@ class OfflineWalletTest { persistenceFilePath, Network.TESTNET ) - val addressInfo: AddressInfo = wallet.getAddress(AddressIndex.New) + val addressInfo: AddressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL) assertTrue(addressInfo.address.isValidForNetwork(Network.TESTNET), "Address is not valid for testnet network") assertTrue(addressInfo.address.isValidForNetwork(Network.SIGNET), "Address is not valid for signet network") diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index ba2563d..5cc38cf 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -115,6 +115,7 @@ interface EsploraError { HeaderHashNotFound(); InvalidHttpHeaderName(string name); InvalidHttpHeaderValue(string value); + RequestAlreadyConsumed(); }; [Error] @@ -238,6 +239,10 @@ dictionary CanonicalTx { ChainPosition chain_position; }; +interface FullScanRequest {}; + +interface SyncRequest {}; + // ------------------------------------------------------------------------ // bdk crate - wallet module // ------------------------------------------------------------------------ @@ -283,6 +288,10 @@ interface Wallet { sequence list_unspent(); sequence list_output(); + + FullScanRequest start_full_scan(); + + SyncRequest start_sync_with_revealed_spks(); }; interface Update {}; @@ -429,7 +438,10 @@ interface EsploraClient { constructor(string url); [Throws=EsploraError] - Update full_scan(Wallet wallet, u64 stop_gap, u64 parallel_requests); + Update full_scan(FullScanRequest full_scan_request, u64 stop_gap, u64 parallel_requests); + + [Throws=EsploraError] + Update sync(SyncRequest sync_request, u64 parallel_requests); [Throws=EsploraError] void broadcast([ByRef] Transaction transaction); diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index 1554743..c7f6df7 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -1,34 +1,28 @@ use crate::bitcoin::OutPoint; +use bdk::bitcoin::address::ParseError; +use bdk::bitcoin::bip32::Error as BdkBip32Error; use bdk::bitcoin::psbt::PsbtParseError as BdkPsbtParseError; use bdk::bitcoin::Network; use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError; use bdk::descriptor::DescriptorError as BdkDescriptorError; +use bdk::keys::bip39::Error as BdkBip39Error; +use bdk::miniscript::descriptor::DescriptorKeyParseError as BdkDescriptorKeyParseError; use bdk::wallet::error::BuildFeeBumpError; +use bdk::wallet::error::CreateTxError as BdkCreateTxError; use bdk::wallet::signer::SignerError as BdkSignerError; use bdk::wallet::tx_builder::AddUtxoError; use bdk::wallet::NewOrLoadError; use bdk_esplora::esplora_client::{Error as BdkEsploraError, Error}; use bdk_file_store::FileError as BdkFileError; -use bdk_file_store::IterError; use bitcoin_internals::hex::display::DisplayHex; -use crate::error::bip32::Error as BdkBip32Error; -use bdk::bitcoin::address::ParseError; -use bdk::keys::bip39::Error as BdkBip39Error; -use bdk::miniscript::descriptor::DescriptorKeyParseError as BdkDescriptorKeyParseError; - -use bdk::bitcoin::bip32; - -use bdk::chain; - -use bdk::wallet::error::CreateTxError as BdkCreateTxError; use std::convert::TryInto; use bdk::bitcoin::address::Error as BdkAddressError; use bdk::bitcoin::consensus::encode::Error as BdkEncodeError; use bdk::bitcoin::psbt::ExtractTxError as BdkExtractTxError; -use chain::local_chain::CannotConnectError as BdkCannotConnectError; +use bdk::chain::local_chain::CannotConnectError as BdkCannotConnectError; // ------------------------------------------------------------------------ // error definitions @@ -295,6 +289,9 @@ pub enum EsploraError { #[error("invalid HTTP header value: {value}")] InvalidHttpHeaderValue { value: String }, + + #[error("the request has already been consumed")] + RequestAlreadyConsumed, } #[derive(Debug, thiserror::Error)] @@ -411,6 +408,7 @@ pub enum TxidParseError { InvalidTxid { txid: String }, } +// This error combines the Rust bdk::wallet::NewOrLoadError and bdk_file_store::FileError #[derive(Debug, thiserror::Error)] pub enum WalletCreationError { #[error("io error trying to read file: {error_message}")] @@ -422,17 +420,14 @@ pub enum WalletCreationError { #[error("error with descriptor")] Descriptor, - #[error("failed to write to persistence")] - Write, - - #[error("failed to load from persistence")] - Load, + #[error("failed to either write to or load from persistence, {error_message}")] + Persist { error_message: String }, #[error("wallet is not initialized, persistence backend is empty")] NotInitialized, - #[error("loaded genesis hash does not match the expected one")] - LoadedGenesisDoesNotMatch, + #[error("loaded genesis hash '{got}' does not match the expected one '{expected}'")] + LoadedGenesisDoesNotMatch { expected: String, got: String }, #[error("loaded network type is not {expected}, got {got:?}")] LoadedNetworkDoesNotMatch { @@ -560,8 +555,8 @@ impl From for CannotConnectError { } } -impl From> for CreateTxError { - fn from(error: BdkCreateTxError) -> Self { +impl From for CreateTxError { + fn from(error: BdkCreateTxError) -> Self { match error { BdkCreateTxError::Descriptor(e) => CreateTxError::Descriptor { error_message: e.to_string(), @@ -751,6 +746,44 @@ impl From for EsploraError { } } +impl From> for EsploraError { + fn from(error: Box) -> Self { + match *error { + BdkEsploraError::Minreq(e) => EsploraError::Minreq { + error_message: e.to_string(), + }, + BdkEsploraError::HttpResponse { status, message } => EsploraError::HttpResponse { + status, + error_message: message, + }, + BdkEsploraError::Parsing(e) => EsploraError::Parsing { + error_message: e.to_string(), + }, + Error::StatusCode(e) => EsploraError::StatusCode { + error_message: e.to_string(), + }, + BdkEsploraError::BitcoinEncoding(e) => EsploraError::BitcoinEncoding { + error_message: e.to_string(), + }, + BdkEsploraError::HexToArray(e) => EsploraError::HexToArray { + error_message: e.to_string(), + }, + BdkEsploraError::HexToBytes(e) => EsploraError::HexToBytes { + error_message: e.to_string(), + }, + BdkEsploraError::TransactionNotFound(_) => EsploraError::TransactionNotFound, + BdkEsploraError::HeaderHeightNotFound(height) => { + EsploraError::HeaderHeightNotFound { height } + } + BdkEsploraError::HeaderHashNotFound(_) => EsploraError::HeaderHashNotFound, + Error::InvalidHttpHeaderName(name) => EsploraError::InvalidHttpHeaderName { name }, + BdkEsploraError::InvalidHttpHeaderValue(value) => { + EsploraError::InvalidHttpHeaderValue { value } + } + } + } +} + impl From for ExtractTxError { fn from(error: BdkExtractTxError) -> Self { match error { @@ -852,15 +885,19 @@ impl From for WalletCreationError { } } -impl From> for WalletCreationError { - fn from(error: NewOrLoadError) -> Self { +impl From for WalletCreationError { + fn from(error: NewOrLoadError) -> Self { match error { NewOrLoadError::Descriptor(_) => WalletCreationError::Descriptor, - NewOrLoadError::Write(_) => WalletCreationError::Write, - NewOrLoadError::Load(_) => WalletCreationError::Load, + NewOrLoadError::Persist(e) => WalletCreationError::Persist { + error_message: e.to_string(), + }, NewOrLoadError::NotInitialized => WalletCreationError::NotInitialized, - NewOrLoadError::LoadedGenesisDoesNotMatch { .. } => { - WalletCreationError::LoadedGenesisDoesNotMatch + NewOrLoadError::LoadedGenesisDoesNotMatch { expected, got } => { + WalletCreationError::LoadedGenesisDoesNotMatch { + expected: expected.to_string(), + got: format!("{:?}", got), + } } NewOrLoadError::LoadedNetworkDoesNotMatch { expected, got } => { WalletCreationError::LoadedNetworkDoesNotMatch { expected, got } @@ -1332,6 +1369,10 @@ mod test { "header height 123456 not found", ), (EsploraError::HeaderHashNotFound, "header hash not found"), + ( + EsploraError::RequestAlreadyConsumed, + "the request has already been consumed", + ), ]; for (error, expected_message) in cases { @@ -1541,20 +1582,21 @@ mod test { "error with descriptor".to_string(), ), ( - WalletCreationError::Write, - "failed to write to persistence".to_string(), - ), - ( - WalletCreationError::Load, - "failed to load from persistence".to_string(), + WalletCreationError::Persist { + error_message: "persistence error".to_string(), + }, + "failed to either write to or load from persistence, persistence error".to_string(), ), ( WalletCreationError::NotInitialized, "wallet is not initialized, persistence backend is empty".to_string(), ), ( - WalletCreationError::LoadedGenesisDoesNotMatch, - "loaded genesis hash does not match the expected one".to_string(), + WalletCreationError::LoadedGenesisDoesNotMatch { + expected: "abc".to_string(), + got: "def".to_string(), + }, + "loaded genesis hash 'def' does not match the expected one 'abc'".to_string(), ), ( WalletCreationError::LoadedNetworkDoesNotMatch { diff --git a/bdk-ffi/src/esplora.rs b/bdk-ffi/src/esplora.rs index a523133..9a855be 100644 --- a/bdk-ffi/src/esplora.rs +++ b/bdk-ffi/src/esplora.rs @@ -1,9 +1,15 @@ -use crate::error::EsploraError; -use crate::wallet::{Update, Wallet}; - use crate::bitcoin::Transaction; +use crate::error::EsploraError; +use crate::types::{FullScanRequest, SyncRequest}; +use crate::wallet::Update; +use std::collections::BTreeMap; + use bdk::bitcoin::Transaction as BdkTransaction; -use bdk::wallet::Update as BdkUpdate; +use bdk::chain::spk_client::FullScanRequest as BdkFullScanRequest; +use bdk::chain::spk_client::FullScanResult as BdkFullScanResult; +use bdk::chain::spk_client::SyncRequest as BdkSyncRequest; +use bdk::chain::spk_client::SyncResult as BdkSyncResult; +use bdk::KeychainKind; use bdk_esplora::esplora_client::{BlockingClient, Builder}; use bdk_esplora::EsploraExt; @@ -17,40 +23,56 @@ impl EsploraClient { Self(client) } - // This is a temporary solution for scanning. The long-term solution involves not passing - // the wallet to the client at all. pub fn full_scan( &self, - wallet: Arc, + request: Arc, stop_gap: u64, parallel_requests: u64, ) -> Result, EsploraError> { - let wallet = wallet.get_wallet(); - - let previous_tip = wallet.latest_checkpoint(); - let keychain_spks = wallet.all_unbounded_spk_iters().into_iter().collect(); - - let (update_graph, last_active_indices) = self + // using option and take is not ideal but the only way to take full ownership of the request + let request: BdkFullScanRequest = request .0 - .full_scan(keychain_spks, stop_gap as usize, parallel_requests as usize) - .map_err(|e| EsploraError::from(*e))?; + .lock() + .unwrap() + .take() + .ok_or(EsploraError::RequestAlreadyConsumed)?; - let missing_heights = update_graph.missing_heights(wallet.local_chain()); - let chain_update = self - .0 - .update_local_chain(previous_tip, missing_heights) - .map_err(|e| EsploraError::from(*e))?; + let result: BdkFullScanResult = + self.0 + .full_scan(request, stop_gap as usize, parallel_requests as usize)?; - let update = BdkUpdate { - last_active_indices, - graph: update_graph, - chain: Some(chain_update), + let update = bdk::wallet::Update { + last_active_indices: result.last_active_indices, + graph: result.graph_update, + chain: Some(result.chain_update), }; Ok(Arc::new(Update(update))) } - // pub fn sync(); + pub fn sync( + &self, + request: Arc, + parallel_requests: u64, + ) -> Result, EsploraError> { + // using option and take is not ideal but the only way to take full ownership of the request + let request: BdkSyncRequest = request + .0 + .lock() + .unwrap() + .take() + .ok_or(EsploraError::RequestAlreadyConsumed)?; + + let result: BdkSyncResult = self.0.sync(request, parallel_requests as usize)?; + + let update = bdk::wallet::Update { + last_active_indices: BTreeMap::default(), + graph: result.graph_update, + chain: Some(result.chain_update), + }; + + Ok(Arc::new(Update(update))) + } pub fn broadcast(&self, transaction: &Transaction) -> Result<(), EsploraError> { let bdk_transaction: BdkTransaction = transaction.into(); diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index 8a3331e..8774ae4 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -40,8 +40,10 @@ use crate::types::AddressInfo; use crate::types::Balance; use crate::types::CanonicalTx; use crate::types::ChainPosition; +use crate::types::FullScanRequest; use crate::types::LocalOutput; use crate::types::ScriptAmount; +use crate::types::SyncRequest; use crate::wallet::BumpFeeTxBuilder; use crate::wallet::SentAndReceivedValues; use crate::wallet::TxBuilder; diff --git a/bdk-ffi/src/types.rs b/bdk-ffi/src/types.rs index 2760321..2a60b31 100644 --- a/bdk-ffi/src/types.rs +++ b/bdk-ffi/src/types.rs @@ -1,14 +1,15 @@ use crate::bitcoin::{Address, OutPoint, Script, Transaction, TxOut}; +use bdk::chain::spk_client::FullScanRequest as BdkFullScanRequest; +use bdk::chain::spk_client::SyncRequest as BdkSyncRequest; use bdk::chain::tx_graph::CanonicalTx as BdkCanonicalTx; use bdk::chain::{ChainPosition as BdkChainPosition, ConfirmationTimeHeightAnchor}; -use bdk::wallet::AddressIndex as BdkAddressIndex; use bdk::wallet::AddressInfo as BdkAddressInfo; use bdk::wallet::Balance as BdkBalance; use bdk::KeychainKind; use bdk::LocalOutput as BdkLocalOutput; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; #[derive(Debug, Clone, PartialEq, Eq)] pub enum ChainPosition { @@ -108,3 +109,7 @@ impl From for LocalOutput { } } } + +pub struct FullScanRequest(pub(crate) Mutex>>); + +pub struct SyncRequest(pub(crate) Mutex>); diff --git a/bdk-ffi/src/wallet.rs b/bdk-ffi/src/wallet.rs index 4eea8f2..46bf1b9 100644 --- a/bdk-ffi/src/wallet.rs +++ b/bdk-ffi/src/wallet.rs @@ -4,7 +4,9 @@ use crate::error::{ CalculateFeeError, CannotConnectError, CreateTxError, PersistenceError, SignerError, TxidParseError, WalletCreationError, }; -use crate::types::{AddressIndex, AddressInfo, Balance, CanonicalTx, LocalOutput, ScriptAmount}; +use crate::types::{ + AddressInfo, Balance, CanonicalTx, FullScanRequest, LocalOutput, ScriptAmount, SyncRequest, +}; use bdk::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf; use bdk::bitcoin::Network; @@ -142,6 +144,16 @@ impl Wallet { pub fn list_output(&self) -> Vec { self.get_wallet().list_output().map(|o| o.into()).collect() } + + pub fn start_full_scan(&self) -> Arc { + let request = self.get_wallet().start_full_scan(); + Arc::new(FullScanRequest(Mutex::new(Some(request)))) + } + + pub fn start_sync_with_revealed_spks(&self) -> Arc { + let request = self.get_wallet().start_sync_with_revealed_spks(); + Arc::new(SyncRequest(Mutex::new(Some(request)))) + } } pub struct SentAndReceivedValues { diff --git a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt index 4c07de2..9eb129d 100644 --- a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt +++ b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt @@ -24,7 +24,8 @@ class LiveTxBuilderTest { val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET) val wallet = Wallet(descriptor, null, persistenceFilePath, Network.TESTNET) val esploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") @@ -47,7 +48,8 @@ class LiveTxBuilderTest { val changeDescriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/1/*)", Network.TESTNET) val wallet = Wallet(externalDescriptor, changeDescriptor, persistenceFilePath, Network.TESTNET) val esploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") diff --git a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveWalletTest.kt b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveWalletTest.kt index eea4f5f..c878105 100644 --- a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveWalletTest.kt +++ b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveWalletTest.kt @@ -26,7 +26,8 @@ class LiveWalletTest { val esploraClient: EsploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") // val esploraClient: EsploraClient = EsploraClient("https://mempool.space/testnet/api") // val esploraClient = EsploraClient("https://blockstream.info/testnet/api") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") @@ -47,14 +48,14 @@ class LiveWalletTest { val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", Network.TESTNET) val wallet: Wallet = Wallet(descriptor, null, persistenceFilePath, Network.TESTNET) val esploraClient = EsploraClient("https://esplora.testnet.kuutamo.cloud/") - val update = esploraClient.fullScan(wallet, 10uL, 1uL) - + val fullScanRequest: FullScanRequest = wallet.startFullScan() + val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) wallet.applyUpdate(update) println("Balance: ${wallet.getBalance().total}") - println("New address: ${wallet.getAddress(AddressIndex.New).address.asString()}") + println("New address: ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address.asString()}") assert(wallet.getBalance().total > 0uL) { - "Wallet balance must be greater than 0! Please send funds to ${wallet.getAddress(AddressIndex.New).address} and try again." + "Wallet balance must be greater than 0! Please send funds to ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address.asString()} and try again." } val recipient: Address = Address("tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", Network.TESTNET) diff --git a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/OfflineWalletTest.kt b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/OfflineWalletTest.kt index f66ad24..a369075 100644 --- a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/OfflineWalletTest.kt +++ b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/OfflineWalletTest.kt @@ -42,7 +42,7 @@ class OfflineWalletTest { persistenceFilePath, Network.TESTNET ) - val addressInfo: AddressInfo = wallet.getAddress(AddressIndex.New) + val addressInfo: AddressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL) assertTrue(addressInfo.address.isValidForNetwork(Network.TESTNET), "Address is not valid for testnet network") assertTrue(addressInfo.address.isValidForNetwork(Network.SIGNET), "Address is not valid for signet network") diff --git a/bdk-python/tests/test_live_tx_builder.py b/bdk-python/tests/test_live_tx_builder.py index 2d2e4d1..2c9a3fc 100644 --- a/bdk-python/tests/test_live_tx_builder.py +++ b/bdk-python/tests/test_live_tx_builder.py @@ -19,19 +19,20 @@ class LiveTxBuilderTest(unittest.TestCase): "./bdk_persistence.db", bdk.Network.TESTNET ) - esploraClient: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") - update = esploraClient.full_scan( - wallet = wallet, - stop_gap = 10, - parallel_requests = 1 + esplora_client: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") + full_scan_request: bdk.FullScanRequest = wallet.start_full_scan() + update = esplora_client.full_scan( + full_scan_request=full_scan_request, + stop_gap=10, + parallel_requests=1 ) wallet.apply_update(update) self.assertGreater(wallet.get_balance().total, 0) recipient = bdk.Address( - address = "tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", - network = bdk.Network.TESTNET + address="tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", + network=bdk.Network.TESTNET ) psbt = bdk.TxBuilder().add_recipient(script=recipient.script_pubkey(), amount=4200).fee_rate(fee_rate=bdk.FeeRate.from_sat_per_vb(2)).finish(wallet) @@ -53,23 +54,24 @@ class LiveTxBuilderTest(unittest.TestCase): "./bdk_persistence.db", bdk.Network.TESTNET ) - esploraClient: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") - update = esploraClient.full_scan( - wallet = wallet, - stop_gap = 10, - parallel_requests = 1 + esplora_client: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") + full_scan_request: bdk.FullScanRequest = wallet.start_full_scan() + update = esplora_client.full_scan( + full_scan_request=full_scan_request, + stop_gap=10, + parallel_requests=1 ) wallet.apply_update(update) self.assertGreater(wallet.get_balance().total, 0) recipient1 = bdk.Address( - address = "tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", - network = bdk.Network.TESTNET + address="tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", + network=bdk.Network.TESTNET ) recipient2 = bdk.Address( - address = "tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", - network = bdk.Network.TESTNET + address="tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", + network=bdk.Network.TESTNET ) all_recipients = list( bdk.ScriptAmount(recipient1.script_pubkey, 4200), diff --git a/bdk-python/tests/test_live_wallet.py b/bdk-python/tests/test_live_wallet.py index 273b395..230b64b 100644 --- a/bdk-python/tests/test_live_wallet.py +++ b/bdk-python/tests/test_live_wallet.py @@ -19,11 +19,12 @@ class LiveWalletTest(unittest.TestCase): "./bdk_persistence.db", bdk.Network.TESTNET ) - esploraClient: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") - update = esploraClient.full_scan( - wallet = wallet, - stop_gap = 10, - parallel_requests = 1 + esplora_client: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") + full_scan_request: bdk.FullScanRequest = wallet.start_full_scan() + update = esplora_client.full_scan( + full_scan_request=full_scan_request, + stop_gap=10, + parallel_requests=1 ) wallet.apply_update(update) @@ -49,19 +50,20 @@ class LiveWalletTest(unittest.TestCase): "./bdk_persistence.db", bdk.Network.TESTNET ) - esploraClient: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") - update = esploraClient.full_scan( - wallet = wallet, - stop_gap = 10, - parallel_requests = 1 + esplora_client: bdk.EsploraClient = bdk.EsploraClient(url = "https://esplora.testnet.kuutamo.cloud/") + full_scan_request: bdk.FullScanRequest = wallet.start_full_scan() + update = esplora_client.full_scan( + full_scan_request=full_scan_request, + stop_gap=10, + parallel_requests=1 ) wallet.apply_update(update) self.assertGreater(wallet.get_balance().total, 0) recipient = bdk.Address( - address = "tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", - network = bdk.Network.TESTNET + address="tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", + network=bdk.Network.TESTNET ) psbt: bdk.Psbt = bdk.TxBuilder().add_recipient(script=recipient.script_pubkey(), amount=4200).fee_rate(fee_rate=bdk.FeeRate.from_sat_per_vb(2)).finish(wallet) @@ -77,7 +79,7 @@ class LiveWalletTest(unittest.TestCase): fee_rate = wallet.calculate_fee_rate(tx) print(f"Transaction Fee Rate: {fee_rate.to_sat_per_vb_ceil()} sat/vB") - esploraClient.broadcast(tx) + esplora_client.broadcast(tx) if __name__ == '__main__': diff --git a/bdk-python/tests/test_offline_wallet.py b/bdk-python/tests/test_offline_wallet.py index f9e607c..59c5fd6 100644 --- a/bdk-python/tests/test_offline_wallet.py +++ b/bdk-python/tests/test_offline_wallet.py @@ -19,7 +19,7 @@ class OfflineWalletTest(unittest.TestCase): "./bdk_persistence.db", bdk.Network.TESTNET ) - address_info: bdk.AddressInfo = wallet.get_address(bdk.AddressIndex.NEW()) + address_info: bdk.AddressInfo = wallet.reveal_next_address(bdk.KeychainKind.EXTERNAL) self.assertTrue(address_info.address.is_valid_for_network(bdk.Network.TESTNET), "Address is not valid for testnet network") self.assertTrue(address_info.address.is_valid_for_network(bdk.Network.SIGNET), "Address is not valid for signet network") diff --git a/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift b/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift index c525252..18b17e4 100644 --- a/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift +++ b/bdk-swift/Tests/BitcoinDevKitTests/LiveTxBuilderTests.swift @@ -35,8 +35,9 @@ final class LiveTxBuilderTests: XCTestCase { network: .testnet ) let esploraClient = EsploraClient(url: "https://esplora.testnet.kuutamo.cloud/") + let fullScanRequest: FullScanRequest = wallet.startFullScan() let update = try esploraClient.fullScan( - wallet: wallet, + fullScanRequest: fullScanRequest, stopGap: 10, parallelRequests: 1 ) @@ -70,8 +71,9 @@ final class LiveTxBuilderTests: XCTestCase { network: .testnet ) let esploraClient = EsploraClient(url: "https://esplora.testnet.kuutamo.cloud/") + let fullScanRequest: FullScanRequest = wallet.startFullScan() let update = try esploraClient.fullScan( - wallet: wallet, + fullScanRequest: fullScanRequest, stopGap: 10, parallelRequests: 1 ) diff --git a/bdk-swift/Tests/BitcoinDevKitTests/LiveWalletTests.swift b/bdk-swift/Tests/BitcoinDevKitTests/LiveWalletTests.swift index e853c7a..ef4db72 100644 --- a/bdk-swift/Tests/BitcoinDevKitTests/LiveWalletTests.swift +++ b/bdk-swift/Tests/BitcoinDevKitTests/LiveWalletTests.swift @@ -35,8 +35,9 @@ final class LiveWalletTests: XCTestCase { network: .testnet ) let esploraClient = EsploraClient(url: "https://esplora.testnet.kuutamo.cloud/") + let fullScanRequest: FullScanRequest = wallet.startFullScan() let update = try esploraClient.fullScan( - wallet: wallet, + fullScanRequest: fullScanRequest, stopGap: 10, parallelRequests: 1 ) @@ -66,8 +67,9 @@ final class LiveWalletTests: XCTestCase { network: .testnet ) let esploraClient = EsploraClient(url: "https://esplora.testnet.kuutamo.cloud/") + let fullScanRequest: FullScanRequest = wallet.startFullScan() let update = try esploraClient.fullScan( - wallet: wallet, + fullScanRequest: fullScanRequest, stopGap: 10, parallelRequests: 1 ) diff --git a/bdk-swift/Tests/BitcoinDevKitTests/OfflineWalletTests.swift b/bdk-swift/Tests/BitcoinDevKitTests/OfflineWalletTests.swift index 330f7af..ad645c2 100644 --- a/bdk-swift/Tests/BitcoinDevKitTests/OfflineWalletTests.swift +++ b/bdk-swift/Tests/BitcoinDevKitTests/OfflineWalletTests.swift @@ -34,7 +34,7 @@ final class OfflineWalletTests: XCTestCase { persistenceBackendPath: dbFilePath.path, network: .testnet ) - let addressInfo: AddressInfo = wallet.getAddress(addressIndex: AddressIndex.new) + let addressInfo: AddressInfo = try wallet.revealNextAddress(keychain: KeychainKind.external) XCTAssertTrue(addressInfo.address.isValidForNetwork(network: Network.testnet), "Address is not valid for testnet network")