inkpad_executor/
result.rs

1//! Inkpad executor result
2use crate::{
3    trap::{Trap, TrapCode},
4    Value,
5};
6use inkpad_std::{fmt, format, String, Vec};
7use parity_scale_codec::{Decode, Encode};
8
9bitflags::bitflags! {
10    /// Flags used by a contract to customize exit behaviour.
11    #[derive(Encode, Decode, Default)]
12    pub struct ReturnFlags: u32 {
13        /// If this bit is set all changes made by the contract execution are rolled back.
14        const REVERT = 0x0000_0001;
15    }
16}
17
18/// Successful Return data
19#[derive(PartialEq, Eq, Debug, Clone, Default, Encode, Decode)]
20pub struct ReturnData {
21    /// Flags passed along by `seal_return`. Empty when `seal_return` was never called.
22    pub flags: ReturnFlags,
23    /// Buffer passed along by `seal_return`. Empty when `seal_return` was never called.
24    pub data: Vec<u8>,
25}
26
27#[repr(i32)]
28#[derive(Debug, PartialEq, Eq, Clone, Copy)]
29pub enum ReturnCode {
30    /// API call successful.
31    Success = 0,
32    /// The called function trapped and has its state changes reverted.
33    /// In this case no output buffer is returned.
34    CalleeTrapped = 1,
35    /// The called function ran to completion but decided to revert its state.
36    /// An output buffer is returned when one was supplied.
37    CalleeReverted = 2,
38    /// The passed key does not exist in storage.
39    KeyNotFound = 3,
40    /// Transfer failed because it would have brought the sender's total balance below the
41    /// subsistence threshold.
42    BelowSubsistenceThreshold = 4,
43    /// Transfer failed for other reasons. Most probably reserved or locked balance of the
44    /// sender prevents the transfer.
45    TransferFailed = 5,
46    /// The newly created contract is below the subsistence threshold after executing
47    /// its constructor.
48    NewContractNotFunded = 6,
49    /// No code could be found at the supplied code hash.
50    CodeNotFound = 7,
51    /// The contract that was called is either no contract at all (a plain account)
52    /// or is a tombstone.
53    NotCallable = 8,
54    /// The call to `seal_debug_message` had no effect because debug message
55    /// recording was disabled.
56    LoggingDisabled = 9,
57    /// The call dispatched by `seal_call_runtime` was executed but returned an error.
58    CallRuntimeReturnedError = 10,
59    /// ECDSA pubkey recovery failed. Most probably wrong recovery id or signature.
60    EcdsaRecoverFailed = 11,
61    /// Unexpected return code
62    UnExpectedReturnCode = 12,
63}
64
65impl From<i32> for ReturnCode {
66    fn from(n: i32) -> ReturnCode {
67        match n {
68            0 => ReturnCode::Success,
69            1 => ReturnCode::CalleeTrapped,
70            2 => ReturnCode::CalleeReverted,
71            3 => ReturnCode::KeyNotFound,
72            4 => ReturnCode::BelowSubsistenceThreshold,
73            5 => ReturnCode::TransferFailed,
74            6 => ReturnCode::NewContractNotFunded,
75            7 => ReturnCode::CodeNotFound,
76            8 => ReturnCode::NotCallable,
77            9 => ReturnCode::LoggingDisabled,
78            _ => ReturnCode::UnExpectedReturnCode,
79        }
80    }
81}
82
83/// Inkpad executor errors
84#[derive(Debug, Eq, PartialEq, Clone)]
85pub enum Error {
86    InitMemoryFailed,
87    /// Memory outof bounds
88    OutOfBounds,
89    InitModuleFailed,
90    ExecuteFailed(ReturnCode),
91    UnkownError,
92    Trap(Trap),
93    GetFunctionNameFailed,
94    CreateWasmtimeConfigFailed,
95    GetExternalFailed(String),
96    DecodeRuntimeValueFailed,
97    OutputBufferTooSmall,
98    WrongArugmentLength,
99    SetStorageFailed,
100    Return(ReturnData),
101    /// Topics
102    TooManyTopics,
103    DuplicateTopics,
104    TopicValueTooLarge,
105    /// Gas
106    OutOfGas,
107    /// Custom Error
108    Custom(&'static str),
109    /// Unexpected return value
110    UnExpectedReturnValue,
111    ParseWasmModuleFailed,
112    ExecutorNotInited,
113    CodeNotFound,
114    ExitedAllFrames,
115    CalcuateMemoryLimitFailed,
116    InitExecutorFailed,
117    DecodeBucketFailed([u8; 32]),
118    MemoryNotFound,
119    SerializationError(String),
120    StateNotFound,
121    CodeHashNotFound,
122    DecodeContractFailed,
123    FlushDataFailed,
124}
125
126impl From<parity_wasm::SerializationError> for Error {
127    fn from(e: parity_wasm::SerializationError) -> Error {
128        Error::SerializationError(format!("{}", e))
129    }
130}
131
132impl From<&'static str> for Error {
133    fn from(e: &'static str) -> Error {
134        Error::Custom(e)
135    }
136}
137
138#[cfg(feature = "wasmtime")]
139impl std::error::Error for Error {}
140
141impl fmt::Display for Error {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        write!(f, "{:?}", self)
144    }
145}
146
147/// Inkpad executor result
148pub type Result<T> = core::result::Result<T, Error>;
149
150/// Wasm function execution result
151#[derive(Clone, Default)]
152pub struct ExecResult {
153    pub data: ReturnData,
154    pub value: Value,
155}
156
157impl ExecResult {
158    /// from execution result
159    pub fn from_res(v: Result<Value>) -> Result<ExecResult> {
160        Ok(match v {
161            Ok(value) => ExecResult {
162                value,
163                ..Default::default()
164            },
165            Err(Error::Trap(Trap {
166                code: TrapCode::HostError(e),
167                trace: _,
168            })) => Self::from_res(Err(*e))?,
169            Err(Error::Return(data)) => {
170                if data.flags.contains(ReturnFlags::REVERT) {
171                    return Err(Error::ExecuteFailed(ReturnCode::CalleeReverted));
172                }
173                ExecResult {
174                    data,
175                    ..Default::default()
176                }
177            }
178            Err(e) => return Err(e),
179        })
180    }
181}