1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
use std::{num::ParseIntError, path::PathBuf};

use humantime::{DurationError, TimestampError};
use jsonrpc_lite::JsonRpc;
use thiserror::Error;

use casper_node::{crypto::Error as CryptoError, types::ExcessiveSizeDeployError};
use casper_types::{
    bytesrepr::Error as ToBytesError, CLValueError, UIntParseError, URefFromStrError,
};

use crate::validation::ValidateResponseError;

/// Crate-wide Result type wrapper.
pub(crate) type Result<T> = std::result::Result<T, Error>;

/// Error that can be returned by `casper-client`.
#[derive(Error, Debug)]
pub enum Error {
    /// Failed to parse a
    /// [`Key`](https://docs.rs/casper-types/latest/casper-types/enum.PublicKey.html) from a
    /// formatted string.
    #[error("Failed to parse as a key")]
    FailedToParseKey,

    /// Failed to parse a `URef` from a formatted string.
    #[error("Failed to parse '{context}' as a uref: {error}")]
    FailedToParseURef {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// The actual error raised.
        error: URefFromStrError,
    },

    /// Failed to parse an integer from a string.
    #[error("Failed to parse '{context}' as an integer: {error}")]
    FailedToParseInt {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// The actual error raised.
        error: ParseIntError,
    },

    /// Failed to parse a `TimeDiff` from a formatted string.
    #[error("Failed to parse '{context}' as a time diff: {error}")]
    FailedToParseTimeDiff {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// The actual error raised.
        error: DurationError,
    },

    /// Failed to parse a `Timestamp` from a formatted string.
    #[error("Failed to parse '{context}' as a timestamp: {error}")]
    FailedToParseTimestamp {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// The actual error raised.
        error: TimestampError,
    },

    /// Failed to parse a `U128`, `U256` or `U512` from a string.
    #[error("Failed to parse '{context}' as U128, U256, or U512: {error:?}")]
    FailedToParseUint {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// The actual error raised.
        error: UIntParseError,
    },

    /// Deploy size too large.
    #[error("Deploy size too large: {0}")]
    DeploySizeTooLarge(#[from] ExcessiveSizeDeployError),

    /// Failed to get a response from the node.
    #[error("Failed to get RPC response: {0}")]
    FailedToGetResponse(reqwest::Error),

    /// Failed to parse the response from the node.
    #[error("Failed to parse as JSON-RPC response: {0}")]
    FailedToParseResponse(reqwest::Error),

    /// Failed to create new file because it already exists.
    #[error("File at {} already exists", .0.display())]
    FileAlreadyExists(PathBuf),

    /// Unsupported keygen algorithm.
    #[error("Unsupported keygen algorithm: {0}")]
    UnsupportedAlgorithm(String),

    /// JSON-RPC error returned from the node.
    #[error("RPC response is error: {0}")]
    ResponseIsError(#[from] jsonrpc_lite::Error),

    /// Invalid JSON returned from the node.
    #[error("Invalid JSON: {0}")]
    InvalidJson(#[from] serde_json::Error),

    /// Invalid response returned from the node.
    #[error("Invalid response: {0:?}")]
    InvalidRpcResponse(JsonRpc),

    /// Failed to send the request to the node.
    #[error("Failed sending {0:?}")]
    FailedSending(JsonRpc),

    /// Context-adding wrapper for `std::io::Error`.
    #[error("IO error: {context}: {error}")]
    IoError {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: String,
        /// std::io::Error raised during the operation in question.
        error: std::io::Error,
    },

    /// Failed to serialize to bytes.
    #[error("Serialization error: {0}")]
    ToBytesError(ToBytesError),

    /// Cryptographic error.
    #[error("Cryptographic error: {context}: {error}")]
    CryptoError {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// Underlying crypto error.
        error: CryptoError,
    },

    /// Invalid `CLValue`.
    #[error("Invalid CLValue error: {0}")]
    InvalidCLValue(String),

    /// Invalid argument.
    #[error("Invalid argument '{context}': {error}")]
    InvalidArgument {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// An error message.
        error: String,
    },

    /// Conflicting arguments.
    #[error("Conflicting arguments passed '{context}' {args:?}")]
    ConflictingArguments {
        /// Contextual description of where this error occurred including relevant paths,
        /// filenames, etc.
        context: &'static str,
        /// Arguments passed, with their values.
        args: Vec<String>,
    },

    /// Failed to validate response.
    #[error("Invalid response: {0}")]
    InvalidResponse(#[from] ValidateResponseError),

    /// Failed to create a DictionaryIdentifier
    #[error("Failed to parse the dictionary identifier")]
    FailedToParseDictionaryIdentifier,

    /// Failed to identify the hash as either block hash or state root hash.
    #[error("Failed to parse state identifier")]
    FailedToParseStateIdentifier,

    /// Must call FFI's setup function prior to making FFI calls.
    #[cfg(feature = "ffi")]
    #[error("Failed to call casper_setup_client()")]
    FFISetupNotCalled,

    /// Must pass valid pointer values to FFI calls.
    #[cfg(feature = "ffi")]
    #[error("Required argument '{0}' was null")]
    FFIPtrNullButRequired(&'static str),
}

impl From<ToBytesError> for Error {
    fn from(error: ToBytesError) -> Self {
        Error::ToBytesError(error)
    }
}

impl From<CLValueError> for Error {
    fn from(error: CLValueError) -> Self {
        match error {
            CLValueError::Serialization(bytesrepr_error) => bytesrepr_error.into(),
            CLValueError::Type(type_mismatch) => Error::InvalidCLValue(type_mismatch.to_string()),
        }
    }
}