From 9f29eb0e8684da25b15f39b5552e4bbd1ff00f20 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 21 Jun 2021 17:01:53 -0700 Subject: [PATCH] Add classes to wrap LibJna native types --- src/error.rs | 159 ++------------------------------------------------ src/lib.rs | 2 + src/wallet.rs | 52 +++++++++++------ 3 files changed, 40 insertions(+), 173 deletions(-) diff --git a/src/error.rs b/src/error.rs index fba774c..3aa6d82 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,6 @@ -//use ::safer_ffi::prelude::*; use bdk::Error; -pub fn error_name(error: &bdk::Error) -> &'static str { +pub fn get_name(error: &bdk::Error) -> String { match error { Error::InvalidU32Bytes(_) => "InvalidU32Bytes", Error::Generic(_) => "Generic", @@ -39,159 +38,9 @@ pub fn error_name(error: &bdk::Error) -> &'static str { Error::Hex(_) => "Hex", Error::Psbt(_) => "Psbt", Error::Electrum(_) => "Electrum", -// Error::Esplora(_) => {} -// Error::CompactFilters(_) => {} + // Error::Esplora(_) => {} + // Error::CompactFilters(_) => {} Error::Sled(_) => "Sled", - _ => "Unknown", } + .to_string() } - -//// Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet) -//// Simplified to work over the FFI interface -//#[derive_ReprC] -//#[repr(i16)] -//#[derive(Debug)] -//pub enum WalletError { -// None, -// InvalidU32Bytes, -// Generic, -// ScriptDoesntHaveAddressForm, -// SingleRecipientMultipleOutputs, -// SingleRecipientNoInputs, -// NoRecipients, -// NoUtxosSelected, -// OutputBelowDustLimit, -// InsufficientFunds, -// BnBTotalTriesExceeded, -// BnBNoExactMatch, -// UnknownUtxo, -// TransactionNotFound, -// TransactionConfirmed, -// IrreplaceableTransaction, -// FeeRateTooLow, -// FeeTooLow, -// FeeRateUnavailable, -// MissingKeyOrigin, -// Key, -// ChecksumMismatch, -// SpendingPolicyRequired, -// InvalidPolicyPathError, -// Signer, -// InvalidNetwork, -// InvalidProgressValue, -// ProgressUpdateError, -// InvalidOutpoint, -// Descriptor, -// AddressValidator, -// Encode, -// Miniscript, -// Bip32, -// Secp256k1, -// Json, -// Hex, -// Psbt, -// PsbtParse, -// //#[cfg(feature = "electrum")] -// Electrum, -// //#[cfg(feature = "esplora")] -// //Esplora, -// //#[cfg(feature = "compact_filters")] -// //CompactFilters, -// //#[cfg(feature = "key-value-db")] -// Sled, -//} - -//impl From for WalletError { -// fn from(error: bdk::Error) -> Self { -// match error { -// Error::InvalidU32Bytes(_) => WalletError::InvalidNetwork, -// Error::Generic(_) => WalletError::Generic, -// Error::ScriptDoesntHaveAddressForm => WalletError::ScriptDoesntHaveAddressForm, -// Error::SingleRecipientMultipleOutputs => WalletError::SingleRecipientMultipleOutputs, -// Error::SingleRecipientNoInputs => WalletError::SingleRecipientNoInputs, -// Error::NoRecipients => WalletError::NoRecipients, -// Error::NoUtxosSelected => WalletError::NoUtxosSelected, -// Error::OutputBelowDustLimit(_) => WalletError::OutputBelowDustLimit, -// Error::InsufficientFunds { .. } => WalletError::InsufficientFunds, -// Error::BnBTotalTriesExceeded => WalletError::BnBTotalTriesExceeded, -// Error::BnBNoExactMatch => WalletError::BnBNoExactMatch, -// Error::UnknownUtxo => WalletError::UnknownUtxo, -// Error::TransactionNotFound => WalletError::TransactionNotFound, -// Error::TransactionConfirmed => WalletError::TransactionConfirmed, -// Error::IrreplaceableTransaction => WalletError::IrreplaceableTransaction, -// Error::FeeRateTooLow { .. } => WalletError::FeeRateTooLow, -// Error::FeeTooLow { .. } => WalletError::FeeTooLow, -// Error::MissingKeyOrigin(_) => WalletError::MissingKeyOrigin, -// Error::Key(_) => WalletError::Key, -// Error::ChecksumMismatch => WalletError::ChecksumMismatch, -// Error::SpendingPolicyRequired(_) => WalletError::SpendingPolicyRequired, -// Error::InvalidPolicyPathError(_) => WalletError::InvalidPolicyPathError, -// Error::Signer(_) => WalletError::Signer, -// Error::InvalidProgressValue(_) => WalletError::InvalidProgressValue, -// Error::ProgressUpdateError => WalletError::ProgressUpdateError, -// Error::InvalidOutpoint(_) => WalletError::InvalidOutpoint, -// Error::Descriptor(_) => WalletError::Descriptor, -// Error::AddressValidator(_) => WalletError::AddressValidator, -// Error::Encode(_) => WalletError::Encode, -// Error::Miniscript(_) => WalletError::Miniscript, -// Error::Bip32(_) => WalletError::Bip32, -// Error::Secp256k1(_) => WalletError::Secp256k1, -// Error::Json(_) => WalletError::Json, -// Error::Hex(_) => WalletError::Hex, -// Error::Psbt(_) => WalletError::Psbt, -// Error::Electrum(_) => WalletError::Electrum, -// //Error::Esplora(_) => WalletError::Esplora, -// //Error::CompactFilters(_) => {} -// Error::Sled(_) => WalletError::Sled, -// } -// } -//} - -//type error_code = i16; -// -//impl From for error_code { -// fn from(error: bdk::Error) -> Self { -// match error { -// Error::InvalidU32Bytes(_) => 1, -// Error::Generic(_) => 2, -// Error::ScriptDoesntHaveAddressForm => 3, -// Error::SingleRecipientMultipleOutputs => 4, -// Error::SingleRecipientNoInputs => 5, -// Error::NoRecipients => 6, -// Error::NoUtxosSelected => 7, -// Error::OutputBelowDustLimit(_) => 8, -// Error::InsufficientFunds { .. } => 9, -// Error::BnBTotalTriesExceeded => 10, -// Error::BnBNoExactMatch => 11, -// Error::UnknownUtxo => 12, -// Error::TransactionNotFound => 13, -// Error::TransactionConfirmed => 14, -// Error::IrreplaceableTransaction => 15, -// Error::FeeRateTooLow { .. } => 16, -// Error::FeeTooLow { .. } => 17, -// Error::MissingKeyOrigin(_) => 18, -// Error::Key(_) => 19, -// Error::ChecksumMismatch => 20, -// Error::SpendingPolicyRequired(_) => 21, -// Error::InvalidPolicyPathError(_) => 22, -// Error::Signer(_) => 23, -// Error::InvalidProgressValue(_) => 24, -// Error::ProgressUpdateError => 25, -// Error::InvalidOutpoint(_) => 26, -// Error::Descriptor(_) => 27, -// Error::AddressValidator(_) => 28, -// Error::Encode(_) => 29, -// Error::Miniscript(_) => 30, -// Error::Bip32(_) => 31, -// Error::Secp256k1(_) => 32, -// Error::Json(_) => 33, -// Error::Hex(_) => 34, -// Error::Psbt(_) => 35, -// Error::Electrum(_) => 36, -// //Error::Esplora(_) => WalletError::Esplora, -// //Error::CompactFilters(_) => {} -// Error::Sled(_) => 37, -// _ => -1 -// } -// } -//} diff --git a/src/lib.rs b/src/lib.rs index f3f6fc6..3c75153 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![deny(unsafe_code)] /* No `unsafe` needed! */ +mod error; mod wallet; /// The following test function is necessary for the header generation. @@ -7,6 +8,7 @@ mod wallet; #[test] fn generate_headers() -> ::std::io::Result<()> { ::safer_ffi::headers::builder() + .with_guard("__RUST_BDK_FFI__") .to_file("cc/bdk_ffi.h")? .generate() } diff --git a/src/wallet.rs b/src/wallet.rs index 87b1fcc..cfd72bc 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -1,3 +1,4 @@ +use crate::error::get_name; use ::safer_ffi::prelude::*; use bdk::bitcoin::network::constants::Network::Testnet; use bdk::blockchain::{ @@ -13,7 +14,7 @@ use safer_ffi::char_p::{char_p_boxed, char_p_ref}; #[derive_ReprC] #[ReprC::opaque] pub struct VoidResult { - raw: Result<(), String>, + raw: Result<(), Error>, } #[ffi_export] @@ -22,7 +23,7 @@ fn get_void_err(void_result: &VoidResult) -> Option { .raw .as_ref() .err() - .map(|s| char_p_boxed::try_from(s.clone()).unwrap()) + .map(|e| char_p_boxed::try_from(get_name(e)).unwrap()) } #[ffi_export] @@ -33,7 +34,7 @@ fn free_void_result(void_result: Option>) { #[derive_ReprC] #[ReprC::opaque] pub struct StringResult { - raw: Result, + raw: Result, } #[ffi_export] @@ -51,7 +52,7 @@ fn get_string_err(string_result: &StringResult) -> Option { .raw .as_ref() .err() - .map(|s| char_p_boxed::try_from(s.clone()).unwrap()) + .map(|e| char_p_boxed::try_from(get_name(e)).unwrap()) } #[ffi_export] @@ -59,10 +60,21 @@ fn free_string_result(string_result: Option>) { drop(string_result) } +#[derive_ReprC] +#[ReprC::opaque] +pub struct WalletRef<'lt> { + raw: &'lt Wallet, +} + +#[ffi_export] +fn free_wallet_ref(wallet_ref: Option>) { + drop(wallet_ref) +} + #[derive_ReprC] #[ReprC::opaque] pub struct WalletResult { - raw: Result, String>, + raw: Result, Error>, } #[ffi_export] @@ -74,12 +86,12 @@ fn new_wallet_result( let name = name.to_string(); let descriptor = descriptor.to_string(); let change_descriptor = change_descriptor.map(|s| s.to_string()); - let wallet_result = new_wallet(name, descriptor, change_descriptor).map_err(|e| e.to_string()); + let wallet_result = new_wallet(name, descriptor, change_descriptor); Box::new(WalletResult { raw: wallet_result }) } fn new_wallet( - name: String, + _name: String, descriptor: String, change_descriptor: Option, ) -> Result, Error> { @@ -108,24 +120,28 @@ fn get_wallet_err(wallet_result: &WalletResult) -> Option { .raw .as_ref() .err() - .map(|s| char_p_boxed::try_from(s.clone()).unwrap()) + .map(|e| char_p_boxed::try_from(get_name(&e)).unwrap()) } #[ffi_export] -fn sync_wallet(wallet_result: &WalletResult) -> Box { - let wallet_result_ref = wallet_result.raw.as_ref().map_err(|error| error.clone()); - let void_result = wallet_result_ref - .and_then(|w| w.sync(log_progress(), Some(100)).map_err(|e| e.to_string())); +fn get_wallet_ok<'lt>(wallet_result: &'lt WalletResult) -> Option>> { + wallet_result + .raw + .as_ref() + .ok() + .map(|w| Box::new(WalletRef { raw: w})) +} + +#[ffi_export] +fn sync_wallet<'lt>(wallet_ref: &'lt WalletRef<'lt>) -> Box { + let void_result = wallet_ref + .raw.sync(log_progress(), Some(100)); Box::new(VoidResult { raw: void_result }) } #[ffi_export] -fn new_address(wallet_result: &WalletResult) -> Box { - let new_address = wallet_result - .raw - .as_ref() - .map_err(|error| error.clone()) - .and_then(|w| w.get_address(New).map_err(|error| error.to_string())); +fn new_address<'lt>(wallet_ref: &'lt WalletRef<'lt>) -> Box { + let new_address = wallet_ref.raw.get_address(New); let string_result = new_address.map(|a| a.to_string()); Box::new(StringResult { raw: string_result }) }