fvm_mock/
mock_runtime.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::Rc;
4use sha3::Digest;
5use fvm_std::prelude::{Vec, Address, H256};
6use fvm_std::types::LogLevel;
7
8
9/// Mock of contract execution runtime
10#[derive(Default)]
11pub struct Runtime {
12    pub inner: Rc<RefCell<RuntimeInner>>,
13}
14
15#[derive(Default)]
16pub struct RuntimeInner {
17    pub storage: HashMap<Vec<u8>, Vec<u8>>,
18    pub block_time: u64,
19    pub block_height: u64,
20    pub caller_addr: Address,
21    pub origin_addr: Address,
22    pub self_addr: Address,
23    pub block_hash: H256,
24    pub tx_hash: H256,
25    pub log: Vec<Vec<u8>>,
26    pub call_return: Vec<Vec<u8>>,
27    pub debug: HashMap<u32, Vec<Vec<u8>>>,
28    pub input: Vec<u8>,
29    pub ret: Vec<u8>,
30    pub hyper_counter: HashMap<Vec<u8>, i64>,
31    pub hyper_list: HashMap<Vec<u8>, Vec<i64>>,
32}
33
34impl RuntimeInner {
35    fn call_contract(&mut self) -> u32 {
36        self.call_return.last().expect("cross call set is not enough.").len() as u32
37    }
38}
39
40impl Runtime {
41    fn storage_write(&self, key: &[u8], prefix: &[u8], val: &[u8]) {
42        let mut p = prefix.to_vec();
43        let mut s = key.to_vec();
44        p.append(&mut s);
45        self.inner.borrow_mut().storage.insert(p, val.to_vec());
46    }
47
48    fn storage_read(&self, key: &[u8], prefix: &[u8]) -> Option<Vec<u8>> {
49        let mut p = prefix.to_vec();
50        let mut s = key.to_vec();
51        p.append(&mut s);
52        self.inner.borrow().storage.get(&p).map(|val| val.to_vec())
53    }
54
55    fn storage_delete(&self, key: &[u8], prefix: &[u8]) {
56        let mut p = prefix.to_vec();
57        let mut s = key.to_vec();
58        p.append(&mut s);
59        self.inner.borrow_mut().storage.remove(&p);
60    }
61
62    fn block_time(&self) -> u64 {
63        self.inner.borrow().block_time
64    }
65
66    fn block_height(&self) -> u64 {
67        self.inner.borrow().block_height
68    }
69
70    fn self_address(&self) -> Address {
71        self.inner.borrow().self_addr.clone()
72    }
73
74    fn caller_address(&self) -> Address {
75        self.inner.borrow().caller_addr.clone()
76    }
77
78    fn origin_address(&self) -> Address {
79        self.inner.borrow().origin_addr.clone()
80    }
81
82    fn tx_hash(&self) -> H256 {
83        self.inner.borrow().tx_hash.clone()
84    }
85
86    fn event(&self, msg: &[u8]) {
87        self.inner.borrow_mut().log.push(msg.to_vec());
88    }
89
90    fn sha256(&self, data: &[u8]) -> H256 {
91        let mut hasher = sha3::Keccak256::new();
92        hasher.update(data);
93        let hash = hasher.finalize();
94        H256::from_slice(hash.as_slice())
95    }
96
97    fn call_contract(&self, _: &Address, _: &[u8]) -> u32 {
98        self.inner.borrow_mut().call_contract()
99    }
100
101    fn cns_call_contract(&self, _: &[u8], _: &[u8]) -> u32 {
102        self.inner.borrow_mut().call_contract()
103    }
104
105    fn call_return(&self) -> Vec<u8> {
106        self.inner.borrow_mut().call_return.pop().expect("cross call set is not enough.")
107    }
108
109    fn ret(&self, _data: &[u8]) {
110        self.inner.borrow_mut().ret = _data.to_vec()
111    }
112
113    fn debug(&self, class_name: &[u8], data: &[u8], level: LogLevel) {
114        let mut c = String::from("[");
115        c.push_str(String::from_utf8(class_name.to_vec()).unwrap().as_str());
116        c.push_str("]: ");
117        c.push_str(String::from_utf8(data.to_vec()).unwrap().as_str());
118        if self.inner.borrow_mut().debug.contains_key(&level.to_int()) {
119            self.inner.borrow_mut().debug.get_mut(&level.to_int()).unwrap().push(c.into_bytes());
120        } else {
121            let mut temp = Vec::new();
122            temp.push(c.into_bytes());
123            self.inner.borrow_mut().debug.entry(level.to_int()).or_insert(temp);
124        }
125    }
126
127    pub fn revert(&self, _msg: &str) -> ! {
128        panic!("{}", _msg)
129    }
130
131    pub fn input(&self) -> Vec<u8> {
132        self.inner.borrow_mut().input.to_vec()
133    }
134
135    pub fn input_length(&self) -> u32 {
136        self.inner.borrow().input.len() as u32
137    }
138
139    pub fn add_list_key(&self, list_name: &[u8], index: u32) -> Option<i64> {
140        let list_name = list_name.to_vec();
141        // get inner
142        let inner = &mut self.inner.borrow_mut();
143        // get key
144        let key =
145            match inner.hyper_counter.get(&list_name) {
146                None => {
147                    inner.hyper_counter.insert(list_name.clone(), 0);
148                    0
149                }
150                Some(v) => v.clone()
151            };
152
153        // add key
154        match inner.hyper_list.get_mut(&list_name) {
155            None => {
156                if index == 0 {
157                    let mut new_vec = Vec::<i64>::new();
158                    new_vec.insert(index as usize, key);
159                    inner.hyper_list.insert(list_name.clone(), new_vec);
160                } else {
161                    panic!("invalid index when add");
162                }
163                inner.hyper_counter.insert(list_name, key + 1);
164                Some(key)
165            }
166            Some(v) => {
167                // check index
168                if index as usize > v.len() {
169                    return None;
170                }
171                // add key
172                v.insert(index as usize, key);
173                // update counter
174                inner.hyper_counter.insert(list_name, key + 1);
175                Some(key)
176            }
177        }
178    }
179
180    pub fn get_list_key(&self, list_name: &[u8], index: u32) -> Option<i64> {
181        let list_name = list_name.to_vec();
182        // get &mut list
183        let hyper_list = &self.inner.borrow().hyper_list;
184        let list = match hyper_list.get(&list_name) {
185            None => {
186                panic!("no list according to list_name when try to get key");
187            }
188            Some(v) => v
189        };
190        // check index
191        if index as usize >= list.len() {
192            None
193        } else {
194            Some(list[index as usize])
195        }
196    }
197
198    pub fn remove_list_key(&self, list_name: &[u8], index: u32) -> Option<i64> {
199        let list_name = list_name.to_vec();
200        // get &mut list
201        let hyper_list = &mut self.inner.borrow_mut().hyper_list;
202        let list = match hyper_list.get_mut(&list_name) {
203            None => {
204                panic!("no list according to list_name when try to remove key");
205            }
206            Some(v) => v
207        };
208        // check index
209        if index as usize >= list.len() {
210            None
211        } else {
212            Some(list.remove(index as usize))
213        }
214    }
215
216    pub fn write_list_keys_back(&mut self, old_list_name: &[u8], list_name: &[u8], size: u32) {
217        let old_list_name = old_list_name.to_vec();
218        let new_list_name = list_name.to_vec();
219        let list_name = if old_list_name.len() > 0 {
220            old_list_name.clone()
221        } else {
222            new_list_name.clone()
223        };
224        // check size
225        let inner = &mut self.inner.borrow_mut();
226        let is_contain = inner.hyper_list.contains_key(&list_name);
227        match is_contain {
228            false => {
229                if size == 0 {
230                    // create this list
231                    inner.hyper_counter.insert(new_list_name.clone(), 0);
232                    let new_list = Vec::<i64>::new();
233                    inner.hyper_list.insert(new_list_name.clone(), new_list);
234                } else {
235                    // panic 
236                    panic!("size is not 0 but no list when writing keys back");
237                }
238            }
239            true => {
240                // replace
241                if old_list_name.len() > 0 {
242                    let counter = inner.hyper_counter.remove(&old_list_name).unwrap();
243                    let list = inner.hyper_list.remove(&old_list_name).unwrap();
244                    inner.hyper_counter.insert(new_list_name.clone(), counter);
245                    inner.hyper_list.insert(new_list_name.clone(), list);
246                }
247                let list = inner.hyper_list.get(&list_name).unwrap();
248                if list.len() != size as usize {
249                    panic!("size not equal when writing keys back");
250                }
251            }
252        };
253        inner.storage.insert(["@HyperList".as_bytes(), new_list_name.as_slice()].concat().to_vec(), vec![0; 28]);
254        // (&new_list_name, "@HyperList".as_bytes(), vec![0;28].as_slice());
255    }
256}
257
258thread_local!(static RUNTIME: RefCell<Runtime> = RefCell::new(Runtime::default()));
259
260pub fn setup_runtime(runtime: Runtime) {
261    RUNTIME.with(|r| *r.borrow_mut() = runtime);
262}
263
264mod env {
265    use super::*;
266    use std::cmp;
267    use std::ptr;
268    use std::slice;
269    use std::u32;
270    use fvm_std::types::Address;
271    use fvm_std::prelude::H256;
272
273    #[no_mangle]
274    pub unsafe extern "C" fn fvm_block_time() -> u64 {
275        RUNTIME.with(|r| r.borrow().block_time())
276    }
277
278    #[no_mangle]
279    pub unsafe extern "C" fn fvm_block_height() -> u64 {
280        RUNTIME.with(|r| r.borrow().block_height())
281    }
282
283    #[no_mangle]
284    pub unsafe extern "C" fn fvm_self_address(dest: *mut u8) {
285        RUNTIME.with(|r| {
286            let addr = r.borrow().self_address();
287            ptr::copy(addr.as_ptr(), dest, Address::len_bytes());
288        })
289    }
290
291    #[no_mangle]
292    pub unsafe extern "C" fn fvm_caller_address(dest: *mut u8) {
293        RUNTIME.with(|r| {
294            let caller = r.borrow().caller_address();
295            ptr::copy(caller.as_ptr(), dest, Address::len_bytes());
296        })
297    }
298
299    #[no_mangle]
300    pub unsafe extern "C" fn fvm_origin_address(dest: *mut u8) {
301        RUNTIME.with(|r| {
302            let origin = r.borrow().origin_address();
303            ptr::copy(origin.as_ptr(), dest, Address::len_bytes());
304        })
305    }
306
307
308    #[no_mangle]
309    pub unsafe extern "C" fn fvm_tx_hash(dest: *const u8) {
310        RUNTIME.with(|r| {
311            let tx_hash = r.borrow().tx_hash();
312            ptr::copy(tx_hash.as_ptr(), dest as *mut u8, H256::len_bytes());
313        })
314    }
315
316    #[no_mangle]
317    pub unsafe extern "C" fn fvm_storage_read(
318        key_ptr: *const u8, key_len: u32, prefix_ptr: *const u8, prefix_len: u32,
319        val: *mut u8, vlen: u32, offset: u32,
320    ) -> u32 {
321        let key = core::slice::from_raw_parts(key_ptr, key_len as usize);
322        let prefix = core::slice::from_raw_parts(prefix_ptr, prefix_len as usize);
323        let offset = offset as usize;
324
325        let v = RUNTIME.with(|r| r.borrow().storage_read(key, prefix));
326        match v {
327            None => 0,
328            Some(v) => {
329                ptr::copy(
330                    v.as_slice()[offset..].as_ptr(),
331                    val,
332                    cmp::min(vlen as usize, v.len() - offset),
333                );
334                v.len() as u32
335            }
336        }
337    }
338
339    #[no_mangle]
340    pub unsafe extern "C" fn fvm_storage_write(
341        key_ptr: *const u8, key_len: u32, prefix_ptr: *const u8, prefix_len: u32, val: *const u8, vlen: u32,
342    ) {
343        let key = core::slice::from_raw_parts(key_ptr, key_len as usize);
344        let prefix = core::slice::from_raw_parts(prefix_ptr, prefix_len as usize);
345        let val = core::slice::from_raw_parts(val, vlen as usize);
346        RUNTIME.with(|r| r.borrow().storage_write(key, prefix, val));
347    }
348
349    #[no_mangle]
350    pub unsafe extern "C" fn fvm_storage_delete(key_ptr: *const u8, key_len: u32, prefix_ptr: *const u8, prefix_len: u32) {
351        let key = core::slice::from_raw_parts(key_ptr, key_len as usize);
352        let prefix = core::slice::from_raw_parts(prefix_ptr, prefix_len as usize);
353        RUNTIME.with(|r| r.borrow().storage_delete(key, prefix));
354    }
355
356    #[no_mangle]
357    pub unsafe extern "C" fn fvm_log(ptr: *const u8, len: u32) {
358        let data = core::slice::from_raw_parts(ptr, len as usize);
359        RUNTIME.with(|r| r.borrow().event(data));
360    }
361
362    #[no_mangle]
363    pub unsafe extern "C" fn fvm_sha256(data_ptr: *const u8, len: u32, val: *mut u8) {
364        let data = core::slice::from_raw_parts(data_ptr, len as usize);
365        RUNTIME.with(|r| {
366            let mut hash = r.borrow_mut().sha256(data);
367            ptr::copy(hash.as_mut_ptr(), val, 32);
368        });
369    }
370
371    #[no_mangle]
372    pub unsafe extern "C" fn fvm_call_contract(
373        addr: *const u8, input_ptr: *const u8, input_len: u32,
374    ) -> u32 {
375        let input = core::slice::from_raw_parts(input_ptr, input_len as usize);
376        let addr = Address::from_slice(slice::from_raw_parts(addr, 20));
377        RUNTIME.with(|r| r.borrow().call_contract(&addr, input))
378    }
379
380    #[no_mangle]
381    pub unsafe extern "C" fn fvm_cns_call_contract(
382        cns: *const u8, cns_len: u32, input_ptr: *const u8, input_len: u32,
383    ) -> u32 {
384        let input = core::slice::from_raw_parts(input_ptr, input_len as usize);
385        let addr = core::slice::from_raw_parts(cns, cns_len as usize);
386        RUNTIME.with(|r| r.borrow().cns_call_contract(&addr, input))
387    }
388
389
390    #[no_mangle]
391    pub unsafe extern "C" fn fvm_revert(ptr: *const u8, len: u32) -> ! {
392        let temp = core::slice::from_raw_parts(ptr, len as usize);
393        RUNTIME.with(|r| r.borrow().revert(std::str::from_utf8(temp).unwrap()))
394    }
395
396    #[no_mangle]
397    pub unsafe extern "C" fn fvm_call_return(dst: *mut u8) {
398        let output = RUNTIME.with(|r| r.borrow().call_return());
399        std::ptr::copy(output.as_ptr(), dst, output.len());
400    }
401
402    #[no_mangle]
403    pub unsafe extern "C" fn fvm_input_length() -> u32 {
404        RUNTIME.with(|r| r.borrow().input_length())
405    }
406
407    #[no_mangle]
408    pub unsafe extern "C" fn fvm_fetch_input(_dst: *mut u8) {
409        let output = RUNTIME.with(|r| r.borrow().input());
410        ptr::copy(output.as_ptr(), _dst, output.len())
411    }
412
413    #[no_mangle]
414    pub unsafe extern "C" fn fvm_return(ptr: *const u8, len: u32) {
415        let ret = core::slice::from_raw_parts(ptr, len as usize);
416        RUNTIME.with(|r| r.borrow().ret(ret))
417    }
418
419    #[no_mangle]
420    pub unsafe fn fvm_debug(class_prt: *const u8, class_len: u32, ptr: *const u8, len: u32, level: u32) {
421        let class_name = core::slice::from_raw_parts(class_prt, class_len as usize);
422        let data = core::slice::from_raw_parts(ptr, len as usize);
423        let l = match level {
424            0 => LogLevel::CRITICAL,
425            1 => LogLevel::ERROR,
426            2 => LogLevel::WARNING,
427            3 => LogLevel::NOTICE,
428            4 => LogLevel::INFO,
429            5 => LogLevel::DEBUG,
430            _ => panic!("invalid log level type")
431        };
432        RUNTIME.with(|r| r.borrow_mut().debug(class_name, data, l))
433    }
434
435    #[no_mangle]
436    pub unsafe fn fvm_add_list_key(key_ptr: *const u8, key_len: u32, index: u32) -> i64 {
437        let list_name = core::slice::from_raw_parts(key_ptr, key_len as usize);
438        let v = RUNTIME.with(|r| r.borrow_mut().add_list_key(list_name, index));
439        match v {
440            None => {
441                -1
442            }
443            Some(v) => v
444        }
445    }
446
447    #[no_mangle]
448    pub unsafe fn fvm_get_list_key(key_ptr: *const u8, key_len: u32, index: u32) -> i64 {
449        let list_name = core::slice::from_raw_parts(key_ptr, key_len as usize);
450        let v = RUNTIME.with(|r| r.borrow().get_list_key(list_name, index));
451        match v {
452            None => -1,
453            Some(v) => v
454        }
455    }
456
457    #[no_mangle]
458    pub fn fvm_remove_list_key(key_ptr: *const u8, key_len: u32, index: u32) -> i64 {
459        unsafe {
460            let list_name = core::slice::from_raw_parts(key_ptr, key_len as usize);
461            let v = RUNTIME.with(|r| r.borrow().remove_list_key(list_name, index));
462            match v {
463                None => -1,
464                Some(v) => v
465            }
466        }
467    }
468
469    #[no_mangle]
470    pub fn fvm_write_list_keys(old_list_name_ptr: *const u8, old_list_name_len: u32, new_list_name_ptr: *const u8, new_list_name_len: u32, size: u32) {
471        unsafe {
472            let old_list_name = core::slice::from_raw_parts(old_list_name_ptr, old_list_name_len as usize);
473            let list_name = core::slice::from_raw_parts(new_list_name_ptr, new_list_name_len as usize);
474            RUNTIME.with(|r| r.borrow_mut().write_list_keys_back(old_list_name, list_name, size))
475        }
476    }
477}