odra_core/
contract_env.rs1use casper_event_standard::EventInstance;
2
3use crate::args::EntrypointArgument;
4use crate::call_def::CallDef;
5use crate::casper_types::bytesrepr::{deserialize_from_slice, Bytes, FromBytes, ToBytes};
6use crate::casper_types::crypto::PublicKey;
7use crate::casper_types::{CLTyped, CLValue, BLAKE2B_DIGEST_LENGTH, U512};
8use crate::module::Revertible;
9pub use crate::ContractContext;
10use crate::{consts, prelude::*, utils};
11
12const INDEX_SIZE: usize = 4;
13const KEY_LEN: usize = 64;
14pub(crate) type StorageKey = [u8; KEY_LEN];
15
16pub trait ContractRef {
18 fn new(env: Rc<ContractEnv>, address: Address) -> Self;
20 fn address(&self) -> &Address;
22}
23
24#[derive(Clone)]
31pub struct ContractEnv {
32 index: u32,
33 mapping_data: Vec<u8>,
34 backend: Rc<RefCell<dyn ContractContext>>
35}
36
37impl Revertible for ContractEnv {
38 fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
39 self.revert(e)
40 }
41}
42
43impl ContractEnv {
44 pub const fn new(index: u32, backend: Rc<RefCell<dyn ContractContext>>) -> Self {
46 Self {
47 index,
48 mapping_data: Vec::new(),
49 backend
50 }
51 }
52
53 pub(crate) fn current_key(&self) -> StorageKey {
55 let mut result = [0u8; KEY_LEN];
56 let mut key = Vec::with_capacity(INDEX_SIZE + self.mapping_data.len());
57 key.extend_from_slice(self.index.to_be_bytes().as_ref());
58 key.extend_from_slice(&self.mapping_data);
59 let hashed_key = self.backend.borrow().hash(key.as_slice());
60 utils::hex_to_slice(&hashed_key, &mut result);
61 result
62 }
63
64 pub(crate) fn add_to_mapping_data(&mut self, data: &[u8]) {
66 self.mapping_data.extend_from_slice(data);
67 }
68
69 pub(crate) fn child(&self, index: u8) -> Self {
71 Self {
72 index: (self.index << 4) + index as u32,
73 mapping_data: self.mapping_data.clone(),
74 backend: self.backend.clone()
75 }
76 }
77
78 pub fn get_value<T: FromBytes>(&self, key: &[u8]) -> Option<T> {
84 self.backend
85 .borrow()
86 .get_value(key)
87 .map(|bytes| deserialize_from_slice(bytes).unwrap_or_revert(self))
88 }
89
90 pub fn set_value<T: ToBytes + CLTyped>(&self, key: &[u8], value: T) {
92 let result = value.to_bytes().map_err(ExecutionError::from);
93 let bytes = result.unwrap_or_revert(self);
94 self.backend.borrow().set_value(key, bytes.into());
95 }
96
97 pub fn get_named_value<T: FromBytes + CLTyped, U: AsRef<str>>(&self, name: U) -> Option<T> {
99 let key = name.as_ref();
100 let bytes = self.backend.borrow().get_named_value(key);
101 bytes.map(|b| deserialize_from_slice(b).unwrap_or_revert(self))
102 }
103
104 pub fn set_named_value<T: CLTyped + ToBytes, U: AsRef<str>>(&self, name: U, value: T) {
106 let key = name.as_ref();
107 let cl_value = CLValue::from_t(value).unwrap_or_revert(self);
109 self.backend.borrow().set_named_value(key, cl_value);
110 }
111
112 pub fn get_dictionary_value<T: FromBytes + CLTyped, U: AsRef<str>>(
114 &self,
115 dictionary_name: U,
116 key: &[u8]
117 ) -> Option<T> {
118 let dictionary_name = dictionary_name.as_ref();
119 let bytes = self
120 .backend
121 .borrow()
122 .get_dictionary_value(dictionary_name, key);
123 bytes.map(|b| {
124 deserialize_from_slice(b)
125 .map_err(|_| ExecutionError::Formatting)
126 .unwrap_or_revert(self)
127 })
128 }
129
130 pub fn set_dictionary_value<T: CLTyped + ToBytes, U: AsRef<str>>(
132 &self,
133 dictionary_name: U,
134 key: &[u8],
135 value: T
136 ) {
137 let dictionary_name = dictionary_name.as_ref();
138 let cl_value = CLValue::from_t(value)
139 .map_err(|_| ExecutionError::Formatting)
140 .unwrap_or_revert(self);
141 self.backend
142 .borrow()
143 .set_dictionary_value(dictionary_name, key, cl_value);
144 }
145
146 pub fn remove_dictionary<U: AsRef<str>>(&self, dictionary_name: U) {
148 let dictionary_name = dictionary_name.as_ref();
149 self.backend.borrow().remove_dictionary(dictionary_name);
150 }
151
152 pub fn caller(&self) -> Address {
154 let backend = self.backend.borrow();
155 backend.caller()
156 }
157
158 pub fn call_contract<T: FromBytes>(&self, address: Address, call: CallDef) -> T {
164 let backend = self.backend.borrow();
165 let bytes = backend.call_contract(address, call);
166 deserialize_from_slice(bytes).unwrap_or_revert(self)
167 }
168
169 pub fn self_address(&self) -> Address {
171 let backend = self.backend.borrow();
172 backend.self_address()
173 }
174
175 pub fn transfer_tokens(&self, to: &Address, amount: &U512) {
177 let backend = self.backend.borrow();
178 backend.transfer_tokens(to, amount)
179 }
180
181 pub fn get_block_time(&self) -> u64 {
183 let backend = self.backend.borrow();
184 backend.get_block_time()
185 }
186
187 pub fn attached_value(&self) -> U512 {
189 let backend = self.backend.borrow();
190 backend.attached_value()
191 }
192
193 pub fn self_balance(&self) -> U512 {
195 let backend = self.backend.borrow();
196 backend.self_balance()
197 }
198
199 pub fn revert<E: Into<OdraError>>(&self, error: E) -> ! {
201 let backend = self.backend.borrow();
202 backend.revert(error.into())
203 }
204
205 pub fn emit_event<T: ToBytes + EventInstance>(&self, event: T) {
207 let backend = self.backend.borrow();
208 let result = event.to_bytes().map_err(ExecutionError::from);
209 let bytes = result.unwrap_or_revert(self);
210 backend.emit_event(&bytes.into())
211 }
212
213 pub fn verify_signature(
225 &self,
226 message: &Bytes,
227 signature: &Bytes,
228 public_key: &PublicKey
229 ) -> bool {
230 let (signature, _) = casper_types::crypto::Signature::from_bytes(signature.as_slice())
231 .unwrap_or_else(|_| self.revert(ExecutionError::CouldNotDeserializeSignature));
232 casper_types::crypto::verify(message.as_slice(), &signature, public_key).is_ok()
233 }
234
235 pub fn hash<T: AsRef<[u8]>>(&self, value: T) -> [u8; BLAKE2B_DIGEST_LENGTH] {
241 self.backend.borrow().hash(value.as_ref())
242 }
243}
244
245pub struct ExecutionEnv {
250 env: Rc<ContractEnv>
251}
252
253impl Revertible for ExecutionEnv {
254 fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
255 self.env.revert(e)
256 }
257}
258
259impl ExecutionEnv {
260 pub fn new(env: Rc<ContractEnv>) -> Self {
262 Self { env }
263 }
264
265 pub fn non_reentrant_before(&self) {
267 let status: bool = self
269 .env
270 .get_value(consts::REENTRANCY_GUARD.as_slice())
271 .unwrap_or_default();
272 if status {
273 self.env.revert(ExecutionError::ReentrantCall);
275 }
276 self.env
278 .set_value(consts::REENTRANCY_GUARD.as_slice(), true);
279 }
280
281 pub fn non_reentrant_after(&self) {
283 self.env
285 .set_value(consts::REENTRANCY_GUARD.as_slice(), false);
286 }
287
288 pub fn handle_attached_value(&self) {
290 self.env.backend.borrow().handle_attached_value();
291 }
292
293 pub fn clear_attached_value(&self) {
295 self.env.backend.borrow().clear_attached_value();
296 }
297
298 pub fn get_named_arg<T: FromBytes + EntrypointArgument>(&self, name: &str) -> T {
305 if T::is_required() {
306 let result = self.env.backend.borrow().get_named_arg_bytes(name);
307 match result {
308 Ok(bytes) => deserialize_from_slice(bytes).unwrap_or_revert(self),
309 Err(err) => self.env.revert(err)
310 }
311 } else {
312 let bytes = self.env.backend.borrow().get_opt_named_arg_bytes(name);
313 let result = bytes.map(|bytes| deserialize_from_slice(bytes).unwrap_or_revert(self));
314 T::unwrap(result, &self.env)
315 }
316 }
317}