diff --git a/CHANGELOG.md b/CHANGELOG.md index 99a9ad22..2fb53a4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Wallet #### Changed - `FeeRate` constructors `from_sat_per_vb` and `default_min_relay_fee` are now `const` functions +- `get_new_address()` refactored to `get_address(AddressIndex::New)` to support different `get_address()` index selection strategies #### Added -- Added `get_unused_address()` which returns the last generated address if it has not been used or if used in a received transaction returns a new address +- Added `get_address(AddressIndex::LastUnused)` which returns the last derived address if it has not been used or if used in a received transaction returns a new address +- Added `get_address(AddressIndex::Peek(u32))` which returns a derived address for a specified descriptor index ## [v0.4.0] - [v0.3.0] diff --git a/README.md b/README.md index 2b85314e..69e0fe47 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ fn main() -> Result<(), bdk::Error> { ```rust use bdk::{Wallet, database::MemoryDatabase}; +use bdk::wallet::AddressIndex::New; fn main() -> Result<(), bdk::Error> { let wallet = Wallet::new_offline( @@ -76,9 +77,9 @@ fn main() -> Result<(), bdk::Error> { MemoryDatabase::default(), )?; - println!("Address #0: {}", wallet.get_new_address()?); - println!("Address #1: {}", wallet.get_new_address()?); - println!("Address #2: {}", wallet.get_new_address()?); + println!("Address #0: {}", wallet.get_address(New)?); + println!("Address #1: {}", wallet.get_address(New)?); + println!("Address #2: {}", wallet.get_address(New)?); Ok(()) } @@ -92,6 +93,7 @@ use bdk::database::MemoryDatabase; use bdk::blockchain::{noop_progress, ElectrumBlockchain}; use bdk::electrum_client::Client; +use bdk::wallet::AddressIndex::New; use bitcoin::consensus::serialize; @@ -107,7 +109,7 @@ fn main() -> Result<(), bdk::Error> { wallet.sync(noop_progress(), None)?; - let send_to = wallet.get_new_address()?; + let send_to = wallet.get_address(New)?; let (psbt, details) = { let mut builder = wallet.build_tx(); builder diff --git a/examples/address_validator.rs b/examples/address_validator.rs index a925d4fd..5ce73e53 100644 --- a/examples/address_validator.rs +++ b/examples/address_validator.rs @@ -18,6 +18,7 @@ use bdk::wallet::address_validator::{AddressValidator, AddressValidatorError}; use bdk::KeychainKind; use bdk::Wallet; +use bdk::wallet::AddressIndex::New; use bitcoin::hashes::hex::FromHex; use bitcoin::util::bip32::Fingerprint; use bitcoin::{Network, Script}; @@ -52,9 +53,9 @@ fn main() -> Result<(), bdk::Error> { wallet.add_address_validator(Arc::new(DummyValidator)); - wallet.get_new_address()?; - wallet.get_new_address()?; - wallet.get_new_address()?; + wallet.get_address(New)?; + wallet.get_address(New)?; + wallet.get_address(New)?; Ok(()) } diff --git a/examples/compiler.rs b/examples/compiler.rs index 88cb0789..e1af0211 100644 --- a/examples/compiler.rs +++ b/examples/compiler.rs @@ -28,6 +28,7 @@ use miniscript::policy::Concrete; use miniscript::Descriptor; use bdk::database::memory::MemoryDatabase; +use bdk::wallet::AddressIndex::New; use bdk::{KeychainKind, Wallet}; fn main() -> Result<(), Box> { @@ -90,7 +91,7 @@ fn main() -> Result<(), Box> { .unwrap_or(Network::Testnet); let wallet = Wallet::new_offline(&format!("{}", descriptor), None, network, database)?; - info!("... First address: {}", wallet.get_new_address()?); + info!("... First address: {}", wallet.get_address(New)?); if matches.is_present("parsed_policy") { let spending_policy = wallet.policies(KeychainKind::External)?; diff --git a/src/descriptor/template.rs b/src/descriptor/template.rs index 012d8966..d48bc434 100644 --- a/src/descriptor/template.rs +++ b/src/descriptor/template.rs @@ -74,6 +74,7 @@ impl IntoWalletDescriptor for T { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::P2PKH; /// /// let key = @@ -86,7 +87,7 @@ impl IntoWalletDescriptor for T { /// )?; /// /// assert_eq!( -/// wallet.get_new_address()?.to_string(), +/// wallet.get_address(New)?.to_string(), /// "mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT" /// ); /// # Ok::<_, Box>(()) @@ -107,6 +108,7 @@ impl> DescriptorTemplate for P2PKH { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::P2WPKH_P2SH; /// /// let key = @@ -119,7 +121,7 @@ impl> DescriptorTemplate for P2PKH { /// )?; /// /// assert_eq!( -/// wallet.get_new_address()?.to_string(), +/// wallet.get_address(New)?.to_string(), /// "2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5" /// ); /// # Ok::<_, Box>(()) @@ -141,6 +143,7 @@ impl> DescriptorTemplate for P2WPKH_P2SH { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::P2WPKH; /// /// let key = @@ -153,7 +156,7 @@ impl> DescriptorTemplate for P2WPKH_P2SH { /// )?; /// /// assert_eq!( -/// wallet.get_new_address()?.to_string(), +/// wallet.get_address(New)?.to_string(), /// "tb1q4525hmgw265tl3drrl8jjta7ayffu6jf68ltjd" /// ); /// # Ok::<_, Box>(()) @@ -179,6 +182,7 @@ impl> DescriptorTemplate for P2WPKH { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::BIP44; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; @@ -189,7 +193,7 @@ impl> DescriptorTemplate for P2WPKH { /// MemoryDatabase::default() /// )?; /// -/// assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR"); +/// assert_eq!(wallet.get_address(New)?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx"); /// # Ok::<_, Box>(()) /// ``` @@ -217,6 +221,7 @@ impl> DescriptorTemplate for BIP44 { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::BIP44Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?; @@ -228,7 +233,7 @@ impl> DescriptorTemplate for BIP44 { /// MemoryDatabase::default() /// )?; /// -/// assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR"); +/// assert_eq!(wallet.get_address(New)?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx"); /// # Ok::<_, Box>(()) /// ``` @@ -253,6 +258,7 @@ impl> DescriptorTemplate for BIP44Public { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::BIP49; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; @@ -263,7 +269,7 @@ impl> DescriptorTemplate for BIP44Public { /// MemoryDatabase::default() /// )?; /// -/// assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt"); +/// assert_eq!(wallet.get_address(New)?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr"); /// # Ok::<_, Box>(()) /// ``` @@ -291,6 +297,7 @@ impl> DescriptorTemplate for BIP49 { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::BIP49Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?; @@ -302,7 +309,7 @@ impl> DescriptorTemplate for BIP49 { /// MemoryDatabase::default() /// )?; /// -/// assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt"); +/// assert_eq!(wallet.get_address(New)?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr"); /// # Ok::<_, Box>(()) /// ``` @@ -327,6 +334,7 @@ impl> DescriptorTemplate for BIP49Public { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::BIP84; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; @@ -337,7 +345,7 @@ impl> DescriptorTemplate for BIP49Public { /// MemoryDatabase::default() /// )?; /// -/// assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7"); +/// assert_eq!(wallet.get_address(New)?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg"); /// # Ok::<_, Box>(()) /// ``` @@ -365,6 +373,7 @@ impl> DescriptorTemplate for BIP84 { /// # use bdk::bitcoin::{PrivateKey, Network}; /// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; +/// # use bdk::wallet::AddressIndex::New; /// use bdk::template::BIP84Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; @@ -376,7 +385,7 @@ impl> DescriptorTemplate for BIP84 { /// MemoryDatabase::default() /// )?; /// -/// assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7"); +/// assert_eq!(wallet.get_address(New)?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7"); /// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg"); /// # Ok::<_, Box>(()) /// ``` diff --git a/src/lib.rs b/src/lib.rs index e9ce3f5b..44d067d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,18 +80,19 @@ //! ``` //! use bdk::{Wallet}; //! use bdk::database::MemoryDatabase; +//! use bdk::wallet::AddressIndex::New; //! //! fn main() -> Result<(), bdk::Error> { -//! let wallet = Wallet::new_offline( +//! let wallet = Wallet::new_offline( //! "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)", //! Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"), //! bitcoin::Network::Testnet, //! MemoryDatabase::default(), //! )?; //! -//! println!("Address #0: {}", wallet.get_new_address()?); -//! println!("Address #1: {}", wallet.get_new_address()?); -//! println!("Address #2: {}", wallet.get_new_address()?); +//! println!("Address #0: {}", wallet.get_address(New)?); +//! println!("Address #1: {}", wallet.get_address(New)?); +//! println!("Address #2: {}", wallet.get_address(New)?); //! //! Ok(()) //! } @@ -109,6 +110,7 @@ //! use bdk::electrum_client::Client; //! //! use bitcoin::consensus::serialize; +//! use bdk::wallet::AddressIndex::New; //! //! fn main() -> Result<(), bdk::Error> { //! let client = Client::new("ssl://electrum.blockstream.info:60002")?; @@ -122,7 +124,7 @@ //! //! wallet.sync(noop_progress(), None)?; //! -//! let send_to = wallet.get_new_address()?; +//! let send_to = wallet.get_address(New)?; //! let (psbt, details) = wallet.build_tx() //! .add_recipient(send_to.script_pubkey(), 50_000) //! .enable_rbf() diff --git a/src/wallet/address_validator.rs b/src/wallet/address_validator.rs index 368d278e..01ef35ef 100644 --- a/src/wallet/address_validator.rs +++ b/src/wallet/address_validator.rs @@ -20,7 +20,7 @@ //! An address validator can be attached to a [`Wallet`](super::Wallet) by using the //! [`Wallet::add_address_validator`](super::Wallet::add_address_validator) method, and //! whenever a new address is generated (either explicitly by the user with -//! [`Wallet::get_new_address`](super::Wallet::get_new_address) or internally to create a change +//! [`Wallet::get_address`](super::Wallet::get_address) or internally to create a change //! address) all the attached validators will be polled, in sequence. All of them must complete //! successfully to continue. //! @@ -32,6 +32,7 @@ //! # use bdk::address_validator::*; //! # use bdk::database::*; //! # use bdk::*; +//! # use bdk::wallet::AddressIndex::New; //! #[derive(Debug)] //! struct PrintAddressAndContinue; //! @@ -57,7 +58,7 @@ //! let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; //! wallet.add_address_validator(Arc::new(PrintAddressAndContinue)); //! -//! let address = wallet.get_new_address()?; +//! let address = wallet.get_address(New)?; //! println!("Address: {}", address); //! # Ok::<(), bdk::Error>(()) //! ``` @@ -115,6 +116,7 @@ mod test { use super::*; use crate::wallet::test::{get_funded_wallet, get_test_wpkh}; + use crate::wallet::AddressIndex::New; #[derive(Debug)] struct TestValidator; @@ -135,7 +137,7 @@ mod test { let (mut wallet, _, _) = get_funded_wallet(get_test_wpkh()); wallet.add_address_validator(Arc::new(TestValidator)); - wallet.get_new_address().unwrap(); + wallet.get_address(New).unwrap(); } #[test] diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 2b17871a..406ca3c7 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -67,7 +67,7 @@ const CACHE_ADDR_BATCH_SIZE: u32 = 100; /// /// A wallet takes descriptors, a [`database`](trait@crate::database::Database) and a /// [`blockchain`](trait@crate::blockchain::Blockchain) and implements the basic functions that a Bitcoin wallets -/// needs to operate, like [generating addresses](Wallet::get_new_address), [returning the balance](Wallet::get_balance), +/// needs to operate, like [generating addresses](Wallet::get_address), [returning the balance](Wallet::get_balance), /// [creating transactions](Wallet::build_tx), etc. /// /// A wallet can be either "online" if the [`blockchain`](crate::blockchain) type provided @@ -162,54 +162,87 @@ where } } +/// The address index selection strategy to use to derived an address from the wallet's external +/// descriptor. See [`Wallet::get_address`]. +#[derive(Debug)] +pub enum AddressIndex { + /// Return the address for a specific descriptor index. Does not change the current descriptor + /// index used by `AddressIndex::New` and `AddressIndex::LastUsed`. + /// + /// Use with caution, if an index is given that is less than the current descriptor index + /// then the returned address may have already been used. + Peek(u32), + /// Return a new address after incrementing the current descriptor index. + New, + /// Return the address for the current descriptor index if it has not been used in a received + /// transaction. Otherwise return a new address as with [`AddressIndex::New`]. + /// + /// Use with caution, if the wallet has not yet detected an address has been used it could + /// return an already used address. This function is primarily meant for situations where the + /// caller is untrusted; for example when deriving donation addresses on-demand for a public + /// web page. + LastUnused, +} + // offline actions, always available impl Wallet where D: BatchDatabase, { - /// Return a newly generated address using the external descriptor - pub fn get_new_address(&self) -> Result { - let index = self.fetch_and_increment_index(KeychainKind::External)?; - + // Return derived address for the external descriptor at a specific index + fn peek_address(&self, index: u32) -> Result { self.descriptor .as_derived(index, &self.secp) .address(self.network) .map_err(|_| Error::ScriptDoesntHaveAddressForm) } - /// Return the the last previously generated address if it has not been used in a received - /// transaction. Otherwise return a new address using [`Wallet::get_new_address`]. - /// - /// Use with caution, if the wallet has not yet detected an address has been used it could - /// return an already used address. This function is primarily meant for situations where the - /// caller is untrusted; for example when generating donation addresses on-demand for a public - /// web page. - /// - pub fn get_unused_address(&self) -> Result { - let index = self.fetch_index(KeychainKind::External)?; + // Return a newly derived address using the external descriptor + fn get_new_address(&self) -> Result { + let incremented_index = self.fetch_and_increment_index(KeychainKind::External)?; - let script = self - .descriptor - .as_derived(index, &self.secp) - .script_pubkey(); + self.descriptor + .as_derived(incremented_index, &self.secp) + .address(self.network) + .map_err(|_| Error::ScriptDoesntHaveAddressForm) + } + + // Return the the last previously derived address if it has not been used in a received + // transaction. Otherwise return a new address using [`Wallet::get_new_address`]. + fn get_unused_address(&self) -> Result { + let current_index = self.fetch_index(KeychainKind::External)?; + + let derived_key = self.descriptor.as_derived(current_index, &self.secp); + + let script_pubkey = derived_key.script_pubkey(); let found_used = self .list_transactions(true)? .iter() .flat_map(|tx_details| tx_details.transaction.as_ref()) .flat_map(|tx| tx.output.iter()) - .any(|o| o.script_pubkey == script); + .any(|o| o.script_pubkey == script_pubkey); if found_used { self.get_new_address() } else { - self.descriptor - .as_derived(index, &self.secp) + derived_key .address(self.network) .map_err(|_| Error::ScriptDoesntHaveAddressForm) } } + /// Return a derived address using the external descriptor, see [`AddressIndex`] for + /// available address index selection strategies. If the wallet descriptor is not derivable + /// (ie. does not end with /*) then the same address will always be returned for any [`AddressIndex`]. + pub fn get_address(&self, address_index: AddressIndex) -> Result { + match address_index { + AddressIndex::New => self.get_new_address(), + AddressIndex::LastUnused => self.get_unused_address(), + AddressIndex::Peek(index) => self.peek_address(index), + } + } + /// Return whether or not a `script` is part of this wallet (either internal or external) pub fn is_mine(&self, script: &Script) -> Result { self.database.borrow().is_mine(script) @@ -1417,6 +1450,7 @@ mod test { use crate::types::KeychainKind; use super::*; + use crate::wallet::AddressIndex::{LastUnused, New, Peek}; #[test] fn test_cache_addresses_fixed() { @@ -1430,11 +1464,11 @@ mod test { .unwrap(); assert_eq!( - wallet.get_new_address().unwrap().to_string(), + wallet.get_address(New).unwrap().to_string(), "tb1qj08ys4ct2hzzc2hcz6h2hgrvlmsjynaw43s835" ); assert_eq!( - wallet.get_new_address().unwrap().to_string(), + wallet.get_address(New).unwrap().to_string(), "tb1qj08ys4ct2hzzc2hcz6h2hgrvlmsjynaw43s835" ); @@ -1458,11 +1492,11 @@ mod test { let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap(); assert_eq!( - wallet.get_new_address().unwrap().to_string(), + wallet.get_address(New).unwrap().to_string(), "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" ); assert_eq!( - wallet.get_new_address().unwrap().to_string(), + wallet.get_address(New).unwrap().to_string(), "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7" ); @@ -1486,7 +1520,7 @@ mod test { let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap(); assert_eq!( - wallet.get_new_address().unwrap().to_string(), + wallet.get_address(New).unwrap().to_string(), "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" ); assert!(wallet @@ -1497,7 +1531,7 @@ mod test { .is_some()); for _ in 0..CACHE_ADDR_BATCH_SIZE { - wallet.get_new_address().unwrap(); + wallet.get_address(New).unwrap(); } assert!(wallet @@ -1594,7 +1628,7 @@ mod test { #[should_panic(expected = "NoUtxosSelected")] fn test_create_tx_manually_selected_empty_utxos() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1606,7 +1640,7 @@ mod test { #[should_panic(expected = "Invalid version `0`")] fn test_create_tx_version_0() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1620,7 +1654,7 @@ mod test { )] fn test_create_tx_version_1_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1631,7 +1665,7 @@ mod test { #[test] fn test_create_tx_custom_version() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1644,7 +1678,7 @@ mod test { #[test] fn test_create_tx_default_locktime() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, _) = builder.finish().unwrap(); @@ -1655,7 +1689,7 @@ mod test { #[test] fn test_create_tx_default_locktime_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, _) = builder.finish().unwrap(); @@ -1666,7 +1700,7 @@ mod test { #[test] fn test_create_tx_custom_locktime() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1679,7 +1713,7 @@ mod test { #[test] fn test_create_tx_custom_locktime_compatible_with_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1695,7 +1729,7 @@ mod test { )] fn test_create_tx_custom_locktime_incompatible_with_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1706,7 +1740,7 @@ mod test { #[test] fn test_create_tx_no_rbf_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, _) = builder.finish().unwrap(); @@ -1717,7 +1751,7 @@ mod test { #[test] fn test_create_tx_with_default_rbf_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1734,7 +1768,7 @@ mod test { )] fn test_create_tx_with_custom_rbf_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1745,7 +1779,7 @@ mod test { #[test] fn test_create_tx_no_rbf_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, _) = builder.finish().unwrap(); @@ -1757,7 +1791,7 @@ mod test { #[should_panic(expected = "Cannot enable RBF with a nSequence >= 0xFFFFFFFE")] fn test_create_tx_invalid_rbf_sequence() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1768,7 +1802,7 @@ mod test { #[test] fn test_create_tx_custom_rbf_sequence() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1781,7 +1815,7 @@ mod test { #[test] fn test_create_tx_default_sequence() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, _) = builder.finish().unwrap(); @@ -1795,7 +1829,7 @@ mod test { )] fn test_create_tx_change_policy_no_internal() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1806,7 +1840,7 @@ mod test { #[test] fn test_create_tx_single_recipient_drain_wallet() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -1823,7 +1857,7 @@ mod test { #[test] fn test_create_tx_default_fee_rate() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, details) = builder.finish().unwrap(); @@ -1834,7 +1868,7 @@ mod test { #[test] fn test_create_tx_custom_fee_rate() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1847,7 +1881,7 @@ mod test { #[test] fn test_create_tx_absolute_fee() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -1866,7 +1900,7 @@ mod test { #[test] fn test_create_tx_absolute_zero_fee() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -1886,7 +1920,7 @@ mod test { #[should_panic(expected = "InsufficientFunds")] fn test_create_tx_absolute_high_fee() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -1900,7 +1934,7 @@ mod test { use super::tx_builder::TxOrdering; let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -1918,7 +1952,7 @@ mod test { #[test] fn test_create_tx_skip_change_dust() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 49_800); let (psbt, details) = builder.finish().unwrap(); @@ -1932,7 +1966,7 @@ mod test { #[should_panic(expected = "InsufficientFunds")] fn test_create_tx_single_recipient_dust_amount() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); // very high fee rate, so that the only output would be below dust let mut builder = wallet.build_tx(); builder @@ -1945,7 +1979,7 @@ mod test { #[test] fn test_create_tx_ordering_respected() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 30_000) @@ -1965,7 +1999,7 @@ mod test { #[test] fn test_create_tx_default_sighash() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 30_000); let (psbt, _) = builder.finish().unwrap(); @@ -1976,7 +2010,7 @@ mod test { #[test] fn test_create_tx_custom_sighash() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 30_000) @@ -1995,7 +2029,7 @@ mod test { use std::str::FromStr; let (wallet, _, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2019,7 +2053,7 @@ mod test { let (wallet, descriptors, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)"); // cache some addresses - wallet.get_new_address().unwrap(); + wallet.get_address(New).unwrap(); let addr = testutils!(@external descriptors, 5); let mut builder = wallet.build_tx(); @@ -2044,7 +2078,7 @@ mod test { let (wallet, _, _) = get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2069,7 +2103,7 @@ mod test { let (wallet, _, _) = get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2094,7 +2128,7 @@ mod test { let (wallet, _, _) = get_funded_wallet("sh(wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2116,7 +2150,7 @@ mod test { fn test_create_tx_non_witness_utxo() { let (wallet, _, _) = get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2131,7 +2165,7 @@ mod test { fn test_create_tx_only_witness_utxo() { let (wallet, _, _) = get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2146,7 +2180,7 @@ mod test { fn test_create_tx_shwpkh_has_witness_utxo() { let (wallet, _, _) = get_funded_wallet("sh(wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2161,7 +2195,7 @@ mod test { fn test_create_tx_both_non_witness_utxo_and_witness_utxo() { let (wallet, _, _) = get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -2280,7 +2314,7 @@ mod test { use bitcoin::util::psbt::raw::Key; let (wallet, _, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -2486,7 +2520,7 @@ mod test { )] fn test_create_tx_global_xpubs_origin_missing() { let (wallet, _, _) = get_funded_wallet("wpkh(tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -2501,7 +2535,7 @@ mod test { use bitcoin::util::psbt::raw::Key; let (wallet, _, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -2525,7 +2559,7 @@ mod test { #[should_panic(expected = "IrreplaceableTransaction")] fn test_bump_fee_irreplaceable_tx() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, mut details) = builder.finish().unwrap(); @@ -2543,7 +2577,7 @@ mod test { #[should_panic(expected = "TransactionConfirmed")] fn test_bump_fee_confirmed_tx() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); let (psbt, mut details) = builder.finish().unwrap(); @@ -2562,7 +2596,7 @@ mod test { #[should_panic(expected = "FeeRateTooLow")] fn test_bump_fee_low_fee_rate() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -2584,7 +2618,7 @@ mod test { #[should_panic(expected = "FeeTooLow")] fn test_bump_fee_low_abs() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -2606,7 +2640,7 @@ mod test { #[should_panic(expected = "FeeTooLow")] fn test_bump_fee_zero_abs() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), 25_000) @@ -3349,7 +3383,7 @@ mod test { #[test] fn test_sign_single_xprv() { let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -3383,7 +3417,7 @@ mod test { #[test] fn test_sign_single_xprv_bip44_path() { let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/44'/0'/0'/0/*)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -3400,7 +3434,7 @@ mod test { #[test] fn test_sign_single_xprv_sh_wpkh() { let (wallet, _, _) = get_funded_wallet("sh(wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*))"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -3418,7 +3452,7 @@ mod test { fn test_sign_single_wif() { let (wallet, _, _) = get_funded_wallet("wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -3435,7 +3469,7 @@ mod test { #[test] fn test_sign_single_xprv_no_hd_keypaths() { let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); - let addr = wallet.get_new_address().unwrap(); + let addr = wallet.get_address(New).unwrap(); let mut builder = wallet.build_tx(); builder .set_single_recipient(addr.script_pubkey()) @@ -3512,11 +3546,11 @@ mod test { None, Network::Testnet, db).unwrap(); assert_eq!( - wallet.get_unused_address().unwrap().to_string(), + wallet.get_address(LastUnused).unwrap().to_string(), "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" ); assert_eq!( - wallet.get_unused_address().unwrap().to_string(), + wallet.get_address(LastUnused).unwrap().to_string(), "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" ); } @@ -3534,7 +3568,7 @@ mod test { .unwrap(); assert_eq!( - wallet.get_unused_address().unwrap().to_string(), + wallet.get_address(LastUnused).unwrap().to_string(), "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" ); @@ -3546,7 +3580,62 @@ mod test { ); assert_eq!( - wallet.get_unused_address().unwrap().to_string(), + wallet.get_address(LastUnused).unwrap().to_string(), + "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7" + ); + } + + #[test] + fn test_peek_address_at_index() { + let db = MemoryDatabase::new(); + let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", + None, Network::Testnet, db).unwrap(); + + assert_eq!( + wallet.get_address(Peek(1)).unwrap().to_string(), + "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7" + ); + + assert_eq!( + wallet.get_address(Peek(0)).unwrap().to_string(), + "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" + ); + + assert_eq!( + wallet.get_address(Peek(2)).unwrap().to_string(), + "tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2" + ); + + // current new address is not affected + assert_eq!( + wallet.get_address(New).unwrap().to_string(), + "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" + ); + + assert_eq!( + wallet.get_address(New).unwrap().to_string(), + "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7" + ); + } + + #[test] + fn test_peek_address_at_index_not_derivable() { + let db = MemoryDatabase::new(); + let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/1)", + None, Network::Testnet, db).unwrap(); + + assert_eq!( + wallet.get_address(Peek(1)).unwrap().to_string(), + "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7" + ); + + assert_eq!( + wallet.get_address(Peek(0)).unwrap().to_string(), + "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7" + ); + + assert_eq!( + wallet.get_address(Peek(2)).unwrap().to_string(), "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7" ); } diff --git a/testutils-macros/src/lib.rs b/testutils-macros/src/lib.rs index 05188911..44c74e12 100644 --- a/testutils-macros/src/lib.rs +++ b/testutils-macros/src/lib.rs @@ -71,6 +71,7 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream use #root_ident::database::MemoryDatabase; use #root_ident::types::KeychainKind; use #root_ident::{Wallet, TxBuilder, FeeRate}; + use #root_ident::wallet::AddressIndex::New; use super::*; @@ -532,7 +533,7 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream #[serial] fn test_sync_receive_coinbase() { let (wallet, descriptors, mut test_client) = init_single_sig(); - let wallet_addr = wallet.get_new_address().unwrap(); + let wallet_addr = wallet.get_address(New).unwrap(); wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 0);