diff --git a/CHANGELOG.md b/CHANGELOG.md index 76fd6935..19da76e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Remove `BlockchainMarker`, `OfflineClient` and `OfflineWallet` in favor of just using the unit + type to mark for a missing client. + ## [v0.2.0] - [0.1.0-beta.1] ### Project diff --git a/README.md b/README.md index 2bf992f2..f13e2d32 100644 --- a/README.md +++ b/README.md @@ -66,11 +66,10 @@ fn main() -> Result<(), bdk::Error> { ### Generate a few addresses ```rust -use bdk::{Wallet, OfflineWallet}; -use bdk::database::MemoryDatabase; +use bdk::{Wallet, database::MemoryDatabase}; fn main() -> Result<(), bdk::Error> { - let wallet: OfflineWallet<_> = 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, @@ -126,13 +125,12 @@ fn main() -> Result<(), bdk::Error> { ### Sign a transaction ```rust,no_run -use bdk::{Wallet, OfflineWallet}; -use bdk::database::MemoryDatabase; +use bdk::{Wallet, database::MemoryDatabase}; use bitcoin::consensus::deserialize; fn main() -> Result<(), bdk::Error> { - let wallet: OfflineWallet<_> = Wallet::new_offline( + let wallet = Wallet::new_offline( "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)", Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"), bitcoin::Network::Testnet, diff --git a/examples/address_validator.rs b/examples/address_validator.rs index eccb1ff4..d00a239a 100644 --- a/examples/address_validator.rs +++ b/examples/address_validator.rs @@ -29,7 +29,7 @@ use bdk::database::MemoryDatabase; use bdk::descriptor::HDKeyPaths; use bdk::wallet::address_validator::{AddressValidator, AddressValidatorError}; use bdk::KeychainKind; -use bdk::{OfflineWallet, Wallet}; +use bdk::Wallet; use bitcoin::hashes::hex::FromHex; use bitcoin::util::bip32::Fingerprint; @@ -59,7 +59,7 @@ impl AddressValidator for DummyValidator { fn main() -> Result<(), bdk::Error> { let descriptor = "sh(and_v(v:pk(tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/*),after(630000)))"; - let mut wallet: OfflineWallet<_> = + let mut wallet = Wallet::new_offline(descriptor, None, Network::Regtest, MemoryDatabase::new())?; wallet.add_address_validator(Arc::new(DummyValidator)); diff --git a/examples/compiler.rs b/examples/compiler.rs index 73f2bd01..0f1ac481 100644 --- a/examples/compiler.rs +++ b/examples/compiler.rs @@ -40,7 +40,7 @@ use miniscript::policy::Concrete; use miniscript::Descriptor; use bdk::database::memory::MemoryDatabase; -use bdk::{KeychainKind, OfflineWallet, Wallet}; +use bdk::{KeychainKind, Wallet}; fn main() { env_logger::init_from_env( @@ -98,8 +98,7 @@ fn main() { Some("regtest") => Network::Regtest, Some("testnet") | _ => Network::Testnet, }; - let wallet: OfflineWallet<_> = - Wallet::new_offline(&format!("{}", descriptor), None, network, database).unwrap(); + let wallet = Wallet::new_offline(&format!("{}", descriptor), None, network, database).unwrap(); info!("... First address: {}", wallet.get_new_address().unwrap()); diff --git a/src/blockchain/mod.rs b/src/blockchain/mod.rs index 9f021275..66538816 100644 --- a/src/blockchain/mod.rs +++ b/src/blockchain/mod.rs @@ -79,29 +79,9 @@ pub enum Capability { AccurateFees, } -/// Marker trait for a blockchain backend -/// -/// This is a marker trait for blockchain types. It is automatically implemented for types that -/// implement [`Blockchain`], so as a user of the library you won't have to implement this -/// manually. -/// -/// Users of the library will probably never have to implement this trait manually, but they -/// could still need to import it to define types and structs with generics; -/// Implementing only the marker trait is pointless, since [`OfflineBlockchain`] -/// already does that, and whenever [`Blockchain`] is implemented, the marker trait is also -/// automatically implemented by the library. -pub trait BlockchainMarker {} - -/// The [`BlockchainMarker`] marker trait is automatically implemented for [`Blockchain`] types -impl BlockchainMarker for T {} - -/// Type that only implements [`BlockchainMarker`] and is always "offline" -pub struct OfflineBlockchain; -impl BlockchainMarker for OfflineBlockchain {} - /// Trait that defines the actions that must be supported by a blockchain backend #[maybe_async] -pub trait Blockchain: BlockchainMarker { +pub trait Blockchain { /// Return the set of [`Capability`] supported by this backend fn get_capabilities(&self) -> HashSet; diff --git a/src/database/any.rs b/src/database/any.rs index 0e842b3d..64dd4772 100644 --- a/src/database/any.rs +++ b/src/database/any.rs @@ -29,20 +29,20 @@ //! //! ## Example //! -//! In this example, `wallet_memory` and `wallet_sled` have the same type of `Wallet`. +//! In this example, `wallet_memory` and `wallet_sled` have the same type of `Wallet<(), AnyDatabase>`. //! //! ```no_run //! # use bitcoin::Network; //! # use bdk::database::{AnyDatabase, MemoryDatabase}; -//! # use bdk::{Wallet, OfflineWallet}; -//! let memory = MemoryDatabase::default().into(); -//! let wallet_memory: OfflineWallet = +//! # use bdk::{Wallet}; +//! let memory = MemoryDatabase::default(); +//! let wallet_memory = //! Wallet::new_offline("...", None, Network::Testnet, memory)?; //! //! # #[cfg(feature = "key-value-db")] //! # { -//! let sled = sled::open("my-database")?.open_tree("default_tree")?.into(); -//! let wallet_sled: OfflineWallet = +//! let sled = sled::open("my-database")?.open_tree("default_tree")?; +//! let wallet_sled = //! Wallet::new_offline("...", None, Network::Testnet, sled)?; //! # } //! # Ok::<(), bdk::Error>(()) @@ -54,10 +54,10 @@ //! ```no_run //! # use bitcoin::Network; //! # use bdk::database::*; -//! # use bdk::{Wallet, OfflineWallet}; +//! # use bdk::{Wallet}; //! let config = serde_json::from_str("...")?; //! let database = AnyDatabase::from_config(&config)?; -//! let wallet: OfflineWallet<_> = Wallet::new_offline("...", None, Network::Testnet, database)?; +//! let wallet = Wallet::new_offline("...", None, Network::Testnet, database)?; //! # Ok::<(), bdk::Error>(()) //! ``` diff --git a/src/descriptor/template.rs b/src/descriptor/template.rs index 6b832f30..6a14e919 100644 --- a/src/descriptor/template.rs +++ b/src/descriptor/template.rs @@ -81,13 +81,13 @@ impl ToWalletDescriptor for T { /// /// ``` /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet}; +/// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::P2PKH; /// /// let key = /// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// P2PKH(key), /// None, /// Network::Testnet, @@ -114,13 +114,13 @@ impl> DescriptorTemplate for P2PKH { /// /// ``` /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet}; +/// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::P2WPKH_P2SH; /// /// let key = /// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// P2WPKH_P2SH(key), /// None, /// Network::Testnet, @@ -148,13 +148,13 @@ impl> DescriptorTemplate for P2WPKH_P2SH { /// /// ``` /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet}; +/// # use bdk::{Wallet}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::P2WPKH; /// /// let key = /// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// P2WPKH(key), /// None, /// Network::Testnet, @@ -186,12 +186,12 @@ impl> DescriptorTemplate for P2WPKH { /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet, KeychainKind}; +/// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP44; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// BIP44(key.clone(), KeychainKind::External), /// Some(BIP44(key, KeychainKind::Internal)), /// Network::Testnet, @@ -224,13 +224,13 @@ impl> DescriptorTemplate for BIP44 { /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet, KeychainKind}; +/// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP44Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?; /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// BIP44Public(key.clone(), fingerprint, KeychainKind::External), /// Some(BIP44Public(key, fingerprint, KeychainKind::Internal)), /// Network::Testnet, @@ -260,12 +260,12 @@ impl> DescriptorTemplate for BIP44Public { /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet, KeychainKind}; +/// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP49; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// BIP49(key.clone(), KeychainKind::External), /// Some(BIP49(key, KeychainKind::Internal)), /// Network::Testnet, @@ -298,13 +298,13 @@ impl> DescriptorTemplate for BIP49 { /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet, KeychainKind}; +/// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP49Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?; /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// BIP49Public(key.clone(), fingerprint, KeychainKind::External), /// Some(BIP49Public(key, fingerprint, KeychainKind::Internal)), /// Network::Testnet, @@ -334,12 +334,12 @@ impl> DescriptorTemplate for BIP49Public { /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet, KeychainKind}; +/// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP84; /// /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// BIP84(key.clone(), KeychainKind::External), /// Some(BIP84(key, KeychainKind::Internal)), /// Network::Testnet, @@ -372,13 +372,13 @@ impl> DescriptorTemplate for BIP84 { /// ``` /// # use std::str::FromStr; /// # use bdk::bitcoin::{PrivateKey, Network}; -/// # use bdk::{Wallet, OfflineWallet, KeychainKind}; +/// # use bdk::{Wallet, KeychainKind}; /// # use bdk::database::MemoryDatabase; /// use bdk::template::BIP84Public; /// /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; -/// let wallet: OfflineWallet<_> = Wallet::new_offline( +/// let wallet = Wallet::new_offline( /// BIP84Public(key.clone(), fingerprint, KeychainKind::External), /// Some(BIP84Public(key, fingerprint, KeychainKind::Internal)), /// Network::Testnet, diff --git a/src/error.rs b/src/error.rs index 8f137f1f..b1fd9bbf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -89,11 +89,6 @@ pub enum Error { /// Signing error Signer(crate::wallet::signer::SignerError), - // Blockchain interface errors - /// Thrown when trying to call a method that requires a network connection, [`Wallet::sync`](crate::Wallet::sync) and [`Wallet::broadcast`](crate::Wallet::broadcast) - /// This error is thrown when creating the Client for the first time, while recovery attempts are tried - /// during the sync - OfflineClient, /// Progress value must be between `0.0` (included) and `100.0` (included) InvalidProgressValue(f32), /// Progress update error (maybe the channel has been closed) diff --git a/src/lib.rs b/src/lib.rs index 3991aed6..163f4c3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,11 +91,11 @@ //! //! ### Example //! ``` -//! use bdk::{Wallet, OfflineWallet}; +//! use bdk::{Wallet}; //! use bdk::database::MemoryDatabase; //! //! fn main() -> Result<(), bdk::Error> { -//! let wallet: OfflineWallet<_> = 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, @@ -155,13 +155,13 @@ //! ### Example //! ```ignore //! use base64::decode; -//! use bdk::{Wallet, OfflineWallet}; +//! use bdk::{Wallet}; //! use bdk::database::MemoryDatabase; //! //! use bitcoin::consensus::deserialize; //! //! fn main() -> Result<(), bdk::Error> { -//! let wallet: OfflineWallet<_> = Wallet::new_offline( +//! let wallet = Wallet::new_offline( //! "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)", //! Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"), //! bitcoin::Network::Testnet, @@ -268,4 +268,4 @@ pub use types::*; pub use wallet::address_validator; pub use wallet::signer; pub use wallet::tx_builder::TxBuilder; -pub use wallet::{OfflineWallet, Wallet}; +pub use wallet::Wallet; diff --git a/src/wallet/address_validator.rs b/src/wallet/address_validator.rs index 26f15a25..c1555f6c 100644 --- a/src/wallet/address_validator.rs +++ b/src/wallet/address_validator.rs @@ -66,7 +66,7 @@ //! } //! //! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; -//! let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; +//! 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()?; diff --git a/src/wallet/coin_selection.rs b/src/wallet/coin_selection.rs index f964f5dc..87808db1 100644 --- a/src/wallet/coin_selection.rs +++ b/src/wallet/coin_selection.rs @@ -84,7 +84,7 @@ //! } //! } //! -//! # let wallet: OfflineWallet<_> = Wallet::new_offline("", None, Network::Testnet, bdk::database::MemoryDatabase::default())?; +//! # let wallet = Wallet::new_offline("", None, Network::Testnet, bdk::database::MemoryDatabase::default())?; //! // create wallet, sync, ... //! //! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); diff --git a/src/wallet/export.rs b/src/wallet/export.rs index 9f17e9d5..cb367b35 100644 --- a/src/wallet/export.rs +++ b/src/wallet/export.rs @@ -43,7 +43,7 @@ //! }"#; //! //! let import = WalletExport::from_str(import)?; -//! let wallet: OfflineWallet<_> = Wallet::new_offline( +//! let wallet = Wallet::new_offline( //! &import.descriptor(), //! import.change_descriptor().as_ref(), //! Network::Testnet, @@ -58,7 +58,7 @@ //! # use bdk::database::*; //! # use bdk::wallet::export::*; //! # use bdk::*; -//! let wallet: OfflineWallet<_> = Wallet::new_offline( +//! let wallet = Wallet::new_offline( //! "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/0/*)", //! Some("wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)"), //! Network::Testnet, @@ -78,7 +78,6 @@ use serde::{Deserialize, Serialize}; use miniscript::{Descriptor, DescriptorPublicKey, ScriptContext, Terminal}; -use crate::blockchain::BlockchainMarker; use crate::database::BatchDatabase; use crate::wallet::Wallet; @@ -120,7 +119,7 @@ impl WalletExport { /// /// If the database is empty or `include_blockheight` is false, the `blockheight` field /// returned will be `0`. - pub fn export_wallet( + pub fn export_wallet( wallet: &Wallet, label: &str, include_blockheight: bool, @@ -208,7 +207,7 @@ mod test { use super::*; use crate::database::{memory::MemoryDatabase, BatchOperations}; use crate::types::TransactionDetails; - use crate::wallet::{OfflineWallet, Wallet}; + use crate::wallet::Wallet; fn get_test_db() -> MemoryDatabase { let mut db = MemoryDatabase::new(); @@ -234,7 +233,7 @@ mod test { let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)"; let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)"; - let wallet: OfflineWallet<_> = Wallet::new_offline( + let wallet = Wallet::new_offline( descriptor, Some(change_descriptor), Network::Bitcoin, @@ -258,7 +257,7 @@ mod test { let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)"; - let wallet: OfflineWallet<_> = + let wallet = Wallet::new_offline(descriptor, None, Network::Bitcoin, get_test_db()).unwrap(); WalletExport::export_wallet(&wallet, "Test Label", true).unwrap(); } @@ -272,7 +271,7 @@ mod test { let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)"; let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/50'/0'/1/*)"; - let wallet: OfflineWallet<_> = Wallet::new_offline( + let wallet = Wallet::new_offline( descriptor, Some(change_descriptor), Network::Bitcoin, @@ -295,7 +294,7 @@ mod test { [c98b1535/48'/0'/0'/2']tpubDCDi5W4sP6zSnzJeowy8rQDVhBdRARaPhK1axABi8V1661wEPeanpEXj4ZLAUEoikVtoWcyK26TKKJSecSfeKxwHCcRrge9k1ybuiL71z4a/1/*\ ))"; - let wallet: OfflineWallet<_> = Wallet::new_offline( + let wallet = Wallet::new_offline( descriptor, Some(change_descriptor), Network::Testnet, @@ -315,7 +314,7 @@ mod test { let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)"; let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)"; - let wallet: OfflineWallet<_> = Wallet::new_offline( + let wallet = Wallet::new_offline( descriptor, Some(change_descriptor), Network::Bitcoin, diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 6db8f8d9..99e5b05c 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -61,7 +61,7 @@ use signer::{Signer, SignerId, SignerOrdering, SignersContainer}; use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxBuilderContext}; use utils::{check_nlocktime, check_nsequence_rbf, descriptor_to_pk_ctx, After, Older, SecpCtx}; -use crate::blockchain::{Blockchain, BlockchainMarker, OfflineBlockchain, Progress}; +use crate::blockchain::{Blockchain, Progress}; use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils}; use crate::descriptor::{ get_checksum, DescriptorMeta, DescriptorScripts, ExtendedDescriptor, ExtractPolicy, Policy, @@ -73,9 +73,6 @@ use crate::types::*; const CACHE_ADDR_BATCH_SIZE: u32 = 100; -/// Type alias for a [`Wallet`] that uses [`OfflineBlockchain`] -pub type OfflineWallet = Wallet; - /// A Bitcoin wallet /// /// A wallet takes descriptors, a [`database`](trait@crate::database::Database) and a @@ -84,7 +81,7 @@ pub type OfflineWallet = Wallet; /// [creating transactions](Wallet::create_tx), etc. /// /// A wallet can be either "online" if the [`blockchain`](crate::blockchain) type provided -/// implements [`Blockchain`], or "offline" [`OfflineBlockchain`] is used. Offline wallets only expose +/// implements [`Blockchain`], or "offline" if it is the unit type `()`. Offline wallets only expose /// methods that don't need any interaction with the blockchain to work. pub struct Wallet { descriptor: ExtendedDescriptor, @@ -99,24 +96,38 @@ pub struct Wallet { current_height: Option, - client: Option, + client: B, database: RefCell, secp: SecpCtx, } -// offline actions, always available -impl Wallet +impl Wallet<(), D> where - B: BlockchainMarker, D: BatchDatabase, { /// Create a new "offline" wallet pub fn new_offline( + descriptor: E, + change_descriptor: Option, + network: Network, + database: D, + ) -> Result { + Self::_new(descriptor, change_descriptor, network, database, (), None) + } +} + +impl Wallet +where + D: BatchDatabase, +{ + fn _new( descriptor: E, change_descriptor: Option, network: Network, mut database: D, + client: B, + current_height: Option, ) -> Result { let (descriptor, keymap) = descriptor.to_wallet_descriptor(network)?; database.check_descriptor_checksum( @@ -148,18 +159,20 @@ where signers, change_signers, address_validators: Vec::new(), - network, - - current_height: None, - - client: None, + current_height, + client, database: RefCell::new(database), - secp: Secp256k1::new(), }) } +} +// 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)?; @@ -241,7 +254,7 @@ where /// # use bdk::*; /// # use bdk::database::*; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; - /// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; + /// # let wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); /// let (psbt, details) = wallet.create_tx( /// TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)]) @@ -556,7 +569,7 @@ where /// # use bdk::*; /// # use bdk::database::*; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; - /// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; + /// # let wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; /// let txid = Txid::from_str("faff0a466b70f5d5f92bd757a92c1371d4838bdd5bc53a06764e2488e51ce8f8").unwrap(); /// let (psbt, details) = wallet.bump_fee( /// &txid, @@ -820,7 +833,7 @@ where /// # use bdk::*; /// # use bdk::database::*; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; - /// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; + /// # let wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; /// # let (psbt, _) = wallet.create_tx(TxBuilder::new())?; /// let (signed_psbt, finalized) = wallet.sign(psbt, None)?; /// # Ok::<(), bdk::Error>(()) @@ -1319,12 +1332,15 @@ where database: D, client: B, ) -> Result { - let mut wallet = Self::new_offline(descriptor, change_descriptor, network, database)?; - - wallet.current_height = Some(maybe_await!(client.get_height())? as u32); - wallet.client = Some(client); - - Ok(wallet) + let current_height = Some(maybe_await!(client.get_height())? as u32); + Self::_new( + descriptor, + change_descriptor, + network, + database, + client, + current_height, + ) } /// Sync the internal database with the blockchain @@ -1372,13 +1388,13 @@ where // TODO: what if i generate an address first and cache some addresses? // TODO: we should sync if generating an address triggers a new batch to be stored if run_setup { - maybe_await!(self.client.as_ref().ok_or(Error::OfflineClient)?.setup( + maybe_await!(self.client.setup( None, self.database.borrow_mut().deref_mut(), progress_update, )) } else { - maybe_await!(self.client.as_ref().ok_or(Error::OfflineClient)?.sync( + maybe_await!(self.client.sync( None, self.database.borrow_mut().deref_mut(), progress_update, @@ -1387,8 +1403,8 @@ where } /// Return a reference to the internal blockchain client - pub fn client(&self) -> Option<&B> { - self.client.as_ref() + pub fn client(&self) -> &B { + &self.client } /// Get the Bitcoin network the wallet is using. @@ -1399,11 +1415,7 @@ where /// Broadcast a transaction to the network #[maybe_async] pub fn broadcast(&self, tx: Transaction) -> Result { - maybe_await!(self - .client - .as_ref() - .ok_or(Error::OfflineClient)? - .broadcast(&tx))?; + maybe_await!(self.client.broadcast(&tx))?; Ok(tx.txid()) } @@ -1424,7 +1436,7 @@ mod test { #[test] fn test_cache_addresses_fixed() { let db = MemoryDatabase::new(); - let wallet: OfflineWallet<_> = Wallet::new_offline( + let wallet = Wallet::new_offline( "wpkh(L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6)", None, Network::Testnet, @@ -1458,7 +1470,7 @@ mod test { #[test] fn test_cache_addresses() { let db = MemoryDatabase::new(); - let wallet: OfflineWallet<_> = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap(); + let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap(); assert_eq!( wallet.get_new_address().unwrap().to_string(), @@ -1486,7 +1498,7 @@ mod test { #[test] fn test_cache_addresses_refill() { let db = MemoryDatabase::new(); - let wallet: OfflineWallet<_> = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap(); + let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap(); assert_eq!( wallet.get_new_address().unwrap().to_string(), @@ -1533,12 +1545,12 @@ mod test { pub(crate) fn get_funded_wallet( descriptor: &str, ) -> ( - OfflineWallet, + Wallet<(), MemoryDatabase>, (String, Option), bitcoin::Txid, ) { let descriptors = testutils!(@descriptors (descriptor)); - let wallet: OfflineWallet<_> = Wallet::new_offline( + let wallet = Wallet::new_offline( &descriptors.0, None, Network::Regtest, diff --git a/src/wallet/signer.rs b/src/wallet/signer.rs index bdac195b..650bdf26 100644 --- a/src/wallet/signer.rs +++ b/src/wallet/signer.rs @@ -79,7 +79,7 @@ //! let custom_signer = CustomSigner::connect(); //! //! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; -//! let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; +//! let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?; //! wallet.add_signer( //! KeychainKind::External, //! Fingerprint::from_str("e30f11b8").unwrap().into(),