/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2024 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ // Hello developer. Please add your error to the according subsection // that is commented, or make a new subsection. Keep it clean. /// Main result type used throughout the codebase. pub type Result = std::result::Result; /// Result type used in the Client module pub type ClientResult = std::result::Result; /// General library errors used throughout the codebase. #[derive(Debug, Clone, thiserror::Error)] pub enum Error { // ============== // Parsing errors // ============== #[error("Parse failed: {0}")] ParseFailed(&'static str), #[error(transparent)] ParseIntError(#[from] std::num::ParseIntError), #[error(transparent)] ParseFloatError(#[from] std::num::ParseFloatError), #[cfg(feature = "url")] #[error(transparent)] UrlParseError(#[from] url::ParseError), #[error("URL parse error: {0}")] UrlParse(String), #[error(transparent)] AddrParseError(#[from] std::net::AddrParseError), #[error("Could not parse token parameter")] TokenParseError, #[error(transparent)] TryFromSliceError(#[from] std::array::TryFromSliceError), #[cfg(feature = "dashu")] #[error(transparent)] DashuConversionError(#[from] dashu::base::error::ConversionError), #[cfg(feature = "dashu")] #[error(transparent)] DashuParseError(#[from] dashu::base::error::ParseError), #[cfg(feature = "semver")] #[error("semver parse error: {0}")] SemverError(String), // =============== // Encoding errors // =============== #[error("decode failed: {0}")] DecodeError(&'static str), #[error("encode failed: {0}")] EncodeError(&'static str), #[error("VarInt was encoded in a non-minimal way")] NonMinimalVarInt, #[error(transparent)] Utf8Error(#[from] std::string::FromUtf8Error), #[error(transparent)] StrUtf8Error(#[from] std::str::Utf8Error), #[cfg(feature = "serde_json")] #[error("serde_json error: {0}")] SerdeJsonError(String), #[cfg(feature = "tinyjson")] #[error("JSON parse error: {0}")] JsonParseError(String), #[cfg(feature = "tinyjson")] #[error("JSON generate error: {0}")] JsonGenerateError(String), #[cfg(feature = "toml")] #[error(transparent)] TomlDeserializeError(#[from] toml::de::Error), #[cfg(feature = "bs58")] #[error(transparent)] Bs58DecodeError(#[from] bs58::decode::Error), #[error("Bad operation type byte")] BadOperationType, // ====================== // Network-related errors // ====================== #[error("Invalid Dialer scheme")] InvalidDialerScheme, #[error("Invalid Listener scheme")] InvalidListenerScheme, #[error("Unsupported network transport: {0}")] UnsupportedTransport(String), #[error("Unsupported network transport upgrade: {0}")] UnsupportedTransportUpgrade(String), #[error("Connection failed")] ConnectFailed, #[cfg(feature = "system")] #[error(transparent)] TimeoutError(#[from] crate::system::timeout::TimeoutError), #[error("Connection timed out")] ConnectTimeout, #[error("Channel stopped")] ChannelStopped, #[error("Channel timed out")] ChannelTimeout, #[error("Failed to reach any seeds")] SeedFailed, #[error("Network service stopped")] NetworkServiceStopped, #[error("Create listener bound to {0} failed")] BindFailed(String), #[error("Accept a new incoming connection from the listener {0} failed")] AcceptConnectionFailed(String), #[error("Accept a new tls connection from the listener {0} failed")] AcceptTlsConnectionFailed(String), #[error("Network operation failed")] NetworkOperationFailed, #[error("Missing P2P message dispatcher")] MissingDispatcher, #[cfg(feature = "arti-client")] #[error(transparent)] ArtiError(#[from] arti_client::Error), #[error("Malformed packet")] MalformedPacket, #[error("Socks proxy error: {0}")] SocksError(String), #[error("No Socks5 URL found")] NoSocks5UrlFound, #[error("No URL found")] NoUrlFound, #[cfg(feature = "async-tungstenite")] #[error("tungstenite error: {0}")] TungsteniteError(String), #[error("Tor error: {0}")] TorError(String), #[error("Node is not connected to other nodes.")] NetworkNotConnected, #[error("P2P network stopped")] P2PNetworkStopped, #[error("No matching hostlist entry")] HostDoesNotExist, // ============= // Crypto errors // ============= #[cfg(feature = "halo2_proofs")] #[error("halo2 plonk error: {0}")] PlonkError(String), #[error("Wrong witness type at index: {0}")] WrongWitnessType(usize), #[error("Wrong witnesses count")] WrongWitnessesCount, #[error("Wrong public inputs count")] WrongPublicInputsCount, #[error("Unable to decrypt mint note: {0}")] NoteDecryptionFailed(String), #[error("No keypair file detected")] KeypairPathNotFound, #[error("Failed converting bytes to PublicKey")] PublicKeyFromBytes, #[error("Failed converting bytes to Coin")] CoinFromBytes, #[error("Failed converting bytes to SecretKey")] SecretKeyFromBytes, #[error("Failed converting b58 string to PublicKey")] PublicKeyFromStr, #[error("Failed converting bs58 string to SecretKey")] SecretKeyFromStr, #[error("Invalid DarkFi address")] InvalidAddress, #[cfg(feature = "async-rustls")] #[error(transparent)] RustlsError(#[from] async_rustls::rustls::Error), #[cfg(feature = "async-rustls")] #[error("Invalid DNS Name {0}")] RustlsInvalidDns(String), #[error("unable to decrypt rcpt")] TxRcptDecryptionError, #[cfg(feature = "blake3")] #[error(transparent)] Blake3FromHexError(#[from] blake3::HexError), // ======================= // Protocol-related errors // ======================= #[error("Unsupported chain")] UnsupportedChain, #[error("JSON-RPC error: {0:?}")] JsonRpcError((i32, String)), #[cfg(feature = "rpc")] #[error(transparent)] RpcServerError(RpcError), #[cfg(feature = "rpc")] #[error("JSON-RPC connections exhausted")] RpcConnectionsExhausted, #[cfg(feature = "rpc")] #[error("JSON-RPC server stopped")] RpcServerStopped, #[cfg(feature = "rpc")] #[error("JSON-RPC client stopped")] RpcClientStopped, #[error("Unexpected JSON-RPC data received: {0}")] UnexpectedJsonRpc(String), #[error("Received proposal from unknown node")] UnknownNodeError, #[error("Public inputs are invalid")] InvalidPublicInputsError, #[error("Coin is not the slot block producer")] CoinIsNotSlotProducer, #[error("Error during leader proof verification")] LeaderProofVerification, #[error("Signature could not be verified")] InvalidSignature, #[error("State transition failed")] StateTransitionError, #[error("No forks exist")] ForksNotFound, #[error("Check if proposal extends any existing fork chains failed")] ExtendedChainIndexNotFound, #[error("Proposal received after finalization sync period")] ProposalAfterFinalizationError, #[error("Proposal received not for current slot")] ProposalNotForCurrentSlotError, #[error("Proposal contains missmatched hashes")] ProposalHashesMissmatchError, #[error("Proposal contains unknown slots")] ProposalContainsUnknownSlots, #[error("Proposal contains missmatched headers")] ProposalHeadersMissmatchError, #[error("Proposal contains different coin creation eta")] ProposalDifferentCoinEtaError, #[error("Proposal contains spent coin")] ProposalIsSpent, #[error("Proposal contains more transactions than configured cap")] ProposalTxsExceedCapError, #[error("Unable to verify transfer transaction")] TransferTxVerification, #[error("Unable to verify proposed mu values")] ProposalPublicValuesMismatched, #[error("Proposer is not eligible to produce proposals")] ProposalProposerNotEligible, #[error("Erroneous transactions detected")] ErroneousTxsDetected, #[error("Proposal task stopped")] ProposalTaskStopped, #[error("Proposal already exists")] ProposalAlreadyExists, #[error("Miner task stopped")] MinerTaskStopped, #[error("Calculated total work is zero")] PoWTotalWorkIsZero, #[error("Erroneous cutoff calculation")] PoWCuttofCalculationError, #[error("Provided timestamp is invalid")] PoWInvalidTimestamp, #[error("Provided output hash is greater than current target")] PoWInvalidOutHash, // =============== // Database errors // =============== #[cfg(feature = "rusqlite")] #[error("rusqlite error: {0}")] RusqliteError(String), #[cfg(feature = "sled")] #[error(transparent)] SledError(#[from] sled::Error), #[cfg(feature = "sled")] #[error(transparent)] SledTransactionError(#[from] sled::transaction::TransactionError), #[error("Transaction {0} not found in database")] TransactionNotFound(String), #[error("Transaction already seen")] TransactionAlreadySeen, #[error("Input vectors have different length")] InvalidInputLengths, #[error("Header {0} not found in database")] HeaderNotFound(String), #[error("Block {0} is invalid")] BlockIsInvalid(String), #[error("Block version {0} is invalid")] BlockVersionIsInvalid(u8), #[error("Block {0} already in database")] BlockAlreadyExists(String), #[error("Block {0} not found in database")] BlockNotFound(String), #[error("Block with order number {0} not found in database")] BlockNumberNotFound(u64), #[error("Block difficulty for height number {0} not found in database")] BlockDifficultyNotFound(u64), #[error("Block {0} contains 0 transactions")] BlockContainsNoTransactions(String), #[error("Verifying slot missmatch")] VerifyingSlotMissmatch(), #[error("Slot {0} is invalid")] SlotIsInvalid(u64), #[error("Slot {0} not found in database")] SlotNotFound(u64), #[error("Block {0} slots not found in database")] BlockSlotsNotFound(String), #[error("Future slot {0} was received")] FutureSlotReceived(u64), #[error("Contract {0} not found in database")] ContractNotFound(String), #[error("Contract state tree not found")] ContractStateNotFound, #[error("Contract already initialized")] ContractAlreadyInitialized, #[error("zkas bincode not found in sled database")] ZkasBincodeNotFound, // =================== // wasm runtime errors // =================== #[cfg(feature = "wasm-runtime")] #[error("Wasmer compile error: {0}")] WasmerCompileError(String), #[cfg(feature = "wasm-runtime")] #[error("Wasmer export error: {0}")] WasmerExportError(String), #[cfg(feature = "wasm-runtime")] #[error("Wasmer runtime error: {0}")] WasmerRuntimeError(String), #[cfg(feature = "wasm-runtime")] #[error("Wasmer instantiation error: {0}")] WasmerInstantiationError(String), #[cfg(feature = "wasm-runtime")] #[error("wasm memory error")] WasmerMemoryError(String), #[cfg(feature = "wasm-runtime")] #[error("wasm runtime out of memory")] WasmerOomError(String), #[cfg(feature = "darkfi-sdk")] #[error("Contract execution failed: {0}")] ContractError(darkfi_sdk::error::ContractError), #[cfg(feature = "darkfi-sdk")] #[error("Invalid DarkTree: {0}")] DarkTreeError(darkfi_sdk::error::DarkTreeError), #[cfg(feature = "blockchain")] #[error("contract wasm bincode not found")] WasmBincodeNotFound, #[cfg(feature = "wasm-runtime")] #[error("contract initialize error")] ContractInitError(u64), #[cfg(feature = "wasm-runtime")] #[error("contract execution error")] ContractExecError(u64), #[cfg(feature = "wasm-runtime")] #[error("wasm function ACL denied")] WasmFunctionAclDenied, // ==================== // Event Graph errors // ==================== #[error("Event is not found in tree: {0}")] EventNotFound(String), #[error("Event is invalid")] EventIsInvalid, // ==================== // Miscellaneous errors // ==================== #[error("IO error: {0}")] Io(std::io::ErrorKind), #[error("Infallible error: {0}")] InfallibleError(String), #[cfg(feature = "smol")] #[error("async_channel sender error: {0}")] AsyncChannelSendError(String), #[cfg(feature = "smol")] #[error("async_channel receiver error: {0}")] AsyncChannelRecvError(String), #[error("SetLogger (log crate) failed: {0}")] SetLoggerError(String), #[error("ValueIsNotObject")] ValueIsNotObject, #[error("No config file detected")] ConfigNotFound, #[error("Invalid config file detected")] ConfigInvalid, #[error("Failed decoding bincode: {0}")] ZkasDecoderError(String), #[cfg(feature = "util")] #[error("System clock is not correct!")] InvalidClock, #[error("Unsupported OS")] UnsupportedOS, #[error("System clock went backwards")] BackwardsTime(std::time::SystemTimeError), #[error("Detached task stopped")] DetachedTaskStopped, // ============================================== // Wrappers for other error types in this library // ============================================== #[error(transparent)] ClientFailed(#[from] ClientFailed), #[cfg(feature = "tx")] #[error(transparent)] TxVerifyFailed(#[from] TxVerifyFailed), //============= // clock //============= #[error("clock out of sync with peers: {0}")] ClockOutOfSync(String), // ================ // DHT/Geode errors // ================ #[error("Geode needs garbage collection")] GeodeNeedsGc, #[error("Geode file not found")] GeodeFileNotFound, #[error("Geode chunk not found")] GeodeChunkNotFound, #[error("Geode file route not found")] GeodeFileRouteNotFound, #[error("Geode chunk route not found")] GeodeChunkRouteNotFound, // ================== // Event Graph errors // ================== #[error("DAG sync failed")] DagSyncFailed, // ========= // Catch-all // ========= #[error("{0}")] Custom(String), } #[cfg(feature = "tx")] impl Error { /// Auxiliary function to retrieve the vector of erroneous /// transactions from a TxVerifyFailed error. /// In any other case, we return the error itself. pub fn retrieve_erroneous_txs(&self) -> Result> { if let Self::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(erroneous_txs)) = self { return Ok(erroneous_txs.clone()) }; Err(self.clone()) } } #[cfg(feature = "tx")] /// Transaction verification errors #[derive(Debug, Clone, thiserror::Error)] pub enum TxVerifyFailed { #[error("Transaction {0} already exists")] AlreadySeenTx(String), #[error("Invalid transaction signature")] InvalidSignature, #[error("Missing signatures in transaction")] MissingSignatures, #[error("Missing contract calls in transaction")] MissingCalls, #[error("Invalid ZK proof in transaction")] InvalidZkProof, #[error("Missing Money::Fee call in transaction")] MissingFee, #[error("Invalid Money::Fee call in transaction")] InvalidFee, #[error("Insufficient fee paid")] InsufficientFee, #[error("Erroneous transactions found")] ErroneousTxs(Vec), } /// Client module errors #[derive(Debug, Clone, thiserror::Error)] pub enum ClientFailed { #[error("IO error: {0}")] Io(std::io::ErrorKind), #[error("Not enough value: {0}")] NotEnoughValue(u64), #[error("Invalid address: {0}")] InvalidAddress(String), #[error("Invalid amount: {0}")] InvalidAmount(u64), #[error("Invalid token ID: {0}")] InvalidTokenId(String), #[error("Internal error: {0}")] InternalError(String), #[error("Verify error: {0}")] VerifyError(String), } #[cfg(feature = "rpc")] #[derive(Clone, Debug, thiserror::Error)] pub enum RpcError { #[error("Connection closed: {0}")] ConnectionClosed(String), #[error("Invalid JSON: {0}")] InvalidJson(String), #[error("IO Error: {0}")] IoError(std::io::ErrorKind), } #[cfg(feature = "rpc")] impl From for RpcError { fn from(err: std::io::Error) -> Self { Self::IoError(err.kind()) } } #[cfg(feature = "rpc")] impl From for Error { fn from(err: RpcError) -> Self { Self::RpcServerError(err) } } impl From for ClientFailed { fn from(err: Error) -> Self { Self::InternalError(err.to_string()) } } impl From for ClientFailed { fn from(err: std::io::Error) -> Self { Self::Io(err.kind()) } } impl From for Error { fn from(err: std::io::Error) -> Self { Self::Io(err.kind()) } } impl From for Error { fn from(err: std::time::SystemTimeError) -> Self { Self::BackwardsTime(err) } } impl From for Error { fn from(err: std::convert::Infallible) -> Self { Self::InfallibleError(err.to_string()) } } impl From<()> for Error { fn from(_err: ()) -> Self { Self::InfallibleError("Infallible".into()) } } #[cfg(feature = "smol")] impl From> for Error { fn from(err: smol::channel::SendError) -> Self { Self::AsyncChannelSendError(err.to_string()) } } #[cfg(feature = "smol")] impl From for Error { fn from(err: smol::channel::RecvError) -> Self { Self::AsyncChannelRecvError(err.to_string()) } } impl From for Error { fn from(err: log::SetLoggerError) -> Self { Self::SetLoggerError(err.to_string()) } } #[cfg(feature = "rusqlite")] impl From for Error { fn from(err: rusqlite::Error) -> Self { Self::RusqliteError(err.to_string()) } } #[cfg(feature = "halo2_proofs")] impl From for Error { fn from(err: halo2_proofs::plonk::Error) -> Self { Self::PlonkError(err.to_string()) } } #[cfg(feature = "semver")] impl From for Error { fn from(err: semver::Error) -> Self { Self::SemverError(err.to_string()) } } /* #[cfg(feature = "tungstenite")] impl From for Error { fn from(err: tungstenite::Error) -> Self { Self::TungsteniteError(err.to_string()) } } */ #[cfg(feature = "async-tungstenite")] impl From for Error { fn from(err: async_tungstenite::tungstenite::Error) -> Self { Self::TungsteniteError(err.to_string()) } } #[cfg(feature = "async-rustls")] impl From for Error { fn from(err: async_rustls::rustls::client::InvalidDnsNameError) -> Self { Self::RustlsInvalidDns(err.to_string()) } } #[cfg(feature = "serde_json")] impl From for Error { fn from(err: serde_json::Error) -> Self { Self::SerdeJsonError(err.to_string()) } } #[cfg(feature = "tinyjson")] impl From for Error { fn from(err: tinyjson::JsonParseError) -> Self { Self::JsonParseError(err.to_string()) } } #[cfg(feature = "tinyjson")] impl From for Error { fn from(err: tinyjson::JsonGenerateError) -> Self { Self::JsonGenerateError(err.to_string()) } } #[cfg(feature = "fast-socks5")] impl From for Error { fn from(err: fast_socks5::SocksError) -> Self { Self::SocksError(err.to_string()) } } #[cfg(feature = "wasm-runtime")] impl From for Error { fn from(err: wasmer::CompileError) -> Self { Self::WasmerCompileError(err.to_string()) } } #[cfg(feature = "wasm-runtime")] impl From for Error { fn from(err: wasmer::ExportError) -> Self { Self::WasmerExportError(err.to_string()) } } #[cfg(feature = "wasm-runtime")] impl From for Error { fn from(err: wasmer::RuntimeError) -> Self { Self::WasmerRuntimeError(err.to_string()) } } #[cfg(feature = "wasm-runtime")] impl From for Error { fn from(err: wasmer::InstantiationError) -> Self { Self::WasmerInstantiationError(err.to_string()) } } #[cfg(feature = "wasm-runtime")] impl From for Error { fn from(err: wasmer::MemoryAccessError) -> Self { Self::WasmerMemoryError(err.to_string()) } } #[cfg(feature = "wasm-runtime")] impl From for Error { fn from(err: wasmer::MemoryError) -> Self { Self::WasmerOomError(err.to_string()) } } #[cfg(feature = "darkfi-sdk")] impl From for Error { fn from(err: darkfi_sdk::error::ContractError) -> Self { Self::ContractError(err) } } #[cfg(feature = "darkfi-sdk")] impl From for Error { fn from(err: darkfi_sdk::error::DarkTreeError) -> Self { Self::DarkTreeError(err) } }