rock_n_rollup/core/
runtime.rs

1use std::{collections::HashMap, println};
2
3use super::constants::PREIMAGE_HASH_SIZE;
4
5pub const MAX_MESSAGE_SIZE: usize = 4096;
6
7#[derive(Clone)]
8pub struct RawInput {
9    pub level: u32,
10    pub id: u32,
11    pub payload: Vec<u8>,
12}
13
14#[repr(C)]
15pub struct ReadInputMessageInfo {
16    pub level: i32,
17    pub id: i32,
18}
19
20#[link(wasm_import_module = "smart_rollup_core")]
21extern "C" {
22    /// Does nothing. Does not check the correctness of its argument.
23    pub fn write_debug(src: *const u8, num_bytes: usize);
24
25    pub fn read_input(
26        message_info: *mut ReadInputMessageInfo,
27        dst: *mut u8,
28        max_bytes: usize,
29    ) -> i32;
30
31    /// Returns
32    /// - 0 the key is missing
33    /// - 1 only a file is stored under the path
34    /// - 2 only directories under the path
35    /// - 3 both a file and directories
36    pub fn store_has(path: *const u8, path_len: usize) -> i32;
37
38    /// Returns 0 in case of success, or an error code
39    pub fn store_delete(path: *const u8, path_len: usize) -> i32;
40
41    /// Returns the number of bytes written to the durable storage
42    /// (should be equal to `num_bytes`, or an error code.
43    pub fn store_read(
44        path: *const u8,
45        path_len: usize,
46        offset: usize,
47        dst: *mut u8,
48        num_bytes: usize,
49    ) -> i32;
50
51    /// Returns 0 in case of success, or an error code.
52    pub fn store_write(
53        path: *const u8,
54        path_len: usize,
55        offset: usize,
56        src: *const u8,
57        num_bytes: usize,
58    ) -> i32;
59
60    /// Returns the number of bytes written at `dst`, or an error code.
61    pub fn reveal_preimage(
62        hash_addr: *const u8,
63        hash_size: u8,
64        dst: *mut u8,
65        max_bytes: usize,
66    ) -> i32;
67
68    /// Returns 0 in case of success, or an error code.
69    pub fn store_move(
70        src_path: *const u8,
71        scr_path_len: usize,
72        dst_path: *const u8,
73        dst_path_len: usize,
74    ) -> i32;
75}
76
77pub trait Runtime: 'static {
78    /// Print a message in the rollup stdout (if activated)
79    fn write_debug(&mut self, msg: &str);
80
81    /// Read one input
82    fn next_input(&mut self) -> Option<RawInput>;
83
84    /// Returns true if something is present under the following path
85    fn store_is_present(&mut self, path: &str) -> bool;
86
87    /// Deletes the path at the following location
88    fn store_delete(&mut self, path: &str) -> Result<(), ()>;
89
90    /// Read some data at a given path
91    fn store_read(&mut self, path: &str, offset: usize, size: usize) -> Option<Vec<u8>>;
92
93    /// Write some data at a given path
94    ///
95    /// TODO: this function should always be used
96    /// The function stored_write and store_read should be removed and put in the Database plugin
97    fn store_write(&mut self, path: &str, data: &[u8], at_offset: usize) -> Result<(), ()>;
98
99    /// Reveal date from the reveal data directory
100    fn reveal_preimage(&mut self, hash: &[u8; PREIMAGE_HASH_SIZE]) -> Result<Vec<u8>, ()>;
101
102    /// Move the data to another path
103    fn store_move(&mut self, from: &str, to: &str) -> Result<(), ()>;
104}
105
106#[derive(Default)]
107pub struct KernelRuntime {}
108
109impl Runtime for KernelRuntime {
110    fn write_debug(&mut self, msg: &str) {
111        unsafe {
112            write_debug(msg.as_ptr(), msg.len());
113        }
114    }
115
116    fn next_input(&mut self) -> Option<RawInput> {
117        let mut payload = Vec::with_capacity(MAX_MESSAGE_SIZE as usize);
118
119        // Placeholder values
120        let mut message_info = ReadInputMessageInfo { level: 0, id: 0 };
121
122        let size = unsafe { read_input(&mut message_info, payload.as_mut_ptr(), MAX_MESSAGE_SIZE) };
123
124        if size == 0 {
125            None
126        } else {
127            unsafe { payload.set_len(size as usize) };
128            Some(RawInput {
129                level: message_info.level as u32,
130                id: message_info.id as u32,
131                payload,
132            })
133        }
134    }
135
136    fn store_is_present(&mut self, path: &str) -> bool {
137        let ptr = path.as_ptr();
138        let res = unsafe { store_has(ptr, path.len()) };
139        match res {
140            0 => false, // No file
141            1 => true,  // Only file
142            2 => true,  // Only directory
143            3 => true,  // Directory + File
144            _ => false,
145        }
146    }
147
148    fn store_delete(&mut self, path: &str) -> Result<(), ()> {
149        let ptr = path.as_ptr();
150        let res = unsafe { store_delete(ptr, path.len()) };
151        match res {
152            0 => Ok(()),
153            _ => Err(()),
154        }
155    }
156
157    fn store_read(&mut self, path: &str, offset: usize, size: usize) -> Option<Vec<u8>> {
158        if !self.store_is_present(path) {
159            return None;
160        }
161
162        let ptr = path.as_ptr();
163        let path_len = path.len();
164        let mut buffer = Vec::with_capacity(size);
165        let dst = buffer.as_mut_ptr();
166        unsafe {
167            let _ = store_read(ptr, path_len, offset, dst, size);
168            buffer.set_len(size);
169        }
170
171        Some(buffer)
172    }
173
174    fn store_write(&mut self, path: &str, data: &[u8], at_offset: usize) -> Result<(), ()> {
175        let res = unsafe {
176            let path_len = path.len();
177            let path = path.as_ptr();
178            let num_bytes = data.len();
179            let src = data.as_ptr();
180            store_write(path, path_len, at_offset, src, num_bytes)
181        };
182        match res {
183            0 => Ok(()),
184            err => {
185                self.write_debug(&format!("error store_write_raw: {}\n", err));
186                Err(())
187            }
188        }
189    }
190    fn reveal_preimage(&mut self, hash: &[u8; PREIMAGE_HASH_SIZE]) -> Result<Vec<u8>, ()> {
191        let max_size = 4096;
192        let mut payload = Vec::with_capacity(MAX_MESSAGE_SIZE as usize);
193
194        let u8_size = u8::try_from(PREIMAGE_HASH_SIZE).unwrap();
195
196        unsafe {
197            let size = reveal_preimage(hash.as_ptr(), u8_size, payload.as_mut_ptr(), max_size);
198            if size < 0 {
199                Err(())
200            } else {
201                let size = usize::try_from(size).unwrap();
202                payload.set_len(size);
203                Ok(payload)
204            }
205        }
206    }
207
208    fn store_move(&mut self, from: &str, to: &str) -> Result<(), ()> {
209        let res = unsafe { store_move(from.as_ptr(), from.len(), to.as_ptr(), to.len()) };
210        match res {
211            0 => Ok(()),
212            _ => Err(()),
213        }
214    }
215}
216
217pub struct MockRuntime {
218    stdout: Vec<String>,
219    inputs: Vec<RawInput>,
220    storage: HashMap<String, Vec<u8>>,
221}
222
223impl Default for MockRuntime {
224    fn default() -> Self {
225        Self {
226            stdout: Vec::default(),
227            inputs: Vec::default(),
228            storage: HashMap::default(),
229        }
230    }
231}
232
233impl MockRuntime {
234    pub fn stdout(&self) -> Vec<&str> {
235        self.stdout
236            .iter()
237            .map(|str| str.as_str())
238            .collect::<Vec<&str>>()
239    }
240
241    pub fn add_input(&mut self, input: Vec<u8>) -> &mut Self {
242        let level = 0;
243        let id = self.inputs.len();
244        let msg = RawInput {
245            level,
246            id: u32::try_from(id).unwrap(),
247            payload: input,
248        };
249        self.inputs.push(msg);
250        self
251    }
252}
253
254impl Runtime for MockRuntime {
255    fn write_debug(&mut self, msg: &str) {
256        self.stdout.push(msg.to_string());
257    }
258
259    fn next_input(&mut self) -> Option<RawInput> {
260        self.inputs.pop()
261    }
262
263    fn store_is_present(&mut self, _path: &str) -> bool {
264        todo!()
265    }
266
267    fn store_delete(&mut self, _path: &str) -> Result<(), ()> {
268        todo!()
269    }
270
271    fn store_read(&mut self, path: &str, offset: usize, size: usize) -> Option<Vec<u8>> {
272        let bytes = self.storage.get(path).cloned()?;
273        if offset + size <= bytes.len() {
274            let data = &bytes[offset..offset + size].to_vec();
275            Some(data.clone())
276        } else {
277            todo!()
278        }
279    }
280
281    fn store_write(&mut self, path: &str, data: &[u8], offset: usize) -> Result<(), ()> {
282        let buffer = self.storage.get(path).cloned();
283        match buffer {
284            None => {
285                self.storage.insert(path.to_string(), data.to_vec());
286                println!("there");
287                Ok(())
288            }
289            Some(mut buffer) => {
290                if offset == buffer.len() {
291                    println!("ici");
292                    let mut data = data.to_vec();
293                    buffer.append(&mut data);
294                    println!("{:?}", &buffer);
295                    self.storage.insert(path.to_string(), buffer.to_vec());
296                    Ok(())
297                } else {
298                    todo!()
299                }
300            }
301        }
302    }
303
304    fn reveal_preimage(&mut self, _hash: &[u8; PREIMAGE_HASH_SIZE]) -> Result<Vec<u8>, ()> {
305        todo!()
306    }
307
308    fn store_move(&mut self, _from: &str, _to: &str) -> Result<(), ()> {
309        todo!()
310    }
311}