diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/ErrorsTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/ErrorsTest.kt new file mode 100644 index 00000000..e50570ae --- /dev/null +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/ErrorsTest.kt @@ -0,0 +1,58 @@ +package org.bitcoindevkit + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +@RunWith(AndroidJUnit4::class) +class ErrorsTest { + @Test + fun bip39ErrorDisplaysBadWordCount() { + val thirteenWordMnemonic = "awesome awesome awesome awesome awesome awesome awesome awesome awesome awesome awesome awesome awesome" + + // Building a Mnemonic fails with BadWordCount exception + val exception = assertFailsWith { + Mnemonic.fromString(thirteenWordMnemonic) + } + + // The toString() method on the exception is the Display trait exported from Rust + assertEquals( + expected = "the word count 13 is not supported", + actual = exception.toString() + ) + + // The exception contains a field `wordCount` correctly populated + assertEquals( + expected = 13uL, + actual = exception.wordCount + ) + + // The `message` field on the exception is the concatenation of all fields on the type + assertEquals( + expected = "wordCount=13", + actual = exception.message + ) + } + + @Test + fun bip32ErrorDisplaysInvalidChildNumberFormat() { + // A derivation path cannot contain words and fails with an InvalidChildNumberFormat exception + val exception = assertFailsWith { + DerivationPath("invalid/path/string") + } + + // The toString() method on the exception is the Display trait exported from Rust + assertEquals( + expected = "invalid format for child number", + actual = exception.toString() + ) + + // The `message` field on the exception is the concatenation of all fields on the type (in this case none) + assertEquals( + expected = "", + actual = exception.message + ) + } +} diff --git a/bdk-ffi/src/error.rs b/bdk-ffi/src/error.rs index 4f718a76..42890b67 100644 --- a/bdk-ffi/src/error.rs +++ b/bdk-ffi/src/error.rs @@ -23,7 +23,6 @@ use bdk_wallet::keys::bip39::Error as BdkBip39Error; use bdk_wallet::migration::PreV1MigrationError as BdkPreV1MigrationError; use bdk_wallet::miniscript::descriptor::DescriptorKeyParseError as BdkDescriptorKeyParseError; use bdk_wallet::miniscript::psbt::Error as BdkPsbtFinalizeError; -#[allow(deprecated)] use bdk_wallet::signer::SignerError as BdkSignerError; use bdk_wallet::tx_builder::AddForeignUtxoError as BdkAddForeignUtxoError; use bdk_wallet::tx_builder::AddUtxoError; @@ -37,6 +36,7 @@ use std::convert::TryInto; // ------------------------------------------------------------------------ #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum AddForeignUtxoError { #[error("foreign utxo outpoint txid does not match PSBT input txid")] InvalidTxid, @@ -52,6 +52,7 @@ pub enum AddForeignUtxoError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum AddressParseError { #[error("base58 address encoding error")] Base58, @@ -86,6 +87,7 @@ pub enum AddressParseError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum Bip32Error { #[error("cannot derive from a hardened key")] CannotDeriveFromHardenedKey, @@ -122,6 +124,7 @@ pub enum Bip32Error { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum Bip39Error { #[error("the word count {word_count} is not supported")] BadWordCount { word_count: u64 }, @@ -140,6 +143,7 @@ pub enum Bip39Error { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum CalculateFeeError { #[error("missing transaction output: {out_points:?}")] MissingTxOut { out_points: Vec }, @@ -149,12 +153,14 @@ pub enum CalculateFeeError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum CannotConnectError { #[error("cannot include height: {height}")] Include { height: u32 }, } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum CreateTxError { #[error("descriptor error: {error_message}")] Descriptor { error_message: String }, @@ -224,6 +230,7 @@ pub enum CreateTxError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum CreateWithPersistError { #[error("sqlite persistence error: {error_message}")] Persist { error_message: String }, @@ -236,6 +243,7 @@ pub enum CreateWithPersistError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum DescriptorError { #[error("invalid hd key path")] InvalidHdKeyPath, @@ -278,6 +286,7 @@ pub enum DescriptorError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum DescriptorKeyError { #[error("error parsing descriptor key: {error_message}")] Parse { error_message: String }, @@ -293,6 +302,7 @@ pub enum DescriptorKeyError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum ElectrumError { #[error("{error_message}")] IOError { error_message: String }, @@ -347,6 +357,7 @@ pub enum ElectrumError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum EsploraError { #[error("minreq error: {error_message}")] Minreq { error_message: String }, @@ -392,6 +403,7 @@ pub enum EsploraError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum ExtractTxError { #[error("an absurdly high fee rate of {fee_rate} sat/vbyte")] AbsurdFeeRate { fee_rate: u64 }, @@ -407,13 +419,16 @@ pub enum ExtractTxError { )] OtherExtractTxErr, } + #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum FeeRateError { #[error("arithmetic overflow")] ArithmeticOverflow, } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum FromScriptError { #[error("script is not a p2pkh, p2sh or witness program")] UnrecognizedScript, @@ -436,6 +451,7 @@ pub enum RequestBuilderError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum LoadWithPersistError { #[error("sqlite persistence error: {error_message}")] Persist { error_message: String }, @@ -448,6 +464,7 @@ pub enum LoadWithPersistError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum MiniscriptError { #[error("absolute locktime error")] AbsoluteLockTime, @@ -562,6 +579,7 @@ pub enum MiniscriptError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum ParseAmountError { #[error("amount out of range")] OutOfRange, @@ -584,12 +602,14 @@ pub enum ParseAmountError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum PersistenceError { #[error("persistence error: {error_message}")] Reason { error_message: String }, } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum PreV1MigrationError { #[error("migration helper is only available for sqlite-backed persisters")] SqliteOnly, @@ -605,6 +625,7 @@ pub enum PreV1MigrationError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum PsbtError { #[error("invalid magic")] InvalidMagic, @@ -709,6 +730,7 @@ pub enum PsbtError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum PsbtParseError { #[error("error in internal psbt data structure: {error_message}")] PsbtEncoding { error_message: String }, @@ -718,12 +740,14 @@ pub enum PsbtParseError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum SighashParseError { #[error("invalid sighash type: {error_message}")] Invalid { error_message: String }, } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum PsbtFinalizeError { #[error("an input at index {index} is invalid: {reason}")] InputError { reason: String, index: u32 }, @@ -734,6 +758,7 @@ pub enum PsbtFinalizeError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum SignerError { #[error("missing key for signing")] MissingKey, @@ -788,6 +813,7 @@ pub enum SignerError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum TransactionError { #[error("io error")] Io, @@ -813,12 +839,14 @@ pub enum TransactionError { } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum TxidParseError { #[error("invalid txid: {txid}")] InvalidTxid { txid: String }, } #[derive(Debug, thiserror::Error, uniffi::Error)] +#[uniffi::export(Debug, Display)] pub enum CbfError { #[error("the node is no longer running")] NodeStopped,