diff --git a/bdk-ffi/src/bitcoin.rs b/bdk-ffi/src/bitcoin.rs index aabbbb8f..49618597 100644 --- a/bdk-ffi/src/bitcoin.rs +++ b/bdk-ffi/src/bitcoin.rs @@ -40,7 +40,7 @@ use std::sync::{Arc, Mutex}; #[derive(Debug, Clone, Eq, PartialEq, uniffi:: Record)] pub struct OutPoint { /// The transaction. - pub txid: String, + pub txid: Arc, /// The index of the output in the transaction. pub vout: u32, } @@ -48,7 +48,7 @@ pub struct OutPoint { impl From<&BdkOutPoint> for OutPoint { fn from(outpoint: &BdkOutPoint) -> Self { OutPoint { - txid: outpoint.txid.to_string(), + txid: Arc::new(Txid(outpoint.txid)), vout: outpoint.vout, } } @@ -57,7 +57,7 @@ impl From<&BdkOutPoint> for OutPoint { impl From for BdkOutPoint { fn from(outpoint: OutPoint) -> Self { BdkOutPoint { - txid: BitcoinTxid::from_str(&outpoint.txid).unwrap(), + txid: BitcoinTxid::from_raw_hash(outpoint.txid.0.to_raw_hash()), vout: outpoint.vout, } } @@ -169,9 +169,9 @@ pub struct Header { /// Block version, now repurposed for soft fork signalling. pub version: i32, /// Reference to the previous block in the chain. - pub prev_blockhash: String, + pub prev_blockhash: Arc, /// The root hash of the merkle tree of transactions in the block. - pub merkle_root: String, + pub merkle_root: Arc, /// The timestamp of the block, as claimed by the miner. pub time: u32, /// The target value below which the blockhash must lie. @@ -184,8 +184,8 @@ impl From for Header { fn from(bdk_header: BdkHeader) -> Self { Header { version: bdk_header.version.to_consensus(), - prev_blockhash: bdk_header.prev_blockhash.to_string(), - merkle_root: bdk_header.merkle_root.to_string(), + prev_blockhash: Arc::new(BlockHash(bdk_header.prev_blockhash)), + merkle_root: Arc::new(TxMerkleNode(bdk_header.merkle_root.to_raw_hash())), time: bdk_header.time, bits: bdk_header.bits.to_consensus(), nonce: bdk_header.nonce, @@ -304,8 +304,8 @@ impl Transaction { /// Computes the Txid. /// Hashes the transaction excluding the segwit data (i.e. the marker, flag bytes, and the witness fields themselves). - pub fn compute_txid(&self) -> String { - self.0.compute_txid().to_string() + pub fn compute_txid(&self) -> Arc { + Arc::new(Txid(self.0.compute_txid())) } /// Returns the weight of this transaction, as defined by BIP-141. @@ -549,7 +549,7 @@ impl From<&BdkTxIn> for TxIn { fn from(tx_in: &BdkTxIn) -> Self { TxIn { previous_output: OutPoint { - txid: tx_in.previous_output.txid.to_string(), + txid: Arc::new(Txid(tx_in.previous_output.txid)), vout: tx_in.previous_output.vout, }, script_sig: Arc::new(Script(tx_in.script_sig.clone())), diff --git a/bdk-ffi/src/descriptor.rs b/bdk-ffi/src/descriptor.rs index bdc05dfc..bc10c099 100644 --- a/bdk-ffi/src/descriptor.rs +++ b/bdk-ffi/src/descriptor.rs @@ -1,3 +1,4 @@ +use crate::bitcoin::DescriptorId; use crate::error::DescriptorError; use crate::keys::DescriptorPublicKey; use crate::keys::DescriptorSecretKey; @@ -5,6 +6,7 @@ use crate::keys::DescriptorSecretKey; use bdk_wallet::bitcoin::bip32::Fingerprint; use bdk_wallet::bitcoin::key::Secp256k1; use bdk_wallet::bitcoin::Network; +use bdk_wallet::chain::DescriptorExt; use bdk_wallet::descriptor::{ExtendedDescriptor, IntoWalletDescriptor}; use bdk_wallet::keys::DescriptorPublicKey as BdkDescriptorPublicKey; use bdk_wallet::keys::{DescriptorSecretKey as BdkDescriptorSecretKey, KeyMap}; @@ -296,6 +298,12 @@ impl Descriptor { self.extended_descriptor.is_multipath() } + /// A unique identifier for the descriptor. + pub fn descriptor_id(&self) -> Arc { + let d_id = self.extended_descriptor.descriptor_id(); + Arc::new(DescriptorId(d_id.0)) + } + /// Return descriptors for all valid paths. pub fn to_single_descriptors(&self) -> Result>, MiniscriptError> { self.extended_descriptor diff --git a/bdk-ffi/src/electrum.rs b/bdk-ffi/src/electrum.rs index bc3635fe..481625c9 100644 --- a/bdk-ffi/src/electrum.rs +++ b/bdk-ffi/src/electrum.rs @@ -1,4 +1,4 @@ -use crate::bitcoin::{Header, Transaction}; +use crate::bitcoin::{BlockHash, Header, Transaction, Txid}; use crate::error::ElectrumError; use crate::types::Update; use crate::types::{FullScanRequest, SyncRequest}; @@ -14,7 +14,6 @@ use bdk_wallet::bitcoin::Transaction as BdkTransaction; use bdk_wallet::KeychainKind; use bdk_wallet::Update as BdkUpdate; -use bdk_core::bitcoin::hex::{Case, DisplayHex}; use bdk_electrum::electrum_client::ElectrumApi; use std::collections::BTreeMap; use std::sync::Arc; @@ -131,12 +130,12 @@ impl ElectrumClient { } /// Broadcasts a transaction to the network. - pub fn transaction_broadcast(&self, tx: &Transaction) -> Result { + pub fn transaction_broadcast(&self, tx: &Transaction) -> Result, ElectrumError> { let bdk_transaction: BdkTransaction = tx.into(); self.0 .transaction_broadcast(&bdk_transaction) .map_err(ElectrumError::from) - .map(|txid| txid.to_string()) + .map(|txid| Arc::new(Txid(txid))) } /// Returns the capabilities of the server. @@ -177,7 +176,7 @@ pub struct ServerFeaturesRes { /// Server version reported. pub server_version: String, /// Hash of the genesis block. - pub genesis_hash: String, + pub genesis_hash: Arc, /// Minimum supported version of the protocol. pub protocol_min: String, /// Maximum supported version of the protocol. @@ -190,9 +189,10 @@ pub struct ServerFeaturesRes { impl From for ServerFeaturesRes { fn from(value: BdkServerFeaturesRes) -> ServerFeaturesRes { + let blockhash = BlockHash::from_bytes(value.genesis_hash.to_vec()).unwrap(); ServerFeaturesRes { server_version: value.server_version, - genesis_hash: value.genesis_hash.to_hex_string(Case::Lower), + genesis_hash: Arc::new(blockhash), protocol_min: value.protocol_min, protocol_max: value.protocol_max, hash_function: value.hash_function, diff --git a/bdk-ffi/src/esplora.rs b/bdk-ffi/src/esplora.rs index 86196e95..39865f7b 100644 --- a/bdk-ffi/src/esplora.rs +++ b/bdk-ffi/src/esplora.rs @@ -1,4 +1,6 @@ +use crate::bitcoin::BlockHash; use crate::bitcoin::Transaction; +use crate::bitcoin::Txid; use crate::error::EsploraError; use crate::types::Tx; use crate::types::TxStatus; @@ -8,7 +10,6 @@ use crate::types::{FullScanRequest, SyncRequest}; use bdk_esplora::esplora_client::{BlockingClient, Builder}; use bdk_esplora::EsploraExt; use bdk_wallet::bitcoin::Transaction as BdkTransaction; -use bdk_wallet::bitcoin::Txid; use bdk_wallet::chain::spk_client::FullScanRequest as BdkFullScanRequest; use bdk_wallet::chain::spk_client::FullScanResponse as BdkFullScanResponse; use bdk_wallet::chain::spk_client::SyncRequest as BdkSyncRequest; @@ -17,7 +18,6 @@ use bdk_wallet::KeychainKind; use bdk_wallet::Update as BdkUpdate; use std::collections::{BTreeMap, HashMap}; -use std::str::FromStr; use std::sync::Arc; /// Wrapper around an esplora_client::BlockingClient which includes an internal in-memory transaction @@ -110,9 +110,8 @@ impl EsploraClient { } /// Get a [`Transaction`] option given its [`Txid`]. - pub fn get_tx(&self, txid: String) -> Result>, EsploraError> { - let txid = Txid::from_str(&txid)?; - let tx_opt = self.0.get_tx(&txid)?; + pub fn get_tx(&self, txid: Arc) -> Result>, EsploraError> { + let tx_opt = self.0.get_tx(&txid.0)?; Ok(tx_opt.map(|inner| Arc::new(Transaction::from(inner)))) } @@ -128,27 +127,25 @@ impl EsploraClient { } /// Get the [`BlockHash`] of a specific block height. - pub fn get_block_hash(&self, block_height: u32) -> Result { + pub fn get_block_hash(&self, block_height: u32) -> Result, EsploraError> { self.0 .get_block_hash(block_height) - .map(|hash| hash.to_string()) + .map(|hash| Arc::new(BlockHash(hash))) .map_err(EsploraError::from) } /// Get the status of a [`Transaction`] given its [`Txid`]. - pub fn get_tx_status(&self, txid: String) -> Result { - let txid = Txid::from_str(&txid)?; + pub fn get_tx_status(&self, txid: Arc) -> Result { self.0 - .get_tx_status(&txid) + .get_tx_status(&txid.0) .map(TxStatus::from) .map_err(EsploraError::from) } /// Get transaction info given its [`Txid`]. - pub fn get_tx_info(&self, txid: String) -> Result, EsploraError> { - let txid = Txid::from_str(&txid)?; + pub fn get_tx_info(&self, txid: Arc) -> Result, EsploraError> { self.0 - .get_tx_info(&txid) + .get_tx_info(&txid.0) .map(|tx| tx.map(Tx::from)) .map_err(EsploraError::from) } diff --git a/bdk-ffi/src/tx_builder.rs b/bdk-ffi/src/tx_builder.rs index 64db08ea..93159015 100644 --- a/bdk-ffi/src/tx_builder.rs +++ b/bdk-ffi/src/tx_builder.rs @@ -1,4 +1,4 @@ -use crate::bitcoin::{Amount, FeeRate, OutPoint, Psbt, Script}; +use crate::bitcoin::{Amount, FeeRate, OutPoint, Psbt, Script, Txid}; use crate::error::CreateTxError; use crate::types::{LockTime, ScriptAmount}; use crate::wallet::Wallet; @@ -8,13 +8,12 @@ use bdk_wallet::bitcoin::amount::Amount as BdkAmount; use bdk_wallet::bitcoin::script::PushBytesBuf; use bdk_wallet::bitcoin::Psbt as BdkPsbt; use bdk_wallet::bitcoin::ScriptBuf as BdkScriptBuf; -use bdk_wallet::bitcoin::{OutPoint as BdkOutPoint, Sequence, Txid}; +use bdk_wallet::bitcoin::{OutPoint as BdkOutPoint, Sequence}; use bdk_wallet::KeychainKind; use std::collections::BTreeMap; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::str::FromStr; use std::sync::Arc; type ChangeSpendPolicy = bdk_wallet::ChangeSpendPolicy; @@ -413,7 +412,7 @@ impl TxBuilder { /// until finally calling `finish` to consume the builder and generate the transaction. #[derive(Clone, uniffi::Object)] pub struct BumpFeeTxBuilder { - txid: String, + txid: Arc, fee_rate: Arc, sequence: Option, current_height: Option, @@ -425,7 +424,7 @@ pub struct BumpFeeTxBuilder { #[uniffi::export] impl BumpFeeTxBuilder { #[uniffi::constructor] - pub fn new(txid: String, fee_rate: Arc) -> Self { + pub fn new(txid: Arc, fee_rate: Arc) -> Self { BumpFeeTxBuilder { txid, fee_rate, @@ -506,11 +505,10 @@ impl BumpFeeTxBuilder { /// WARNING: To avoid change address reuse you must persist the changes resulting from one or more calls to this /// method before closing the wallet. See `Wallet::reveal_next_address`. pub fn finish(&self, wallet: &Arc) -> Result, CreateTxError> { - let txid = Txid::from_str(self.txid.as_str()).map_err(|_| CreateTxError::UnknownUtxo { - outpoint: self.txid.clone(), - })?; let mut wallet = wallet.get_wallet(); - let mut tx_builder = wallet.build_fee_bump(txid).map_err(CreateTxError::from)?; + let mut tx_builder = wallet + .build_fee_bump(self.txid.0) + .map_err(CreateTxError::from)?; tx_builder.fee_rate(self.fee_rate.0); if let Some(sequence) = self.sequence { tx_builder.set_exact_sequence(Sequence(sequence)); diff --git a/bdk-ffi/src/types.rs b/bdk-ffi/src/types.rs index 05a030bb..f894edea 100644 --- a/bdk-ffi/src/types.rs +++ b/bdk-ffi/src/types.rs @@ -1,4 +1,4 @@ -use crate::bitcoin::{Address, Amount, OutPoint, Script, Transaction, TxOut}; +use crate::bitcoin::{Address, Amount, BlockHash, OutPoint, Script, Transaction, TxOut, Txid}; use crate::error::{CreateTxError, RequestBuilderError}; use bdk_core::bitcoin::absolute::LockTime as BdkLockTime; @@ -51,7 +51,7 @@ pub enum ChainPosition { /// A child transaction that has been confirmed. Due to incomplete information, /// it is only known that this transaction is confirmed at a chain height less than /// or equal to this child TXID. - transitively: Option, + transitively: Option>, }, /// The transaction was last seen in the mempool at this timestamp. Unconfirmed { timestamp: Option }, @@ -73,7 +73,7 @@ impl From> for ChainPosition { block_id, confirmation_time: anchor.confirmation_time, }, - transitively: transitively.map(|t| t.to_string()), + transitively: transitively.map(|t| Arc::new(Txid(t))), } } BdkChainPosition::Unconfirmed { last_seen } => ChainPosition::Unconfirmed { @@ -203,7 +203,7 @@ impl From for LocalOutput { fn from(local_utxo: BdkLocalOutput) -> Self { LocalOutput { outpoint: OutPoint { - txid: local_utxo.outpoint.txid.to_string(), + txid: Arc::new(Txid(local_utxo.outpoint.txid)), vout: local_utxo.outpoint.vout, }, txout: TxOut { @@ -658,7 +658,7 @@ pub struct TxStatus { /// Height of the block this transaction was included. pub block_height: Option, /// Hash of the block. - pub block_hash: Option, + pub block_hash: Option>, /// The time shown in the block, not necessarily the same time as when the block was found. pub block_time: Option, } @@ -668,7 +668,7 @@ impl From for TxStatus { TxStatus { confirmed: status.confirmed, block_height: status.block_height, - block_hash: status.block_hash.map(|h| h.to_string()), + block_hash: status.block_hash.map(|h| Arc::new(BlockHash(h))), block_time: status.block_time, } } @@ -678,7 +678,7 @@ impl From for TxStatus { #[derive(Debug, uniffi::Record)] pub struct Tx { /// The transaction identifier. - pub txid: String, + pub txid: Arc, /// The transaction version, of which 0, 1, 2 are standard. pub version: i32, /// The block height or time restriction on the transaction. @@ -696,7 +696,7 @@ pub struct Tx { impl From for Tx { fn from(tx: BdkTx) -> Self { Self { - txid: tx.txid.to_string(), + txid: Arc::new(Txid(tx.txid)), version: tx.version, locktime: tx.locktime, size: tx.size as u64, diff --git a/bdk-ffi/src/wallet.rs b/bdk-ffi/src/wallet.rs index 8fed093b..e70029ac 100644 --- a/bdk-ffi/src/wallet.rs +++ b/bdk-ffi/src/wallet.rs @@ -1,4 +1,4 @@ -use crate::bitcoin::{Amount, FeeRate, OutPoint, Psbt, Script, Transaction}; +use crate::bitcoin::{Amount, FeeRate, OutPoint, Psbt, Script, Transaction, Txid}; use crate::descriptor::Descriptor; use crate::error::{ CalculateFeeError, CannotConnectError, CreateWithPersistError, DescriptorError, @@ -10,13 +10,12 @@ use crate::types::{ Policy, SentAndReceivedValues, SignOptions, SyncRequestBuilder, UnconfirmedTx, Update, }; -use bdk_wallet::bitcoin::{Network, Txid}; +use bdk_wallet::bitcoin::Network; use bdk_wallet::rusqlite::Connection as BdkConnection; use bdk_wallet::signer::SignOptions as BdkSignOptions; use bdk_wallet::{KeychainKind, PersistedWallet, Wallet as BdkWallet}; use std::borrow::BorrowMut; -use std::str::FromStr; use std::sync::{Arc, Mutex, MutexGuard}; /// A Bitcoin wallet. @@ -334,10 +333,8 @@ impl Wallet { /// confirmed or unconfirmed. If the transaction is confirmed, the anchor which proves the /// confirmation is provided. If the transaction is unconfirmed, the unix timestamp of when /// the transaction was last seen in the mempool is provided. - pub fn get_tx(&self, txid: String) -> Result, TxidParseError> { - let txid = - Txid::from_str(txid.as_str()).map_err(|_| TxidParseError::InvalidTxid { txid })?; - Ok(self.get_wallet().get_tx(txid).map(|tx| tx.into())) + pub fn get_tx(&self, txid: Arc) -> Result, TxidParseError> { + Ok(self.get_wallet().get_tx(txid.0).map(|tx| tx.into())) } /// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase transaction. diff --git a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveElectrumClientTest.kt b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveElectrumClientTest.kt index 5fdfef78..ea282f04 100644 --- a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveElectrumClientTest.kt +++ b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/LiveElectrumClientTest.kt @@ -48,7 +48,7 @@ class LiveElectrumClientTest { assertEquals( expected = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", - actual = features.genesisHash + actual = features.genesisHash.toString() ) } diff --git a/bdk-swift/Tests/BitcoinDevKitTests/LiveElectrumClientTests.swift b/bdk-swift/Tests/BitcoinDevKitTests/LiveElectrumClientTests.swift index 05c4873b..af543fce 100644 --- a/bdk-swift/Tests/BitcoinDevKitTests/LiveElectrumClientTests.swift +++ b/bdk-swift/Tests/BitcoinDevKitTests/LiveElectrumClientTests.swift @@ -54,7 +54,7 @@ final class LiveElectrumClientTests: XCTestCase { print("Server Features:\n\(features)") XCTAssertEqual( - features.genesisHash, + features.genesisHash.description, "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" ) }