From 6ac386c8df8f5a38bc9786796255af5ec5b968ab Mon Sep 17 00:00:00 2001 From: Matthew Date: Wed, 17 Apr 2024 21:09:09 -0500 Subject: [PATCH] feat: add mnemonic related error --- bdk-ffi/src/bdk.udl | 13 +++++++-- bdk-ffi/src/error.rs | 67 +++++++++++++++++++++++++++++++++++++++++++- bdk-ffi/src/keys.rs | 10 +++---- bdk-ffi/src/lib.rs | 1 + 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index 29db64c..7d2cf28 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -9,6 +9,15 @@ enum Alpha3Error { "Generic" }; +[Error] +interface Bip39Error { + BadWordCount(u64 word_count); + UnknownWord(u64 index); + BadEntropyBitCount(u64 bit_count); + InvalidChecksum(); + AmbiguousLanguages(string languages); +}; + [Error] interface CalculateFeeError { MissingTxOut(sequence out_points); @@ -316,10 +325,10 @@ interface BumpFeeTxBuilder { interface Mnemonic { constructor(WordCount word_count); - [Name=from_string, Throws=Alpha3Error] + [Name=from_string, Throws=Bip39Error] constructor(string mnemonic); - [Name=from_entropy, Throws=Alpha3Error] + [Name=from_entropy, Throws=Bip39Error] constructor(sequence entropy); string as_string(); diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index a9d8359..bad5465 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -14,7 +14,9 @@ use bdk_file_store::IterError; use bitcoin_internals::hex::display::DisplayHex; use bdk::bitcoin::address::ParseError; +use bdk::keys::bip39::Error as BdkBip39Error; use std::convert::Infallible; +use std::convert::TryInto; #[derive(Debug, thiserror::Error)] pub enum Alpha3Error { @@ -63,6 +65,24 @@ pub enum WalletCreationError { }, } +#[derive(Debug, thiserror::Error)] +pub enum Bip39Error { + #[error("the word count {word_count} is not supported")] + BadWordCount { word_count: u64 }, + + #[error("unknown word at index {index}")] + UnknownWord { index: u64 }, + + #[error("entropy bit count {bit_count} is invalid")] + BadEntropyBitCount { bit_count: u64 }, + + #[error("checksum is invalid")] + InvalidChecksum, + + #[error("ambiguous languages detected: {languages}")] + AmbiguousLanguages { languages: String }, +} + #[derive(Debug, thiserror::Error)] pub enum PersistenceError { #[error("writing to persistence error: {e}")] @@ -392,6 +412,26 @@ impl From> for WalletCreationError { } } +impl From for Bip39Error { + fn from(error: BdkBip39Error) -> Self { + match error { + BdkBip39Error::BadWordCount(word_count) => Bip39Error::BadWordCount { + word_count: word_count.try_into().expect("word count exceeds u64"), + }, + BdkBip39Error::UnknownWord(index) => Bip39Error::UnknownWord { + index: index.try_into().expect("index exceeds u64"), + }, + BdkBip39Error::BadEntropyBitCount(bit_count) => Bip39Error::BadEntropyBitCount { + bit_count: bit_count.try_into().expect("bit count exceeds u64"), + }, + BdkBip39Error::InvalidChecksum => Bip39Error::InvalidChecksum, + BdkBip39Error::AmbiguousLanguages(info) => Bip39Error::AmbiguousLanguages { + languages: format!("{:?}", info), + }, + } + } +} + impl From for PersistenceError { fn from(error: std::io::Error) -> Self { PersistenceError::Write { @@ -581,7 +621,9 @@ impl From for ExtractTxError { } #[cfg(test)] mod test { - use crate::error::{CannotConnectError, EsploraError, PersistenceError, WalletCreationError}; + use crate::error::{ + Bip39Error, CannotConnectError, EsploraError, PersistenceError, WalletCreationError, + }; use crate::CalculateFeeError; use crate::OutPoint; use crate::SignerError; @@ -806,4 +848,27 @@ mod test { assert_eq!(format!("{}", error), "cannot include height: 42"); } + + #[test] + fn test_error_bip39() { + let error = Bip39Error::BadWordCount { word_count: 15 }; + assert_eq!(format!("{}", error), "the word count 15 is not supported"); + + let error = Bip39Error::UnknownWord { index: 102 }; + assert_eq!(format!("{}", error), "unknown word at index 102"); + + let error = Bip39Error::BadEntropyBitCount { bit_count: 128 }; + assert_eq!(format!("{}", error), "entropy bit count 128 is invalid"); + + let error = Bip39Error::InvalidChecksum; + assert_eq!(format!("{}", error), "checksum is invalid"); + + let error = Bip39Error::AmbiguousLanguages { + languages: "English, Spanish".to_string(), + }; + assert_eq!( + format!("{}", error), + "ambiguous languages detected: English, Spanish" + ); + } } diff --git a/bdk-ffi/src/keys.rs b/bdk-ffi/src/keys.rs index 6886318..2ccc1a5 100644 --- a/bdk-ffi/src/keys.rs +++ b/bdk-ffi/src/keys.rs @@ -1,4 +1,4 @@ -use crate::error::Alpha3Error; +use crate::error::{Alpha3Error, Bip39Error}; use bdk::bitcoin::bip32::DerivationPath as BdkDerivationPath; use bdk::bitcoin::key::Secp256k1; @@ -35,16 +35,16 @@ impl Mnemonic { Mnemonic { inner: mnemonic } } - pub(crate) fn from_string(mnemonic: String) -> Result { + pub(crate) fn from_string(mnemonic: String) -> Result { BdkMnemonic::from_str(&mnemonic) .map(|m| Mnemonic { inner: m }) - .map_err(|_| Alpha3Error::Generic) + .map_err(Bip39Error::from) } - pub(crate) fn from_entropy(entropy: Vec) -> Result { + pub(crate) fn from_entropy(entropy: Vec) -> Result { BdkMnemonic::from_entropy(entropy.as_slice()) .map(|m| Mnemonic { inner: m }) - .map_err(|_| Alpha3Error::Generic) + .map_err(Bip39Error::from) } pub(crate) fn as_string(&self) -> String { diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index d9c6ee8..347e1b2 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -15,6 +15,7 @@ use crate::bitcoin::TxOut; use crate::descriptor::Descriptor; use crate::error::AddressError; use crate::error::Alpha3Error; +use crate::error::Bip39Error; use crate::error::CalculateFeeError; use crate::error::CannotConnectError; use crate::error::DescriptorError;