use std::fmt::Debug;
use packable::error::UnexpectedEOF;
use serde::{
ser::{SerializeMap, Serializer},
Serialize,
};
use crate::{
client::{api::input_selection::Error as InputSelectionError, node_api::indexer::QueryParameter},
types::block::semantic::ConflictReason,
};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("{0}")]
ApiTypes(#[from] crate::types::api::core::error::Error),
#[error("{0}")]
Blake2b256(&'static str),
#[error("{0}")]
Block(#[from] crate::types::block::Error),
#[error("the wallet account has enough funds, but split on too many outputs: {0}, max. is 128, consolidate them")]
ConsolidationRequired(usize),
#[error("{0}")]
Crypto(#[from] crypto::Error),
#[error("address: {address} not found in range: {range}")]
InputAddressNotFound {
address: String,
range: String,
},
#[error("invalid amount in API response: {0}")]
InvalidAmount(String),
#[error("invalid BIP32 chain data")]
InvalidBIP32ChainData,
#[error("invalid bech32 hrp for the connected network: {provided}, expected: {expected}")]
InvalidBech32Hrp {
provided: String,
expected: String,
},
#[error("invalid mnemonic {0}")]
InvalidMnemonic(String),
#[error("the transaction essence is too large. Its length is {length}, max length is {max_length}")]
InvalidRegularTransactionEssenceLength {
length: usize,
max_length: usize,
},
#[error("the transaction payload is too large. Its length is {length}, max length is {max_length}")]
InvalidTransactionPayloadLength {
length: usize,
max_length: usize,
},
#[error("{0}")]
Json(#[from] serde_json::Error),
#[error("must provide required parameter: {0}")]
MissingParameter(&'static str),
#[error("node error: {0}")]
Node(String),
#[error("block ID `{0}` doesn't need to be promoted or reattached")]
NoNeedPromoteOrReattach(String),
#[error("the requested data {0} was not found.")]
NotFound(String),
#[error("output error: {0}")]
Output(&'static str),
#[error("placeholderSecretManager can't be used for address generation or signing")]
PlaceholderSecretManager,
#[error("rw lock failed")]
PoisonError,
#[error("{0}")]
Pow(String),
#[error("{0}")]
PrefixHex(#[from] prefix_hex::Error),
#[error("not enough nodes for quorum: {available_nodes} < {minimum_threshold}")]
QuorumPoolSizeError {
available_nodes: usize,
minimum_threshold: usize,
},
#[error("failed to reach quorum: {quorum_size} < {minimum_threshold}")]
QuorumThresholdError {
quorum_size: usize,
minimum_threshold: usize,
},
#[error("response error with status code {code}: {text}, URL: {url}")]
ResponseError {
code: u16,
text: String,
url: String,
},
#[error("{0}")]
Reqwest(#[from] reqwest::Error),
#[error("cannot unwrap a SecretManager: type mismatch!")]
SecretManagerMismatch,
#[error("no healthy node available")]
HealthyNodePoolEmpty,
#[error("error when building tagged_data block: {0}")]
TaggedData(String),
#[error("block ID `{0}` couldn't get included into the Tangle")]
TangleInclusion(String),
#[cfg(not(target_family = "wasm"))]
#[error("{0}")]
TaskJoin(#[from] tokio::task::JoinError),
#[error(
"local time {current_time} doesn't match the time of the latest milestone timestamp: {milestone_timestamp}"
)]
TimeNotSynced {
current_time: u32,
milestone_timestamp: u32,
},
#[error("the semantic validation of a transaction failed with conflict reason: {} - {0:?}", *.0 as u8)]
TransactionSemantic(ConflictReason),
#[error("unexpected API response")]
UnexpectedApiResponse,
#[error("an indexer API request contains a query parameter not supported by the endpoint: {0}.")]
UnsupportedQueryParameter(QueryParameter),
#[error("{0}")]
Unpack(#[from] packable::error::UnpackError<crate::types::block::Error, UnexpectedEOF>),
#[error("can't set {0} to URL")]
UrlAuth(&'static str),
#[error("{0}")]
Url(#[from] url::ParseError),
#[error("{0}")]
UrlValidation(String),
#[error("{0}")]
InputSelection(#[from] InputSelectionError),
#[error("missing BIP32 chain to sign with")]
MissingBip32Chain,
#[cfg(feature = "participation")]
#[cfg_attr(docsrs, doc(cfg(feature = "participation")))]
#[error("{0}")]
Participation(#[from] crate::types::api::plugins::participation::error::Error),
#[cfg(feature = "ledger_nano")]
#[cfg_attr(docsrs, doc(cfg(feature = "ledger_nano")))]
#[error("{0}")]
Ledger(#[from] crate::client::secret::ledger_nano::Error),
#[cfg(feature = "mqtt")]
#[cfg_attr(docsrs, doc(cfg(feature = "mqtt")))]
#[error("{0}")]
Mqtt(#[from] crate::client::node_api::mqtt::Error),
#[cfg(feature = "stronghold")]
#[cfg_attr(docsrs, doc(cfg(feature = "stronghold")))]
#[error("{0}")]
Stronghold(#[from] crate::client::stronghold::Error),
}
impl Serialize for Error {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_map(Some(2))?;
let mut kind_dbg = format!("{self:?}");
if let Some(r) = kind_dbg.get_mut(0..1) {
r.make_ascii_lowercase();
}
let kind = kind_dbg.split([' ', '(']).next().unwrap();
seq.serialize_entry("type", &kind)?;
seq.serialize_entry("error", &self.to_string())?;
seq.end()
}
}