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#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18pub struct GasInfo {
19 pub cost: u64,
24 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 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
77pub struct Backend<A: BackendApi, S: Storage, Q: Querier> {
82 pub api: A,
83 pub storage: S,
84 pub querier: Q,
85}
86
87pub trait Storage {
89 fn get(&self, key: &[u8]) -> BackendResult<Option<Vec<u8>>>;
96
97 #[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 #[cfg(feature = "iterator")]
123 fn next(&mut self, iterator_id: u32) -> BackendResult<Option<Record>>;
124
125 #[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 #[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 fn remove(&mut self, key: &[u8]) -> BackendResult<()>;
160}
161
162pub 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 fn query_raw(
187 &self,
188 request: &[u8],
189 gas_limit: u64,
190 ) -> BackendResult<SystemResult<ContractResult<Binary>>>;
191}
192
193pub type BackendResult<T> = (core::result::Result<T, BackendError>, GasInfo);
197
198macro_rules! unwrap_or_return_with_gas {
206 ($result: expr $(,)?, $gas_total: expr $(,)?) => {{
207 let result: core::result::Result<_, _> = $result; let gas: GasInfo = $gas_total; 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 #[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 #[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 #[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}