revm_precompile/
interface.rs

1use context_interface::result::EVMError;
2use core::fmt;
3use primitives::Bytes;
4use std::string::{String, ToString};
5
6/// A precompile operation result type
7///
8/// Returns either `Ok((gas_used, return_bytes))` or `Err(error)`.
9pub type PrecompileResult = Result<PrecompileOutput, PrecompileError>;
10
11/// Precompile execution output
12#[derive(Clone, Debug, PartialEq, Eq, Hash)]
13pub struct PrecompileOutput {
14    /// Gas used by the precompile
15    pub gas_used: u64,
16    /// Output bytes
17    pub bytes: Bytes,
18}
19
20impl PrecompileOutput {
21    /// Returns new precompile output with the given gas used and output bytes.
22    pub fn new(gas_used: u64, bytes: Bytes) -> Self {
23        Self { gas_used, bytes }
24    }
25}
26
27pub type PrecompileFn = fn(&Bytes, u64) -> PrecompileResult;
28
29#[derive(Clone, Debug, PartialEq, Eq, Hash)]
30pub enum PrecompileError {
31    /// out of gas is the main error. Others are here just for completeness
32    OutOfGas,
33    // Blake2 errors
34    Blake2WrongLength,
35    Blake2WrongFinalIndicatorFlag,
36    // Modexp errors
37    ModexpExpOverflow,
38    ModexpBaseOverflow,
39    ModexpModOverflow,
40    // Bn128 errors
41    Bn128FieldPointNotAMember,
42    Bn128AffineGFailedToCreate,
43    Bn128PairLength,
44    // Blob errors
45    /// The input length is not exactly 192 bytes
46    BlobInvalidInputLength,
47    /// The commitment does not match the versioned hash
48    BlobMismatchedVersion,
49    /// The proof verification failed
50    BlobVerifyKzgProofFailed,
51    /// Fatal error with a custom error message
52    Fatal(String),
53    /// Catch-all variant for other errors
54    Other(String),
55}
56
57impl PrecompileError {
58    /// Returns another error with the given message.
59    pub fn other(err: impl Into<String>) -> Self {
60        Self::Other(err.into())
61    }
62
63    /// Returns `true` if the error is out of gas.
64    pub fn is_oog(&self) -> bool {
65        matches!(self, Self::OutOfGas)
66    }
67}
68
69impl<DB, TXERROR> From<PrecompileError> for EVMError<DB, TXERROR> {
70    fn from(value: PrecompileError) -> Self {
71        Self::Precompile(value.to_string())
72    }
73}
74
75impl core::error::Error for PrecompileError {}
76
77impl fmt::Display for PrecompileError {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        let s = match self {
80            Self::OutOfGas => "out of gas",
81            Self::Blake2WrongLength => "wrong input length for blake2",
82            Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
83            Self::ModexpExpOverflow => "modexp exp overflow",
84            Self::ModexpBaseOverflow => "modexp base overflow",
85            Self::ModexpModOverflow => "modexp mod overflow",
86            Self::Bn128FieldPointNotAMember => "field point not a member of bn128 curve",
87            Self::Bn128AffineGFailedToCreate => "failed to create affine g point for bn128 curve",
88            Self::Bn128PairLength => "bn128 invalid pair length",
89            Self::BlobInvalidInputLength => "invalid blob input length",
90            Self::BlobMismatchedVersion => "mismatched blob version",
91            Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
92            Self::Fatal(s) => s,
93            Self::Other(s) => s,
94        };
95        f.write_str(s)
96    }
97}