Skip to content

Commit

Permalink
feat: add derivation path related error
Browse files Browse the repository at this point in the history
  • Loading branch information
reez committed Apr 19, 2024
1 parent cacb78f commit ecff2f9
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 5 deletions.
7 changes: 7 additions & 0 deletions bdk-ffi/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions bdk-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ bdk_file_store = { version = "0.8.0" }
uniffi = { version = "=0.26.1" }
bitcoin-internals = { version = "0.2.0", features = ["alloc"] }
thiserror = "1.0.58"
hex = "0.4.3"

[build-dependencies]
uniffi = { version = "=0.26.1", features = ["build"] }
Expand Down
17 changes: 16 additions & 1 deletion bdk-ffi/src/bdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ enum Alpha3Error {
"Generic"
};

[Error]
interface Bip32Error {
CannotDeriveFromHardenedKey();
Secp256k1(string message);
InvalidChildNumber(u32 child_number);
InvalidChildNumberFormat();
InvalidDerivationPathFormat();
UnknownVersion(string version);
WrongExtendedKeyLength(u32 length);
Base58(string message);
Hex(string message);
InvalidPublicKeyHexLength(u32 length);
UnknownError(string error_message);
};

[Error]
interface CalculateFeeError {
MissingTxOut(sequence<OutPoint> out_points);
Expand Down Expand Up @@ -300,7 +315,7 @@ interface Mnemonic {
};

interface DerivationPath {
[Throws=Alpha3Error]
[Throws=Bip32Error]
constructor(string path);
};

Expand Down
126 changes: 125 additions & 1 deletion bdk-ffi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use bdk_file_store::FileError as BdkFileError;
use bdk_file_store::IterError;
use bitcoin_internals::hex::display::DisplayHex;

use crate::error::bip32::Error as BdkBip32Error;
use bdk::bitcoin::bip32;

use std::convert::Infallible;

#[derive(Debug, thiserror::Error)]
Expand All @@ -20,6 +23,42 @@ pub enum Alpha3Error {
Generic,
}

#[derive(Debug, thiserror::Error)]
pub enum Bip32Error {
#[error("Cannot derive from a hardened key")]
CannotDeriveFromHardenedKey,

#[error("Secp256k1 error: {message}")]
Secp256k1 { message: String },

#[error("Invalid child number: {child_number}")]
InvalidChildNumber { child_number: u32 },

#[error("Invalid format for child number")]
InvalidChildNumberFormat,

#[error("Invalid derivation path format")]
InvalidDerivationPathFormat,

#[error("Unknown version: {version}")]
UnknownVersion { version: String },

#[error("Wrong extended key length: {length}")]
WrongExtendedKeyLength { length: u32 },

#[error("Base58 error: {message}")]
Base58 { message: String },

#[error("Hexadecimal conversion error: {message}")]
Hex { message: String },

#[error("Invalid public key hex length: {length}")]
InvalidPublicKeyHexLength { length: u32 },

#[error("Unknown error: {error_message}")]
UnknownError { error_message: String },
}

#[derive(Debug, thiserror::Error)]
pub enum CalculateFeeError {
#[error("missing transaction output: {out_points:?}")]
Expand Down Expand Up @@ -354,6 +393,40 @@ impl From<bdk::bitcoin::bip32::Error> for Alpha3Error {
}
}

impl From<BdkBip32Error> for Bip32Error {
fn from(error: BdkBip32Error) -> Self {
match error {
BdkBip32Error::CannotDeriveFromHardenedKey => Bip32Error::CannotDeriveFromHardenedKey,
BdkBip32Error::Secp256k1(err) => Bip32Error::Secp256k1 {
message: err.to_string(),
},
BdkBip32Error::InvalidChildNumber(num) => {
Bip32Error::InvalidChildNumber { child_number: num }
}
BdkBip32Error::InvalidChildNumberFormat => Bip32Error::InvalidChildNumberFormat,
BdkBip32Error::InvalidDerivationPathFormat => Bip32Error::InvalidDerivationPathFormat,
BdkBip32Error::UnknownVersion(bytes) => Bip32Error::UnknownVersion {
version: hex::encode(bytes),
},
BdkBip32Error::WrongExtendedKeyLength(len) => {
Bip32Error::WrongExtendedKeyLength { length: len as u32 }
}
BdkBip32Error::Base58(err) => Bip32Error::Base58 {
message: err.to_string(),
},
BdkBip32Error::Hex(err) => Bip32Error::Hex {
message: err.to_string(),
},
BdkBip32Error::InvalidPublicKeyHexLength(len) => {
Bip32Error::InvalidPublicKeyHexLength { length: len as u32 }
}
_ => Bip32Error::UnknownError {
error_message: format!("Unhandled error: {:?}", error),
},
}
}
}

impl From<NewError<std::io::Error>> for Alpha3Error {
fn from(_: NewError<std::io::Error>) -> Self {
Alpha3Error::Generic
Expand Down Expand Up @@ -484,7 +557,7 @@ impl From<bdk::bitcoin::consensus::encode::Error> for TransactionError {

#[cfg(test)]
mod test {
use crate::error::{EsploraError, PersistenceError, WalletCreationError};
use crate::error::{Bip32Error, EsploraError, PersistenceError, WalletCreationError};
use crate::CalculateFeeError;
use crate::OutPoint;
use bdk::bitcoin::Network;
Expand Down Expand Up @@ -648,4 +721,55 @@ mod test {
"loaded network type is not bitcoin, got Some(Testnet)"
);
}
#[test]
fn test_error_bip32() {
let error = Bip32Error::CannotDeriveFromHardenedKey;
assert_eq!(format!("{}", error), "Cannot derive from a hardened key");

let error = Bip32Error::Secp256k1 {
message: "Secp256k1 failure".to_string(),
};
assert_eq!(format!("{}", error), "Secp256k1 error: Secp256k1 failure");

let error = Bip32Error::InvalidChildNumber { child_number: 42 };
assert_eq!(format!("{}", error), "Invalid child number: 42");

let error = Bip32Error::InvalidChildNumberFormat;
assert_eq!(format!("{}", error), "Invalid format for child number");

let error = Bip32Error::InvalidDerivationPathFormat;
assert_eq!(format!("{}", error), "Invalid derivation path format");

let error = Bip32Error::UnknownVersion {
version: "deadbeef".to_string(),
};
assert_eq!(format!("{}", error), "Unknown version: deadbeef");

let error = Bip32Error::WrongExtendedKeyLength { length: 128 };
assert_eq!(format!("{}", error), "Wrong extended key length: 128");

let error = Bip32Error::Base58 {
message: "Base58 error".to_string(),
};
assert_eq!(format!("{}", error), "Base58 error: Base58 error");

let error = Bip32Error::Hex {
message: "Hex error".to_string(),
};
assert_eq!(
format!("{}", error),
"Hexadecimal conversion error: Hex error"
);

let error = Bip32Error::InvalidPublicKeyHexLength { length: 65 };
assert_eq!(format!("{}", error), "Invalid public key hex length: 65");

let error = Bip32Error::UnknownError {
error_message: "An unknown error occurred".to_string(),
};
assert_eq!(
format!("{}", error),
"Unknown error: An unknown error occurred"
);
}
}
6 changes: 3 additions & 3 deletions bdk-ffi/src/keys.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::Alpha3Error;
use crate::error::{Alpha3Error, Bip32Error};

use bdk::bitcoin::bip32::DerivationPath as BdkDerivationPath;
use bdk::bitcoin::key::Secp256k1;
Expand Down Expand Up @@ -57,12 +57,12 @@ pub(crate) struct DerivationPath {
}

impl DerivationPath {
pub(crate) fn new(path: String) -> Result<Self, Alpha3Error> {
pub(crate) fn new(path: String) -> Result<Self, Bip32Error> {
BdkDerivationPath::from_str(&path)
.map(|x| DerivationPath {
inner_mutex: Mutex::new(x),
})
.map_err(|_| Alpha3Error::Generic)
.map_err(Bip32Error::from)
}
}

Expand Down
1 change: 1 addition & 0 deletions bdk-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::bitcoin::TxOut;
use crate::descriptor::Descriptor;
use crate::error::AddressError;
use crate::error::Alpha3Error;
use crate::error::Bip32Error;
use crate::error::CalculateFeeError;
use crate::error::DescriptorError;
use crate::error::EsploraError;
Expand Down

0 comments on commit ecff2f9

Please sign in to comment.