Compare commits

...

10 Commits

Author SHA1 Message Date
Steve Myers
89d58db02a Bump version to 0.3.1 2022-03-02 14:46:06 -08:00
Steve Myers
cda682b634 Remove hard coded sync progress value 2022-03-02 14:45:26 -08:00
Steve Myers
d17ea4b90c Bump version to 0.3.0 2022-02-27 21:18:05 -08:00
Steve Myers
76fa9b9521 Add CHANGELOG.md 2022-02-27 21:17:37 -08:00
Steve Myers
cafa8dacab Merge bitcoindevkit/bdk-ffi#104: Add PSBT deserialize and serialize functions, remove details
c039281ffc Add PSBT deserialize and serialize functions, remove details (Steve Myers)
1f0b053872 Fix bin/generate with no features (Steve Myers)

Pull request description:

  1. Fix bin/generate with no features
  2. Add `PartiallySignedBitcoinTransaction::deserialize` function as named constructor to decode from a string per [BIP 0174]
  3. Add `PartiallySignedBitcoinTransaction::serialize` function to encode to a string per [BIP 0174]
  4. Remove `PartiallySignedBitcoinTransaction.details` struct field

  [BIP 0174]:https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#encoding

  Fixes #103

Top commit has no ACKs.

Tree-SHA512: 0ba34d96625d71434d41573089a150d09fcfb6439648a7eed6e36dcdddd2682c969525b7c6efda898b2f979a7ca6ce51dc2158acf65da7f1f4c554d98b60f4ff
2022-02-25 14:47:47 -08:00
Steve Myers
c039281ffc Add PSBT deserialize and serialize functions, remove details 2022-02-24 20:49:59 -08:00
Steve Myers
1f0b053872 Fix bin/generate with no features 2022-02-24 17:17:05 -08:00
Alekos Filini
97f1011748 Add a binary to generate bindings 2022-02-08 22:15:10 +01:00
Alekos Filini
edfcde1cc6 Generate bindings for Python in build.rs 2022-02-08 21:04:12 +01:00
Sudarsan Balaji
15c0dac622 Rename field to wallet_mutex 2022-01-30 21:22:40 +00:00
5 changed files with 126 additions and 18 deletions

23
CHANGELOG.md Normal file
View File

@@ -0,0 +1,23 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [v0.3.0]
- Move bdk-kotlin bindings and ios example to separate repos
- Add bin to generate Python bindings
- Add `PartiallySignedBitcoinTransaction::deserialize` function as named constructor to decode from a string per [BIP 0174]
- Add `PartiallySignedBitcoinTransaction::serialize` function to encode to a string per [BIP 0174]
- Remove `PartiallySignedBitcoinTransaction.details` struct field
[BIP 0174]:https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#encoding
## [v0.2.0]
[v0.2.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.0.0...v0.2.0
[v0.3.0]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.2.0...v0.3.0
[unreleased]: https://github.com/bitcoindevkit/bdk-ffi/compare/v0.3.0...HEAD

View File

@@ -1,6 +1,6 @@
[package]
name = "bdk-ffi"
version = "0.2.0"
version = "0.3.1"
authors = ["Steve Myers <steve@notmandatory.org>", "Sudarsan Balaji <sudarsan.balaji@artfuldev.com>"]
edition = "2018"
@@ -11,10 +11,18 @@ name = "bdkffi"
[dependencies]
bdk = { version = "0.14", features = ["all-keys", "use-esplora-ureq"] }
uniffi_macros = "0.16.0"
uniffi = "0.16.0"
uniffi_macros = { version = "0.16.0", features = ["builtin-bindgen"] }
uniffi = { version = "0.16.0", features = ["builtin-bindgen"] }
thiserror = "1.0"
anyhow = "=1.0.45" # remove after upgrading to next version of uniffi
uniffi_bindgen = { version = "0.16.0", optional = true }
[build-dependencies]
uniffi_build = "0.16.0"
uniffi_build = { version = "0.16.0", features = ["builtin-bindgen"] }
[features]
generate-python = ["uniffi_bindgen"]
[[bin]]
name = "generate"

View File

@@ -131,6 +131,9 @@ interface Wallet {
interface PartiallySignedBitcoinTransaction {
[Throws=BdkError]
constructor([ByRef] Wallet wallet, string recipient, u64 amount, float? fee_rate);
[Name=deserialize,Throws=BdkError]
constructor(string psbt_base64);
string serialize();
};
dictionary ExtendedKeyInfo {

67
src/bin/generate.rs Normal file
View File

@@ -0,0 +1,67 @@
pub const BDK_UDL: &str = "src/bdk.udl";
#[cfg(feature = "generate-python")]
fn fixup_python_lib_path<O: AsRef<std::path::Path>>(
out_dir: O,
lib_name: &str,
) -> Result<(), Box<dyn std::error::Error>> {
use std::fs;
use std::io::Write;
const LOAD_INDIRECT_DEF: &str = "def loadIndirect():";
let bindings_file = out_dir.as_ref().join("bdk.py");
let mut data = fs::read_to_string(&bindings_file)?;
let pos = data.find(LOAD_INDIRECT_DEF).expect(&format!(
"loadIndirect not found in `{}`",
bindings_file.display()
));
let range = pos..pos + LOAD_INDIRECT_DEF.len();
let replacement = format!(
r#"
def loadIndirect():
import glob
return getattr(ctypes.cdll, glob.glob(os.path.join(os.path.dirname(os.path.abspath(__file__)), '{}.*'))[0])
def _loadIndirectOld():"#,
lib_name
);
data.replace_range(range, &replacement);
let mut file = fs::OpenOptions::new()
.write(true)
.truncate(true)
.open(&bindings_file)?;
file.write(data.as_bytes())?;
Ok(())
}
#[cfg(feature = "generate-python")]
fn generate_python() -> Result<(), Box<dyn std::error::Error>> {
use std::env;
let out_path = env::var("GENERATE_PYTHON_BINDINGS_OUT")
.map_err(|_| String::from("`GENERATE_PYTHON_BINDINGS_OUT` env variable missing"))?;
uniffi_bindgen::generate_bindings(
&format!("{}/{}", env!("CARGO_MANIFEST_DIR"), BDK_UDL),
None,
vec!["python"],
Some(&out_path),
false,
)?;
if let Some(name) = env::var("GENERATE_PYTHON_BINDINGS_FIXUP_LIB_PATH").ok() {
fixup_python_lib_path(&out_path, &name)?;
}
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
#[cfg(feature = "generate-python")]
generate_python()?;
Ok(())
}

View File

@@ -12,7 +12,7 @@ use bdk::keys::bip39::{Language, Mnemonic, WordCount};
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
use bdk::miniscript::BareCtx;
use bdk::wallet::AddressIndex;
use bdk::{BlockTime, Error, FeeRate, SignOptions, Wallet as BdkWallet };
use bdk::{BlockTime, Error, FeeRate, SignOptions, Wallet as BdkWallet};
use std::convert::TryFrom;
use std::str::FromStr;
use std::sync::{Mutex, MutexGuard};
@@ -135,7 +135,7 @@ trait WalletOperations<B>: WalletHolder<B> {
}
struct Wallet {
_wallet: Mutex<BdkWallet<AnyBlockchain, AnyDatabase>>,
wallet_mutex: Mutex<BdkWallet<AnyBlockchain, AnyDatabase>>,
}
pub trait BdkProgress: Send + Sync {
@@ -155,7 +155,6 @@ impl Progress for BdkProgressHolder {
struct PartiallySignedBitcoinTransaction {
internal: Mutex<PartiallySignedTransaction>,
details: bdk::TransactionDetails,
}
impl PartiallySignedBitcoinTransaction {
@@ -168,7 +167,7 @@ impl PartiallySignedBitcoinTransaction {
let wallet = wallet.get_wallet();
match Address::from_str(&recipient) {
Ok(address) => {
let (psbt, details) = {
let (psbt, _details) = {
let mut builder = wallet.build_tx();
builder.add_recipient(address.script_pubkey(), amount);
if let Some(sat_per_vb) = fee_rate {
@@ -178,7 +177,6 @@ impl PartiallySignedBitcoinTransaction {
};
Ok(PartiallySignedBitcoinTransaction {
internal: Mutex::new(psbt),
details,
})
}
Err(..) => Err(BdkError::Generic(
@@ -186,11 +184,23 @@ impl PartiallySignedBitcoinTransaction {
)),
}
}
pub fn deserialize(psbt_base64: String) -> Result<Self, Error> {
let psbt: PartiallySignedTransaction = PartiallySignedTransaction::from_str(&psbt_base64)?;
Ok(PartiallySignedBitcoinTransaction {
internal: Mutex::new(psbt),
})
}
pub fn serialize(&self) -> String {
let psbt = self.internal.lock().unwrap().clone();
psbt.to_string()
}
}
impl WalletHolder<AnyBlockchain> for Wallet {
fn get_wallet(&self) -> MutexGuard<BdkWallet<AnyBlockchain, AnyDatabase>> {
self._wallet.lock().unwrap()
self.wallet_mutex.lock().unwrap()
}
}
@@ -230,14 +240,14 @@ impl Wallet {
};
let database = AnyDatabase::from_config(&any_database_config)?;
let blockchain = AnyBlockchain::from_config(&any_blockchain_config)?;
let _wallet = Mutex::new(BdkWallet::new(
let wallet_mutex = Mutex::new(BdkWallet::new(
&descriptor,
change_descriptor.to_owned().as_ref(),
network,
database,
blockchain,
)?);
Ok(Wallet { _wallet })
Ok(Wallet { wallet_mutex })
}
fn get_network(&self) -> Network {
@@ -249,18 +259,15 @@ impl Wallet {
progress_update: Box<dyn BdkProgress>,
max_address_param: Option<u32>,
) -> Result<(), BdkError> {
progress_update.update(21.0, Some("message".to_string()));
self.get_wallet()
.sync(BdkProgressHolder { progress_update }, max_address_param)
}
fn broadcast(
&self,
psbt: &PartiallySignedBitcoinTransaction,
) -> Result<Transaction, Error> {
fn broadcast(&self, psbt: &PartiallySignedBitcoinTransaction) -> Result<Transaction, Error> {
let tx = psbt.internal.lock().unwrap().clone().extract_tx();
self.get_wallet().broadcast(&tx)?;
Ok(Transaction::from(&psbt.details))
let tx_details = self.get_wallet().get_tx(&tx.txid(), true)?;
Ok(Transaction::from(&tx_details.unwrap()))
}
}