cosmwasm_vm/
backend.rs

1use std::fmt::Debug;
2use std::ops::AddAssign;
3use std::string::FromUtf8Error;
4use thiserror::Error;
5
6use cosmwasm_std::{Binary, ContractResult, SystemResult};
7#[cfg(feature = "iterator")]
8use cosmwasm_std::{Order, Record};
9
10/// A structure that represents gas cost to be deducted from the remaining gas.
11/// This is always needed when computations are performed outside of
12/// Wasm execution, such as calling crypto APIs or calls into the blockchain.
13///
14/// All values are measured in [CosmWasm gas].
15///
16/// [CosmWasm gas]: https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18pub struct GasInfo {
19    /// The gas cost of a computation that was executed already but not yet charged.
20    ///
21    /// This could be renamed to `internally_used` for consistency because it is used inside
22    /// of the `cosmwasm_vm`.
23    pub cost: u64,
24    /// Gas that was used and charged externally. This is needed to
25    /// adjust the VM's gas limit but does not affect the gas usage.
26    ///
27    /// Since this is measured in [CosmWasm gas], the caller may need
28    /// to convert from Cosmos SDK gas in cases where an SDK gas meter
29    /// is used.
30    ///
31    /// [CosmWasm gas]: https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md
32    pub externally_used: u64,
33}
34
35impl GasInfo {
36    pub fn new(cost: u64, externally_used: u64) -> Self {
37        GasInfo {
38            cost,
39            externally_used,
40        }
41    }
42
43    pub fn with_cost(amount: u64) -> Self {
44        GasInfo {
45            cost: amount,
46            externally_used: 0,
47        }
48    }
49
50    pub fn with_externally_used(amount: u64) -> Self {
51        GasInfo {
52            cost: 0,
53            externally_used: amount,
54        }
55    }
56
57    /// Creates a gas information with no cost for the caller and with zero externally used gas.
58    ///
59    /// Caution: when using this you need to make sure no gas was metered externally to keep the gas values in sync.
60    pub fn free() -> Self {
61        GasInfo {
62            cost: 0,
63            externally_used: 0,
64        }
65    }
66}
67
68impl AddAssign for GasInfo {
69    fn add_assign(&mut self, other: Self) {
70        *self = GasInfo {
71            cost: self.cost + other.cost,
72            externally_used: self.externally_used + other.externally_used,
73        };
74    }
75}
76
77/// Holds all external dependencies of the contract.
78/// Designed to allow easy dependency injection at runtime.
79/// This cannot be copied or cloned since it would behave differently
80/// for mock storages and a bridge storage in the VM.
81pub struct Backend<A: BackendApi, S: Storage, Q: Querier> {
82    pub api: A,
83    pub storage: S,
84    pub querier: Q,
85}
86
87/// Access to the VM's backend storage, i.e. the chain
88pub trait Storage {
89    /// Returns Err on error.
90    /// Returns Ok(None) when key does not exist.
91    /// Returns Ok(Some(Vec<u8>)) when key exists.
92    ///
93    /// Note: Support for differentiating between a non-existent key and a key with empty value
94    /// is not great yet and might not be possible in all backends. But we're trying to get there.
95    fn get(&self, key: &[u8]) -> BackendResult<Option<Vec<u8>>>;
96
97    /// Allows iteration over a set of key/value pairs, either forwards or backwards.
98    /// Returns an iterator ID that is unique within the Storage instance.
99    ///
100    /// The bound `start` is inclusive and `end` is exclusive.
101    ///
102    /// If `start` is lexicographically greater than or equal to `end`, an empty range is described, mo matter of the order.
103    ///
104    /// This call must not change data in the storage, but creating and storing a new iterator can be a mutating operation on
105    /// the Storage implementation.
106    /// The implementation must ensure that iterator IDs are assigned in a deterministic manner as this is
107    /// environment data that is injected into the contract.
108    #[cfg(feature = "iterator")]
109    fn scan(
110        &mut self,
111        start: Option<&[u8]>,
112        end: Option<&[u8]>,
113        order: Order,
114    ) -> BackendResult<u32>;
115
116    /// Returns the next element of the iterator with the given ID.
117    ///
118    /// If the ID is not found, a BackendError::IteratorDoesNotExist is returned.
119    ///
120    /// This call must not change data in the storage, but incrementing an iterator can be a mutating operation on
121    /// the Storage implementation.
122    #[cfg(feature = "iterator")]
123    fn next(&mut self, iterator_id: u32) -> BackendResult<Option<Record>>;
124
125    /// Returns the next value of the iterator with the given ID.
126    /// Since the iterator is incremented, the corresponding key will never be accessible.
127    ///
128    /// If the ID is not found, a BackendError::IteratorDoesNotExist is returned.
129    ///
130    /// The default implementation uses [`Storage::next`] and discards the key.
131    /// More efficient implementations might be possible depending on the storage.
132    #[cfg(feature = "iterator")]
133    fn next_value(&mut self, iterator_id: u32) -> BackendResult<Option<Vec<u8>>> {
134        let (result, gas_info) = self.next(iterator_id);
135        let result = result.map(|record| record.map(|(_, v)| v));
136        (result, gas_info)
137    }
138
139    /// Returns the next key of the iterator with the given ID.
140    /// Since the iterator is incremented, the corresponding value will never be accessible.
141    ///
142    /// If the ID is not found, a BackendError::IteratorDoesNotExist is returned.
143    ///
144    /// The default implementation uses [`Storage::next`] and discards the value.
145    /// More efficient implementations might be possible depending on the storage.
146    #[cfg(feature = "iterator")]
147    fn next_key(&mut self, iterator_id: u32) -> BackendResult<Option<Vec<u8>>> {
148        let (result, gas_info) = self.next(iterator_id);
149        let result = result.map(|record| record.map(|(k, _)| k));
150        (result, gas_info)
151    }
152
153    fn set(&mut self, key: &[u8], value: &[u8]) -> BackendResult<()>;
154
155    /// Removes a database entry at `key`.
156    ///
157    /// The current interface does not allow to differentiate between a key that existed
158    /// before and one that didn't exist. See https://github.com/CosmWasm/cosmwasm/issues/290
159    fn remove(&mut self, key: &[u8]) -> BackendResult<()>;
160}
161
162/// Callbacks to system functions defined outside of the wasm modules.
163/// This is a trait to allow Mocks in the test code.
164///
165/// Currently it just supports address conversion, we could add eg. crypto functions here.
166/// These should all be pure (stateless) functions. If you need state, you probably want
167/// to use the Querier.
168pub trait BackendApi: Clone + Send {
169    fn addr_validate(&self, input: &str) -> BackendResult<()>;
170    fn addr_canonicalize(&self, human: &str) -> BackendResult<Vec<u8>>;
171    fn addr_humanize(&self, canonical: &[u8]) -> BackendResult<String>;
172}
173
174pub trait Querier {
175    /// This is all that must be implemented for the Querier.
176    /// This allows us to pass through binary queries from one level to another without
177    /// knowing the custom format, or we can decode it, with the knowledge of the allowed
178    /// types.
179    ///
180    /// The gas limit describes how much [CosmWasm gas] this particular query is allowed
181    /// to consume when measured separately from the rest of the contract.
182    /// The returned gas info (in BackendResult) can exceed the gas limit in cases
183    /// where the query could not be aborted exactly at the limit.
184    ///
185    /// [CosmWasm gas]: https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md
186    fn query_raw(
187        &self,
188        request: &[u8],
189        gas_limit: u64,
190    ) -> BackendResult<SystemResult<ContractResult<Binary>>>;
191}
192
193/// A result type for calling into the backend. Such a call can cause
194/// non-negligible computational cost in both success and failure case and
195/// must always have gas information attached.
196pub type BackendResult<T> = (core::result::Result<T, BackendError>, GasInfo);
197
198/// This aims to be similar to the `?` operator, but for a [`BackendResult`].
199///
200/// The first argument is a result. If it is Ok, return the value.
201/// If it is Err, end the current function with a `return BackendResult::Err`.
202///
203/// The second argument is the gas value that will be used in the error case.
204/// It should be the sum of all gas used in the calling function.
205macro_rules! unwrap_or_return_with_gas {
206    ($result: expr $(,)?, $gas_total: expr $(,)?) => {{
207        let result: core::result::Result<_, _> = $result; // just a type check
208        let gas: GasInfo = $gas_total; // just a type check
209        match result {
210            Ok(v) => v,
211            Err(e) => return (Err(e), gas),
212        }
213    }};
214}
215pub(crate) use unwrap_or_return_with_gas;
216
217#[derive(Error, Debug, PartialEq, Eq)]
218#[non_exhaustive]
219pub enum BackendError {
220    #[error("Panic in FFI call")]
221    ForeignPanic {},
222    #[error("Bad argument")]
223    BadArgument {},
224    #[error("VM received invalid UTF-8 data from backend")]
225    InvalidUtf8 {},
226    #[error("Iterator with ID {id} does not exist")]
227    IteratorDoesNotExist { id: u32 },
228    #[error("Ran out of gas during call into backend")]
229    OutOfGas {},
230    #[error("Unknown error during call into backend: {msg}")]
231    Unknown { msg: String },
232    // This is the only error case of BackendError that is reported back to the contract.
233    #[error("User error during call into backend: {msg}")]
234    UserErr { msg: String },
235}
236
237impl BackendError {
238    pub fn foreign_panic() -> Self {
239        BackendError::ForeignPanic {}
240    }
241
242    pub fn bad_argument() -> Self {
243        BackendError::BadArgument {}
244    }
245
246    pub fn iterator_does_not_exist(iterator_id: u32) -> Self {
247        BackendError::IteratorDoesNotExist { id: iterator_id }
248    }
249
250    pub fn out_of_gas() -> Self {
251        BackendError::OutOfGas {}
252    }
253
254    pub fn unknown(msg: impl Into<String>) -> Self {
255        BackendError::Unknown { msg: msg.into() }
256    }
257
258    pub fn user_err(msg: impl Into<String>) -> Self {
259        BackendError::UserErr { msg: msg.into() }
260    }
261}
262
263impl From<FromUtf8Error> for BackendError {
264    fn from(_original: FromUtf8Error) -> Self {
265        BackendError::InvalidUtf8 {}
266    }
267}
268
269#[cfg(test)]
270mod tests {
271    use super::*;
272
273    #[test]
274    fn gas_info_with_cost_works() {
275        let gas_info = GasInfo::with_cost(21);
276        assert_eq!(gas_info.cost, 21);
277        assert_eq!(gas_info.externally_used, 0);
278    }
279
280    #[test]
281    fn gas_info_with_externally_used_works() {
282        let gas_info = GasInfo::with_externally_used(65);
283        assert_eq!(gas_info.cost, 0);
284        assert_eq!(gas_info.externally_used, 65);
285    }
286
287    #[test]
288    fn gas_info_free_works() {
289        let gas_info = GasInfo::free();
290        assert_eq!(gas_info.cost, 0);
291        assert_eq!(gas_info.externally_used, 0);
292    }
293
294    #[test]
295    fn gas_info_implements_add_assign() {
296        let mut a = GasInfo::new(0, 0);
297        a += GasInfo::new(0, 0);
298        assert_eq!(
299            a,
300            GasInfo {
301                cost: 0,
302                externally_used: 0
303            }
304        );
305
306        let mut a = GasInfo::new(0, 0);
307        a += GasInfo::new(12, 0);
308        assert_eq!(
309            a,
310            GasInfo {
311                cost: 12,
312                externally_used: 0
313            }
314        );
315
316        let mut a = GasInfo::new(10, 0);
317        a += GasInfo::new(3, 0);
318        assert_eq!(
319            a,
320            GasInfo {
321                cost: 13,
322                externally_used: 0
323            }
324        );
325
326        let mut a = GasInfo::new(0, 0);
327        a += GasInfo::new(0, 7);
328        assert_eq!(
329            a,
330            GasInfo {
331                cost: 0,
332                externally_used: 7
333            }
334        );
335
336        let mut a = GasInfo::new(0, 8);
337        a += GasInfo::new(0, 9);
338        assert_eq!(
339            a,
340            GasInfo {
341                cost: 0,
342                externally_used: 17
343            }
344        );
345
346        let mut a = GasInfo::new(100, 200);
347        a += GasInfo::new(1, 2);
348        assert_eq!(
349            a,
350            GasInfo {
351                cost: 101,
352                externally_used: 202
353            }
354        );
355    }
356
357    // constructors
358
359    #[test]
360    fn backend_err_foreign_panic() {
361        let error = BackendError::foreign_panic();
362        match error {
363            BackendError::ForeignPanic { .. } => {}
364            e => panic!("Unexpected error: {e:?}"),
365        }
366    }
367
368    #[test]
369    fn backend_err_bad_argument() {
370        let error = BackendError::bad_argument();
371        match error {
372            BackendError::BadArgument { .. } => {}
373            e => panic!("Unexpected error: {e:?}"),
374        }
375    }
376
377    #[test]
378    fn iterator_does_not_exist_works() {
379        let error = BackendError::iterator_does_not_exist(15);
380        match error {
381            BackendError::IteratorDoesNotExist { id, .. } => assert_eq!(id, 15),
382            e => panic!("Unexpected error: {e:?}"),
383        }
384    }
385
386    #[test]
387    fn backend_err_out_of_gas() {
388        let error = BackendError::out_of_gas();
389        match error {
390            BackendError::OutOfGas { .. } => {}
391            e => panic!("Unexpected error: {e:?}"),
392        }
393    }
394
395    #[test]
396    fn backend_err_unknown() {
397        let error = BackendError::unknown("broken");
398        match error {
399            BackendError::Unknown { msg, .. } => assert_eq!(msg, "broken"),
400            e => panic!("Unexpected error: {e:?}"),
401        }
402    }
403
404    #[test]
405    fn backend_err_user_err() {
406        let error = BackendError::user_err("invalid input");
407        match error {
408            BackendError::UserErr { msg, .. } => assert_eq!(msg, "invalid input"),
409            e => panic!("Unexpected error: {e:?}"),
410        }
411    }
412
413    // conversions
414
415    #[test]
416    fn convert_from_fromutf8error() {
417        let error: BackendError = String::from_utf8(vec![0x80]).unwrap_err().into();
418        match error {
419            BackendError::InvalidUtf8 { .. } => {}
420            e => panic!("Unexpected error: {e:?}"),
421        }
422    }
423}