odra_core/
contract_env.rs1use crate::args::EntrypointArgument;
2use crate::call_def::CallDef;
3use crate::casper_types::bytesrepr::{deserialize_from_slice, Bytes, FromBytes, ToBytes};
4use crate::casper_types::crypto::PublicKey;
5use crate::casper_types::{CLTyped, CLValue, BLAKE2B_DIGEST_LENGTH, U512};
6use crate::module::Revertible;
7pub use crate::ContractContext;
8use crate::VmError::{Serialization, TypeMismatch};
9use crate::{consts, prelude::*, utils};
10use casper_event_standard::EventInstance;
11use casper_types::CLValueError;
12
13const INDEX_SIZE: usize = 4;
14const KEY_LEN: usize = 64;
15pub(crate) type StorageKey = [u8; KEY_LEN];
16
17pub trait ContractRef {
19 fn new(env: Rc<ContractEnv>, address: Address) -> Self;
21 fn address(&self) -> &Address;
23 fn with_tokens(&self, tokens: U512) -> Self;
28}
29
30#[derive(Clone)]
37pub struct ContractEnv {
38 index: u32,
39 mapping_data: Vec<u8>,
40 backend: Rc<RefCell<dyn ContractContext>>
41}
42
43impl Revertible for ContractEnv {
44 fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
45 self.revert(e)
46 }
47}
48
49impl ContractEnv {
50 pub const fn new(index: u32, backend: Rc<RefCell<dyn ContractContext>>) -> Self {
52 Self {
53 index,
54 mapping_data: Vec::new(),
55 backend
56 }
57 }
58
59 pub(crate) fn current_key(&self) -> StorageKey {
61 let mut result = [0u8; KEY_LEN];
62 let mut key = Vec::with_capacity(INDEX_SIZE + self.mapping_data.len());
63 key.extend_from_slice(self.index.to_be_bytes().as_ref());
64 key.extend_from_slice(&self.mapping_data);
65 let hashed_key = self.backend.borrow().hash(key.as_slice());
66 utils::hex_to_slice(&hashed_key, &mut result);
67 result
68 }
69
70 pub(crate) fn add_to_mapping_data(&mut self, data: &[u8]) {
72 self.mapping_data.extend_from_slice(data);
73 }
74
75 pub(crate) fn child(&self, index: u8) -> Self {
77 Self {
78 index: (self.index << 4) + index as u32,
79 mapping_data: self.mapping_data.clone(),
80 backend: self.backend.clone()
81 }
82 }
83
84 pub fn get_value<T: FromBytes>(&self, key: &[u8]) -> Option<T> {
90 self.backend
91 .borrow()
92 .get_value(key)
93 .map(|bytes| deserialize_from_slice(bytes).unwrap_or_revert(self))
94 }
95
96 pub fn set_value<T: ToBytes + CLTyped>(&self, key: &[u8], value: T) {
98 let result = value.to_bytes().map_err(ExecutionError::from);
99 let bytes = result.unwrap_or_revert(self);
100 self.backend.borrow().set_value(key, bytes.into());
101 }
102
103 pub fn get_named_value<T: FromBytes + CLTyped, U: AsRef<str>>(&self, name: U) -> Option<T> {
105 let key = name.as_ref();
106 let bytes = self.backend.borrow().get_named_value(key);
107 bytes.map(|b| deserialize_from_slice(b).unwrap_or_revert(self))
108 }
109
110 pub fn set_named_value<T: CLTyped + ToBytes, U: AsRef<str>>(&self, name: U, value: T) {
112 let key = name.as_ref();
113 let cl_value = CLValue::from_t(value)
114 .map_err(|e| match e {
115 CLValueError::Serialization(_) => OdraError::VmError(Serialization),
116 CLValueError::Type(e) => OdraError::VmError(TypeMismatch {
117 found: e.found,
118 expected: e.expected
119 })
120 })
121 .unwrap_or_revert(self);
122 self.backend.borrow().set_named_value(key, cl_value);
123 }
124
125 pub fn get_dictionary_value<T: FromBytes + CLTyped, U: AsRef<str>>(
127 &self,
128 dictionary_name: U,
129 key: &[u8]
130 ) -> Option<T> {
131 let dictionary_name = dictionary_name.as_ref();
132 let bytes = self
133 .backend
134 .borrow()
135 .get_dictionary_value(dictionary_name, key);
136 bytes.map(|b| {
137 deserialize_from_slice(b)
138 .map_err(|_| ExecutionError::Formatting)
139 .unwrap_or_revert(self)
140 })
141 }
142
143 pub fn set_dictionary_value<T: CLTyped + ToBytes, U: AsRef<str>>(
145 &self,
146 dictionary_name: U,
147 key: &[u8],
148 value: T
149 ) {
150 let dictionary_name = dictionary_name.as_ref();
151 let cl_value = CLValue::from_t(value)
152 .map_err(|_| ExecutionError::Formatting)
153 .unwrap_or_revert(self);
154 self.backend
155 .borrow()
156 .set_dictionary_value(dictionary_name, key, cl_value);
157 }
158
159 pub fn remove_dictionary<U: AsRef<str>>(&self, dictionary_name: U) {
161 let dictionary_name = dictionary_name.as_ref();
162 self.backend.borrow().remove_dictionary(dictionary_name);
163 }
164
165 pub fn caller(&self) -> Address {
167 let backend = self.backend.borrow();
168 backend.caller()
169 }
170
171 pub fn call_contract<T: FromBytes>(&self, address: Address, call: CallDef) -> T {
177 let backend = self.backend.borrow();
178 let bytes = backend.call_contract(address, call);
179 deserialize_from_slice(bytes).unwrap_or_revert(self)
180 }
181
182 pub fn self_address(&self) -> Address {
184 let backend = self.backend.borrow();
185 backend.self_address()
186 }
187
188 pub fn transfer_tokens(&self, to: &Address, amount: &U512) {
190 let backend = self.backend.borrow();
191 backend.transfer_tokens(to, amount)
192 }
193
194 pub fn get_block_time(&self) -> u64 {
196 let backend = self.backend.borrow();
197 backend.get_block_time()
198 }
199
200 pub fn get_block_time_millis(&self) -> u64 {
202 let backend = self.backend.borrow();
203 backend.get_block_time()
204 }
205
206 pub fn get_block_time_secs(&self) -> u64 {
208 let backend = self.backend.borrow();
209 backend.get_block_time().checked_div(1000).unwrap()
210 }
211
212 pub fn attached_value(&self) -> U512 {
214 let backend = self.backend.borrow();
215 backend.attached_value()
216 }
217
218 pub fn self_balance(&self) -> U512 {
220 let backend = self.backend.borrow();
221 backend.self_balance()
222 }
223
224 pub fn revert<E: Into<OdraError>>(&self, error: E) -> ! {
226 let backend = self.backend.borrow();
227 backend.revert(error.into())
228 }
229
230 pub fn emit_event<T: ToBytes + EventInstance>(&self, event: T) {
232 let backend = self.backend.borrow();
233 let result = event.to_bytes().map_err(ExecutionError::from);
234 let bytes = result.unwrap_or_revert(self);
235 backend.emit_event(&bytes.into())
236 }
237
238 pub fn emit_native_event<T: ToBytes + EventInstance>(&self, event: T) {
240 let backend = self.backend.borrow();
241 let result = event.to_bytes().map_err(ExecutionError::from);
242 let bytes = result.unwrap_or_revert(self);
243 backend.emit_native_event(&bytes.into())
244 }
245
246 pub fn verify_signature(
258 &self,
259 message: &Bytes,
260 signature: &Bytes,
261 public_key: &PublicKey
262 ) -> bool {
263 let (signature, _) = casper_types::crypto::Signature::from_bytes(signature.as_slice())
264 .unwrap_or_else(|_| self.revert(ExecutionError::CouldNotDeserializeSignature));
265 casper_types::crypto::verify(message.as_slice(), &signature, public_key).is_ok()
266 }
267
268 pub fn hash<T: AsRef<[u8]>>(&self, value: T) -> [u8; BLAKE2B_DIGEST_LENGTH] {
274 self.backend.borrow().hash(value.as_ref())
275 }
276
277 pub fn delegate(&self, validator: PublicKey, amount: U512) {
284 self.backend.borrow().delegate(validator, amount)
285 }
286
287 pub fn undelegate(&self, validator: PublicKey, amount: U512) {
294 self.backend.borrow().undelegate(validator, amount)
295 }
296
297 pub fn delegated_amount(&self, validator: PublicKey) -> U512 {
307 self.backend.borrow().delegated_amount(validator)
308 }
309
310 pub fn pseudorandom_bytes(&self, size: usize) -> Vec<u8> {
313 self.backend.borrow().pseudorandom_bytes(size)
314 }
315}
316
317pub struct ExecutionEnv {
322 env: Rc<ContractEnv>
323}
324
325impl Revertible for ExecutionEnv {
326 fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
327 self.env.revert(e)
328 }
329}
330
331impl ExecutionEnv {
332 pub fn new(env: Rc<ContractEnv>) -> Self {
334 Self { env }
335 }
336
337 pub fn non_reentrant_before(&self) {
339 let status: bool = self
341 .env
342 .get_value(consts::REENTRANCY_GUARD.as_slice())
343 .unwrap_or_default();
344 if status {
345 self.env.revert(ExecutionError::ReentrantCall);
347 }
348 self.env
350 .set_value(consts::REENTRANCY_GUARD.as_slice(), true);
351 }
352
353 pub fn non_reentrant_after(&self) {
355 self.env
357 .set_value(consts::REENTRANCY_GUARD.as_slice(), false);
358 }
359
360 pub fn handle_attached_value(&self) {
362 self.env.backend.borrow().handle_attached_value();
363 }
364
365 pub fn clear_attached_value(&self) {
367 self.env.backend.borrow().clear_attached_value();
368 }
369
370 pub fn get_named_arg<T: FromBytes + EntrypointArgument>(&self, name: &str) -> T {
377 if T::is_required() {
378 let result = self.env.backend.borrow().get_named_arg_bytes(name);
379 match result {
380 Ok(bytes) => deserialize_from_slice(bytes).unwrap_or_revert(self),
381 Err(err) => self.env.revert(err)
382 }
383 } else {
384 let bytes = self.env.backend.borrow().get_opt_named_arg_bytes(name);
385 let result = bytes.map(|bytes| deserialize_from_slice(bytes).unwrap_or_revert(self));
386 T::unwrap(result, &self.env)
387 }
388 }
389}