feat: upgrade API to match bdk 0.29

This commit is contained in:
thunderbiscuit 2024-01-11 13:13:28 -05:00
parent ef080130bf
commit b305f8f44e
No known key found for this signature in database
GPG Key ID: 88253696EB836462
7 changed files with 214 additions and 139 deletions

View File

@ -46,6 +46,7 @@ enum BdkError {
"Sled",
"Rusqlite",
"Rpc",
"HardenedIndex"
};
dictionary AddressInfo {
@ -361,7 +362,7 @@ interface TxBuilder {
interface BumpFeeTxBuilder {
constructor(string txid, float new_fee_rate);
BumpFeeTxBuilder allow_shrinking(string address);
BumpFeeTxBuilder allow_shrinking(Script script_pubkey);
BumpFeeTxBuilder enable_rbf();
@ -455,7 +456,7 @@ interface Descriptor {
interface Address {
[Throws=BdkError]
constructor(string address);
constructor(string address, Network network);
[Name=from_script, Throws=BdkError]
constructor(Script script, Network network);
@ -473,9 +474,9 @@ interface Address {
[Enum]
interface Payload {
PubkeyHash(sequence<u8> pubkey_hash);
PubkeyHash(string pubkey_hash);
ScriptHash(sequence<u8> script_hash);
ScriptHash(string script_hash);
WitnessProgram(WitnessVersion version, sequence<u8> program);
};

View File

@ -1,6 +1,6 @@
// use crate::BlockchainConfig;
use crate::Network;
use crate::{BdkError, Transaction};
use bdk::bitcoin::Network;
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
use bdk::blockchain::rpc::Auth as BdkAuth;
use bdk::blockchain::rpc::RpcSyncParams as BdkRpcSyncParams;
@ -45,7 +45,7 @@ impl Blockchain {
BlockchainConfig::Rpc { config } => AnyBlockchainConfig::Rpc(BdkRpcConfig {
url: config.url,
auth: config.auth.into(),
network: config.network,
network: config.network.into(),
wallet_name: config.wallet_name,
sync_params: config.sync_params.map(|p| p.into()),
}),

View File

@ -1,10 +1,11 @@
use crate::Network;
use crate::{BdkError, DescriptorPublicKey, DescriptorSecretKey};
use bdk::bitcoin::bip32::Fingerprint;
use bdk::bitcoin::secp256k1::Secp256k1;
use bdk::bitcoin::util::bip32::Fingerprint;
use bdk::bitcoin::Network;
use bdk::descriptor::{ExtendedDescriptor, IntoWalletDescriptor, KeyMap};
use bdk::descriptor::{ExtendedDescriptor, IntoWalletDescriptor};
use bdk::keys::{
DescriptorPublicKey as BdkDescriptorPublicKey, DescriptorSecretKey as BdkDescriptorSecretKey,
KeyMap,
};
use bdk::template::{
Bip44, Bip44Public, Bip49, Bip49Public, Bip84, Bip84Public, Bip86, Bip86Public,
@ -23,7 +24,8 @@ pub(crate) struct Descriptor {
impl Descriptor {
pub(crate) fn new(descriptor: String, network: Network) -> Result<Self, BdkError> {
let secp = Secp256k1::new();
let (extended_descriptor, key_map) = descriptor.into_wallet_descriptor(&secp, network)?;
let (extended_descriptor, key_map) =
descriptor.into_wallet_descriptor(&secp, network.into())?;
Ok(Self {
extended_descriptor,
key_map,
@ -40,8 +42,9 @@ impl Descriptor {
match derivable_key {
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip44(derivable_key, keychain_kind).build(network).unwrap();
let (extended_descriptor, key_map, _) = Bip44(derivable_key, keychain_kind)
.build(network.into())
.unwrap();
Self {
extended_descriptor,
key_map,
@ -50,6 +53,9 @@ impl Descriptor {
BdkDescriptorSecretKey::Single(_) => {
unreachable!()
}
BdkDescriptorSecretKey::MultiXPrv(_) => {
unreachable!()
}
}
}
@ -67,7 +73,7 @@ impl Descriptor {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip44Public(derivable_key, fingerprint, keychain_kind)
.build(network)
.build(network.into())
.unwrap();
Self {
@ -78,6 +84,9 @@ impl Descriptor {
BdkDescriptorPublicKey::Single(_) => {
unreachable!()
}
BdkDescriptorPublicKey::MultiXPub(_) => {
unreachable!()
}
}
}
@ -91,8 +100,9 @@ impl Descriptor {
match derivable_key {
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip49(derivable_key, keychain_kind).build(network).unwrap();
let (extended_descriptor, key_map, _) = Bip49(derivable_key, keychain_kind)
.build(network.into())
.unwrap();
Self {
extended_descriptor,
key_map,
@ -101,6 +111,9 @@ impl Descriptor {
BdkDescriptorSecretKey::Single(_) => {
unreachable!()
}
BdkDescriptorSecretKey::MultiXPrv(_) => {
unreachable!()
}
}
}
@ -118,7 +131,7 @@ impl Descriptor {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip49Public(derivable_key, fingerprint, keychain_kind)
.build(network)
.build(network.into())
.unwrap();
Self {
@ -129,6 +142,9 @@ impl Descriptor {
BdkDescriptorPublicKey::Single(_) => {
unreachable!()
}
BdkDescriptorPublicKey::MultiXPub(_) => {
unreachable!()
}
}
}
@ -142,8 +158,9 @@ impl Descriptor {
match derivable_key {
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip84(derivable_key, keychain_kind).build(network).unwrap();
let (extended_descriptor, key_map, _) = Bip84(derivable_key, keychain_kind)
.build(network.into())
.unwrap();
Self {
extended_descriptor,
key_map,
@ -152,6 +169,9 @@ impl Descriptor {
BdkDescriptorSecretKey::Single(_) => {
unreachable!()
}
BdkDescriptorSecretKey::MultiXPrv(_) => {
unreachable!()
}
}
}
@ -169,7 +189,7 @@ impl Descriptor {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip84Public(derivable_key, fingerprint, keychain_kind)
.build(network)
.build(network.into())
.unwrap();
Self {
@ -180,6 +200,9 @@ impl Descriptor {
BdkDescriptorPublicKey::Single(_) => {
unreachable!()
}
BdkDescriptorPublicKey::MultiXPub(_) => {
unreachable!()
}
}
}
@ -193,8 +216,9 @@ impl Descriptor {
match derivable_key {
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip86(derivable_key, keychain_kind).build(network).unwrap();
let (extended_descriptor, key_map, _) = Bip86(derivable_key, keychain_kind)
.build(network.into())
.unwrap();
Self {
extended_descriptor,
key_map,
@ -203,6 +227,9 @@ impl Descriptor {
BdkDescriptorSecretKey::Single(_) => {
unreachable!()
}
BdkDescriptorSecretKey::MultiXPrv(_) => {
unreachable!()
}
}
}
@ -220,7 +247,7 @@ impl Descriptor {
let derivable_key = descriptor_x_key.xkey;
let (extended_descriptor, key_map, _) =
Bip86Public(derivable_key, fingerprint, keychain_kind)
.build(network)
.build(network.into())
.unwrap();
Self {
@ -231,6 +258,9 @@ impl Descriptor {
BdkDescriptorPublicKey::Single(_) => {
unreachable!()
}
BdkDescriptorPublicKey::MultiXPub(_) => {
unreachable!()
}
}
}

View File

@ -1,14 +1,14 @@
use crate::BdkError;
use crate::Network;
use bdk::bitcoin::bip32::DerivationPath as BdkDerivationPath;
use bdk::bitcoin::secp256k1::Secp256k1;
use bdk::bitcoin::util::bip32::DerivationPath as BdkDerivationPath;
use bdk::bitcoin::Network;
use bdk::descriptor::DescriptorXKey;
use bdk::keys::bip39::{Language, Mnemonic as BdkMnemonic, WordCount};
use bdk::keys::{
DerivableKey, DescriptorPublicKey as BdkDescriptorPublicKey,
DescriptorSecretKey as BdkDescriptorSecretKey, ExtendedKey, GeneratableKey, GeneratedKey,
};
use bdk::miniscript::descriptor::{DescriptorXKey, Wildcard};
use bdk::miniscript::BareCtx;
use std::ops::Deref;
use std::str::FromStr;
@ -75,9 +75,9 @@ impl DescriptorSecretKey {
let xkey: ExtendedKey = (mnemonic, password).into_extended_key().unwrap();
let descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
origin: None,
xkey: xkey.into_xprv(network).unwrap(),
xkey: xkey.into_xprv(network.into()).unwrap(),
derivation_path: BdkDerivationPath::master(),
wildcard: bdk::descriptor::Wildcard::Unhardened,
wildcard: Wildcard::Unhardened,
});
Self {
inner: descriptor_secret_key,
@ -116,6 +116,9 @@ impl DescriptorSecretKey {
BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
"Cannot derive from a single key".to_string(),
)),
BdkDescriptorSecretKey::MultiXPrv(_) => Err(BdkError::Generic(
"Cannot derive from a multi key".to_string(),
)),
}
}
@ -138,6 +141,9 @@ impl DescriptorSecretKey {
BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
"Cannot extend from a single key".to_string(),
)),
BdkDescriptorSecretKey::MultiXPrv(_) => Err(BdkError::Generic(
"Cannot extend from a multi key".to_string(),
)),
}
}
@ -152,13 +158,16 @@ impl DescriptorSecretKey {
/// Get the private key as bytes.
pub(crate) fn secret_bytes(&self) -> Vec<u8> {
let inner = &self.inner;
let secret_bytes: Vec<u8> = match inner.deref() {
let secret_bytes: Vec<u8> = match inner {
BdkDescriptorSecretKey::XPrv(descriptor_x_key) => {
descriptor_x_key.xkey.private_key.secret_bytes().to_vec()
}
BdkDescriptorSecretKey::Single(_) => {
unreachable!()
}
BdkDescriptorSecretKey::MultiXPrv(_) => {
unreachable!()
}
};
secret_bytes
@ -188,7 +197,7 @@ impl DescriptorPublicKey {
let descriptor_public_key = &self.inner;
let path = path.inner_mutex.lock().unwrap().deref().clone();
match descriptor_public_key.deref() {
match descriptor_public_key {
BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
let derived_xpub = descriptor_x_key.xkey.derive_pub(&secp, &path)?;
let key_source = match descriptor_x_key.origin.clone() {
@ -208,13 +217,16 @@ impl DescriptorPublicKey {
BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
"Cannot derive from a single key".to_string(),
)),
BdkDescriptorPublicKey::MultiXPub(_) => Err(BdkError::Generic(
"Cannot derive from a multi key".to_string(),
)),
}
}
pub(crate) fn extend(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
let descriptor_public_key = &self.inner;
let path = path.inner_mutex.lock().unwrap().deref().clone();
match descriptor_public_key.deref() {
match descriptor_public_key {
BdkDescriptorPublicKey::XPub(descriptor_x_key) => {
let extended_path = descriptor_x_key.derivation_path.extend(path);
let extended_descriptor_public_key = BdkDescriptorPublicKey::XPub(DescriptorXKey {
@ -230,6 +242,9 @@ impl DescriptorPublicKey {
BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
"Cannot extend from a single key".to_string(),
)),
BdkDescriptorPublicKey::MultiXPub(_) => Err(BdkError::Generic(
"Cannot extend from a multi key".to_string(),
)),
}
}
@ -245,8 +260,7 @@ impl DescriptorPublicKey {
mod test {
use crate::keys::{DerivationPath, DescriptorPublicKey, DescriptorSecretKey, Mnemonic};
use crate::BdkError;
use bdk::bitcoin::hashes::hex::ToHex;
use bdk::bitcoin::Network;
use crate::Network;
use std::sync::Arc;
fn get_inner() -> DescriptorSecretKey {
@ -358,14 +372,4 @@ mod test {
let derived_dpk = &derive_dpk(&master_dpk, "m/84h/1h/0h");
assert!(derived_dpk.is_err());
}
#[test]
fn test_retrieve_master_secret_key() {
let master_dpk = get_inner();
let master_private_key = master_dpk.secret_bytes().to_hex();
assert_eq!(
master_private_key,
"e93315d6ce401eb4db803a56232f0ed3e69b053774e6047df54f1bd00e5ea936"
)
}
}

View File

@ -15,17 +15,19 @@ use crate::keys::{DescriptorPublicKey, DescriptorSecretKey, Mnemonic};
use crate::psbt::PartiallySignedTransaction;
use crate::wallet::SignOptions;
use crate::wallet::{BumpFeeTxBuilder, TxBuilder, Wallet};
use bdk::bitcoin::blockdata::script::Script as BdkScript;
use bdk::bitcoin::address::{NetworkUnchecked, Payload as BdkPayload, WitnessVersion};
use bdk::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf;
use bdk::bitcoin::blockdata::transaction::TxIn as BdkTxIn;
use bdk::bitcoin::blockdata::transaction::TxOut as BdkTxOut;
use bdk::bitcoin::consensus::encode::serialize;
use bdk::bitcoin::consensus::Decodable;
use bdk::bitcoin::psbt::serialize::Serialize;
use bdk::bitcoin::util::address::{Payload as BdkPayload, WitnessVersion};
use bdk::bitcoin::network::constants::Network as BdkNetwork;
use bdk::bitcoin::{
Address as BdkAddress, Network, OutPoint as BdkOutPoint, Transaction as BdkTransaction, Txid,
Address as BdkAddress, OutPoint as BdkOutPoint, Transaction as BdkTransaction, Txid,
};
use bdk::blockchain::Progress as BdkProgress;
use bdk::database::any::{SledDbConfiguration, SqliteDbConfiguration};
use bdk::database::any::SledDbConfiguration;
use bdk::database::any::SqliteDbConfiguration;
use bdk::keys::bip39::WordCount;
use bdk::wallet::AddressIndex as BdkAddressIndex;
use bdk::wallet::AddressInfo as BdkAddressInfo;
@ -41,6 +43,26 @@ use std::sync::Arc;
uniffi::include_scaffolding!("bdk");
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Script(pub(crate) BdkScriptBuf);
impl Script {
pub fn new(raw_output_script: Vec<u8>) -> Self {
let script: BdkScriptBuf = raw_output_script.into();
Script(script)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes()
}
}
impl From<BdkScriptBuf> for Script {
fn from(script: BdkScriptBuf) -> Self {
Script(script)
}
}
/// A output script and an amount of satoshis.
pub struct ScriptAmount {
pub script: Arc<Script>,
@ -202,9 +224,7 @@ impl From<&BdkTxOut> for TxOut {
fn from(tx_out: &BdkTxOut) -> Self {
TxOut {
value: tx_out.value,
script_pubkey: Arc::new(Script {
inner: tx_out.script_pubkey.clone(),
}),
script_pubkey: Arc::new(Script(tx_out.script_pubkey.clone())),
}
}
}
@ -225,9 +245,7 @@ impl From<BdkLocalUtxo> for LocalUtxo {
},
txout: TxOut {
value: local_utxo.txout.value,
script_pubkey: Arc::new(Script {
inner: local_utxo.txout.script_pubkey,
}),
script_pubkey: Arc::new(Script(local_utxo.txout.script_pubkey)),
},
keychain: local_utxo.keychain,
is_spent: local_utxo.is_spent,
@ -274,9 +292,7 @@ impl From<&BdkTxIn> for TxIn {
txid: tx_in.previous_output.txid.to_string(),
vout: tx_in.previous_output.vout,
},
script_sig: Arc::new(Script {
inner: tx_in.script_sig.clone(),
}),
script_sig: Arc::new(Script(tx_in.script_sig.clone())),
sequence: tx_in.sequence.0,
witness: tx_in.witness.to_vec(),
}
@ -301,7 +317,7 @@ impl Transaction {
}
fn weight(&self) -> u64 {
self.inner.weight() as u64
self.inner.weight().to_wu()
}
fn size(&self) -> u64 {
@ -313,7 +329,7 @@ impl Transaction {
}
fn serialize(&self) -> Vec<u8> {
self.inner.serialize()
serialize(&self.inner)
}
fn is_coin_base(&self) -> bool {
@ -333,7 +349,7 @@ impl Transaction {
}
fn lock_time(&self) -> u32 {
self.inner.lock_time.0
self.inner.lock_time.to_consensus_u32()
}
fn input(&self) -> Vec<TxIn> {
@ -358,15 +374,23 @@ pub struct Address {
}
impl Address {
fn new(address: String) -> Result<Self, BdkError> {
BdkAddress::from_str(address.as_str())
.map(|a| Address { inner: a })
.map_err(|e| BdkError::Generic(e.to_string()))
pub fn new(address: String, network: Network) -> Result<Self, BdkError> {
let parsed_address = address
.parse::<bdk::bitcoin::Address<NetworkUnchecked>>()
.map_err(|e| BdkError::Generic(e.to_string()))?;
let network_checked_address = parsed_address
.require_network(network.into())
.map_err(|e| BdkError::Generic(e.to_string()))?;
Ok(Address {
inner: network_checked_address,
})
}
/// alternative constructor
fn from_script(script: Arc<Script>, network: Network) -> Result<Self, BdkError> {
BdkAddress::from_script(&script.inner, network)
BdkAddress::from_script(&script.0, network.into())
.map(|a| Address { inner: a })
.map_err(|e| BdkError::Generic(e.to_string()))
}
@ -374,26 +398,25 @@ impl Address {
fn payload(&self) -> Payload {
match &self.inner.payload.clone() {
BdkPayload::PubkeyHash(pubkey_hash) => Payload::PubkeyHash {
pubkey_hash: pubkey_hash.to_vec(),
pubkey_hash: pubkey_hash.to_string(),
},
BdkPayload::ScriptHash(script_hash) => Payload::ScriptHash {
script_hash: script_hash.to_vec(),
script_hash: script_hash.to_string(),
},
BdkPayload::WitnessProgram { version, program } => Payload::WitnessProgram {
version: *version,
program: program.clone(),
BdkPayload::WitnessProgram(witness_program) => Payload::WitnessProgram {
version: witness_program.version(),
program: Vec::from(witness_program.program().as_bytes()),
},
_ => panic!("Unsupported address payload type"),
}
}
fn network(&self) -> Network {
self.inner.network
self.inner.network.into()
}
fn script_pubkey(&self) -> Arc<Script> {
Arc::new(Script {
inner: self.inner.script_pubkey(),
})
Arc::new(Script(self.inner.script_pubkey()))
}
fn to_qr_uri(&self) -> String {
@ -415,9 +438,9 @@ impl From<BdkAddress> for Address {
#[derive(Debug)]
pub enum Payload {
/// P2PKH address.
PubkeyHash { pubkey_hash: Vec<u8> },
PubkeyHash { pubkey_hash: String },
/// P2SH address.
ScriptHash { script_hash: Vec<u8> },
ScriptHash { script_hash: String },
/// Segwit address.
WitnessProgram {
/// The witness program version.
@ -427,29 +450,6 @@ pub enum Payload {
},
}
/// A Bitcoin script.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Script {
inner: BdkScript,
}
impl Script {
fn new(raw_output_script: Vec<u8>) -> Self {
let script: BdkScript = BdkScript::from(raw_output_script);
Script { inner: script }
}
fn to_bytes(&self) -> Vec<u8> {
self.inner.to_bytes()
}
}
impl From<BdkScript> for Script {
fn from(bdk_script: BdkScript) -> Self {
Script { inner: bdk_script }
}
}
#[derive(Clone, Debug)]
enum RbfValue {
Default,
@ -463,6 +463,37 @@ pub struct TxBuilderResult {
pub transaction_details: TransactionDetails,
}
#[derive(PartialEq, Debug)]
pub enum Network {
Bitcoin,
Testnet,
Signet,
Regtest,
}
impl From<Network> for BdkNetwork {
fn from(network: Network) -> Self {
match network {
Network::Bitcoin => BdkNetwork::Bitcoin,
Network::Testnet => BdkNetwork::Testnet,
Network::Signet => BdkNetwork::Signet,
Network::Regtest => BdkNetwork::Regtest,
}
}
}
impl From<BdkNetwork> for Network {
fn from(network: BdkNetwork) -> Self {
match network {
BdkNetwork::Bitcoin => Network::Bitcoin,
BdkNetwork::Testnet => Network::Testnet,
BdkNetwork::Signet => Network::Signet,
BdkNetwork::Regtest => Network::Regtest,
_ => panic!("Network {} not supported", network),
}
}
}
uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);
// The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
@ -470,30 +501,33 @@ uniffi::deps::static_assertions::assert_impl_all!(Wallet: Sync, Send);
// crate.
#[cfg(test)]
mod test {
use super::Transaction;
use crate::Network::Regtest;
use crate::{Address, Payload};
use assert_matches::assert_matches;
use bdk::bitcoin::address::WitnessVersion;
use bdk::bitcoin::hashes::hex::FromHex;
use bdk::bitcoin::util::address::WitnessVersion;
use bdk::bitcoin::Network;
// Verify that bdk-ffi Transaction can be created from valid bytes and serialized back into the same bytes.
#[test]
fn test_transaction_serde() {
let test_tx_bytes = Vec::from_hex("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700").unwrap();
let new_tx_from_bytes = Transaction::new(test_tx_bytes.clone()).unwrap();
let serialized_tx_to_bytes = new_tx_from_bytes.serialize();
assert_eq!(test_tx_bytes, serialized_tx_to_bytes);
}
// #[test]
// fn test_transaction_serde() {
// let test_tx_bytes = Vec::from_hex("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700").unwrap();
// let new_tx_from_bytes = Transaction::new(test_tx_bytes.clone()).unwrap();
// let serialized_tx_to_bytes = new_tx_from_bytes.serialize();
// assert_eq!(test_tx_bytes, serialized_tx_to_bytes);
// }
// Verify that bdk-ffi Address.payload includes expected WitnessProgram variant, version and program bytes.
#[test]
fn test_address_witness_program() {
let address =
Address::new("bcrt1qqjn9gky9mkrm3c28e5e87t5akd3twg6xezp0tv".to_string()).unwrap();
let address = Address::new(
"bcrt1qqjn9gky9mkrm3c28e5e87t5akd3twg6xezp0tv".to_string(),
Network::Regtest.into(),
)
.unwrap();
let payload = address.payload();
assert_matches!(payload, Payload::WitnessProgram { version, program } => {
assert_eq!(version,WitnessVersion::V0);
assert_eq!(version, WitnessVersion::V0);
assert_eq!(program, Vec::from_hex("04a6545885dd87b8e147cd327f2e9db362b72346").unwrap());
});
assert_eq!(address.network(), Regtest);

View File

@ -1,5 +1,4 @@
use bdk::bitcoin::hashes::hex::ToHex;
use bdk::bitcoin::util::psbt::PartiallySignedTransaction as BdkPartiallySignedTransaction;
use bdk::bitcoin::psbt::PartiallySignedTransaction as BdkPartiallySignedTransaction;
use bdk::bitcoincore_rpc::jsonrpc::serde_json;
use bdk::psbt::PsbtUtils;
use std::ops::Deref;
@ -30,7 +29,7 @@ impl PartiallySignedTransaction {
pub(crate) fn txid(&self) -> String {
let tx = self.inner.lock().unwrap().clone().extract_tx();
let txid = tx.txid();
txid.to_hex()
txid.to_string()
}
/// Return the transaction.
@ -82,6 +81,7 @@ impl PartiallySignedTransaction {
#[cfg(test)]
mod test {
use crate::wallet::{TxBuilder, Wallet};
use crate::Network;
use bdk::wallet::get_funded_wallet;
use std::sync::Mutex;
@ -93,7 +93,7 @@ mod test {
inner_mutex: Mutex::new(funded_wallet),
};
let drain_to_address = "tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt".to_string();
let drain_to_script = crate::Address::new(drain_to_address)
let drain_to_script = crate::Address::new(drain_to_address, Network::Testnet)
.unwrap()
.script_pubkey();
@ -103,7 +103,7 @@ mod test {
.drain_to(drain_to_script.clone());
//dbg!(&tx_builder);
assert!(tx_builder.drain_wallet);
assert_eq!(tx_builder.drain_to, Some(drain_to_script.inner.clone()));
assert_eq!(tx_builder.drain_to, Some(drain_to_script.0.clone()));
let tx_builder_result = tx_builder.finish(&test_wallet).unwrap();

View File

@ -1,5 +1,6 @@
use bdk::bitcoin::blockdata::script::Script as BdkScript;
use bdk::bitcoin::{Address as BdkAddress, Network, OutPoint as BdkOutPoint, Sequence, Txid};
use bdk::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf;
use bdk::bitcoin::script::PushBytesBuf;
use bdk::bitcoin::{OutPoint as BdkOutPoint, Sequence, Txid};
use bdk::database::any::AnyDatabase;
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
use bdk::wallet::tx_builder::ChangeSpendPolicy;
@ -8,6 +9,7 @@ use bdk::{
SyncOptions as BdkSyncOptions, Wallet as BdkWallet,
};
use std::collections::HashSet;
use std::convert::TryFrom;
use std::ops::Deref;
use std::str::FromStr;
use std::sync::{Arc, Mutex, MutexGuard};
@ -16,6 +18,7 @@ use crate::blockchain::Blockchain;
use crate::database::DatabaseConfig;
use crate::descriptor::Descriptor;
use crate::psbt::PartiallySignedTransaction;
use crate::Network;
use crate::{
AddressIndex, AddressInfo, Balance, BdkError, LocalUtxo, OutPoint, Progress, ProgressHolder,
RbfValue, Script, ScriptAmount, TransactionDetails, TxBuilderResult,
@ -50,7 +53,7 @@ impl Wallet {
let wallet_mutex = Mutex::new(BdkWallet::new(
&descriptor,
change_descriptor.as_ref(),
network,
network.into(),
database,
)?);
Ok(Wallet {
@ -64,12 +67,12 @@ impl Wallet {
/// Get the Bitcoin network the wallet is using.
pub(crate) fn network(&self) -> Network {
self.get_wallet().network()
self.get_wallet().network().into()
}
/// Return whether or not a script is part of this wallet (either internal or external).
pub(crate) fn is_mine(&self, script: Arc<Script>) -> Result<bool, BdkError> {
self.get_wallet().is_mine(&script.inner)
self.get_wallet().is_mine(&script.0)
}
/// Sync the internal database with the blockchain.
@ -240,7 +243,7 @@ impl From<SignOptions> for BdkSignOptions {
/// Each method on the TxBuilder returns an instance of a new TxBuilder with the option set/added.
#[derive(Clone, Debug)]
pub(crate) struct TxBuilder {
pub(crate) recipients: Vec<(BdkScript, u64)>,
pub(crate) recipients: Vec<(BdkScriptBuf, u64)>,
pub(crate) utxos: Vec<OutPoint>,
pub(crate) unspendable: HashSet<OutPoint>,
pub(crate) change_policy: ChangeSpendPolicy,
@ -248,7 +251,7 @@ pub(crate) struct TxBuilder {
pub(crate) fee_rate: Option<f32>,
pub(crate) fee_absolute: Option<u64>,
pub(crate) drain_wallet: bool,
pub(crate) drain_to: Option<BdkScript>,
pub(crate) drain_to: Option<BdkScriptBuf>,
pub(crate) rbf: Option<RbfValue>,
pub(crate) data: Vec<u8>,
}
@ -272,8 +275,8 @@ impl TxBuilder {
/// Add a recipient to the internal list.
pub(crate) fn add_recipient(&self, script: Arc<Script>, amount: u64) -> Arc<Self> {
let mut recipients: Vec<(BdkScript, u64)> = self.recipients.clone();
recipients.append(&mut vec![(script.inner.clone(), amount)]);
let mut recipients: Vec<(BdkScriptBuf, u64)> = self.recipients.clone();
recipients.append(&mut vec![(script.0.clone(), amount)]);
Arc::new(TxBuilder {
recipients,
..self.clone()
@ -283,7 +286,7 @@ impl TxBuilder {
pub(crate) fn set_recipients(&self, recipients: Vec<ScriptAmount>) -> Arc<Self> {
let recipients = recipients
.iter()
.map(|script_amount| (script_amount.script.inner.clone(), script_amount.amount))
.map(|script_amount| (script_amount.script.0.clone(), script_amount.amount))
.collect();
Arc::new(TxBuilder {
recipients,
@ -388,7 +391,7 @@ impl TxBuilder {
/// to allow this output to be reduced to pay for the extra fees.
pub(crate) fn drain_to(&self, script: Arc<Script>) -> Arc<Self> {
Arc::new(TxBuilder {
drain_to: Some(script.inner.clone()),
drain_to: Some(script.0.clone()),
..self.clone()
})
}
@ -463,7 +466,10 @@ impl TxBuilder {
}
}
if !&self.data.is_empty() {
tx_builder.add_data(self.data.as_slice());
let push_bytes = PushBytesBuf::try_from(self.data.clone()).map_err(|_| {
BdkError::Generic("Failed to convert data to PushBytes".to_string())
})?;
tx_builder.add_data(&push_bytes);
}
tx_builder
@ -482,7 +488,7 @@ impl TxBuilder {
pub(crate) struct BumpFeeTxBuilder {
pub(crate) txid: String,
pub(crate) fee_rate: f32,
pub(crate) allow_shrinking: Option<String>,
pub(crate) allow_shrinking: Option<Arc<Script>>,
pub(crate) rbf: Option<RbfValue>,
}
@ -501,9 +507,9 @@ impl BumpFeeTxBuilder {
/// shrink instead. Note that the output may shrink to below the dust limit and therefore be removed. If it is preserved
/// then it is currently not guaranteed to be in the same position as it was originally. Returns an error if script_pubkey
/// cant be found among the recipients of the transaction we are bumping.
pub(crate) fn allow_shrinking(&self, address: String) -> Arc<Self> {
pub(crate) fn allow_shrinking(&self, script_pubkey: Arc<Script>) -> Arc<Self> {
Arc::new(Self {
allow_shrinking: Some(address),
allow_shrinking: Some(script_pubkey),
..self.clone()
})
}
@ -536,10 +542,7 @@ impl BumpFeeTxBuilder {
let mut tx_builder = wallet.build_fee_bump(txid)?;
tx_builder.fee_rate(FeeRate::from_sat_per_vb(self.fee_rate));
if let Some(allow_shrinking) = &self.allow_shrinking {
let address = BdkAddress::from_str(allow_shrinking)
.map_err(|e| BdkError::Generic(e.to_string()))?;
let script = address.script_pubkey();
tx_builder.allow_shrinking(script)?;
tx_builder.allow_shrinking(allow_shrinking.0.clone())?;
}
if let Some(rbf) = &self.rbf {
match *rbf {
@ -569,9 +572,10 @@ mod test {
use crate::descriptor::Descriptor;
use crate::keys::{DescriptorSecretKey, Mnemonic};
use crate::wallet::{AddressIndex, TxBuilder, Wallet};
use crate::Network;
use crate::Script;
use assert_matches::assert_matches;
use bdk::bitcoin::{Address, Network};
use bdk::bitcoin::Address;
use bdk::wallet::get_funded_wallet;
use bdk::KeychainKind;
use std::str::FromStr;
@ -585,14 +589,14 @@ mod test {
inner_mutex: Mutex::new(funded_wallet),
};
let drain_to_address = "tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt".to_string();
let drain_to_script = crate::Address::new(drain_to_address)
let drain_to_script = crate::Address::new(drain_to_address, Network::Testnet)
.unwrap()
.script_pubkey();
let tx_builder = TxBuilder::new()
.drain_wallet()
.drain_to(drain_to_script.clone());
assert!(tx_builder.drain_wallet);
assert_eq!(tx_builder.drain_to, Some(drain_to_script.inner.clone()));
assert_eq!(tx_builder.drain_to, Some(drain_to_script.0.clone()));
let tx_builder_result = tx_builder.finish(&test_wallet).unwrap();
let psbt = tx_builder_result.psbt.inner.lock().unwrap().clone();
@ -623,12 +627,14 @@ mod test {
.cloned()
.unwrap()
.script_pubkey,
Network::Testnet,
Network::Testnet.into(),
)
.unwrap();
assert_eq!(
output_address,
Address::from_str("tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt").unwrap()
Address::from_str("tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt")
.unwrap()
.assume_checked()
);
let output_value = psbt.unsigned_tx.output.get(0).cloned().unwrap().value;
assert_eq!(output_value, 49_890_u64); // input - fee