calimero_runtime/logic/host_functions/
utility.rs1use borsh::from_slice as from_borsh_slice;
2use rand::RngCore;
3use std::time::{SystemTime, UNIX_EPOCH};
4
5use crate::{
6 errors::HostError,
7 logic::{sys, VMHostFunctions, VMLogicResult},
8};
9
10impl VMHostFunctions<'_> {
11 pub fn fetch(
38 &mut self,
39 src_url_ptr: u64,
40 src_method_ptr: u64,
41 src_headers_ptr: u64,
42 src_body_ptr: u64,
43 dest_register_id: u64,
44 ) -> VMLogicResult<u32> {
45 let url = unsafe { self.read_guest_memory_typed::<sys::Buffer<'_>>(src_url_ptr)? };
46 let method = unsafe { self.read_guest_memory_typed::<sys::Buffer<'_>>(src_method_ptr)? };
47 let headers = unsafe { self.read_guest_memory_typed::<sys::Buffer<'_>>(src_headers_ptr)? };
48 let body = unsafe { self.read_guest_memory_typed::<sys::Buffer<'_>>(src_body_ptr)? };
49
50 let url = self.read_guest_memory_str(&url)?;
51 let method = self.read_guest_memory_str(&method)?;
52
53 let headers = self.read_guest_memory_slice(&headers);
54 let body = self.read_guest_memory_slice(&body);
55
56 let headers: Vec<(String, String)> =
61 from_borsh_slice(headers).map_err(|_| HostError::DeserializationError)?;
62
63 let mut request = ureq::request(&method, &url);
64
65 for (key, value) in &headers {
66 request = request.set(key, value);
67 }
68
69 let response = if body.is_empty() {
70 request.call()
71 } else {
72 request.send_bytes(body)
73 };
74
75 let (status, data) = match response {
76 Ok(response) => {
77 let mut buffer = vec![];
78 match response.into_reader().read_to_end(&mut buffer) {
79 Ok(_) => (0, buffer),
80 Err(_) => (1, "Failed to read the response body.".into()),
81 }
82 }
83 Err(e) => (1, e.to_string().into_bytes()),
84 };
85
86 self.with_logic_mut(|logic| logic.registers.set(logic.limits, dest_register_id, data))?;
87 Ok(status)
88 }
89
90 pub fn random_bytes(&mut self, dest_ptr: u64) -> VMLogicResult<()> {
100 let dest_buf = unsafe { self.read_guest_memory_typed::<sys::BufferMut<'_>>(dest_ptr)? };
101
102 rand::thread_rng().fill_bytes(self.read_guest_memory_slice_mut(&dest_buf));
103
104 Ok(())
105 }
106
107 #[expect(
125 clippy::cast_possible_truncation,
126 reason = "Impossible to overflow in normal circumstances"
127 )]
128 #[expect(
129 clippy::expect_used,
130 clippy::unwrap_in_result,
131 reason = "Effectively infallible here"
132 )]
133 pub fn time_now(&mut self, dest_ptr: u64) -> VMLogicResult<()> {
134 let guest_time_ptr =
135 unsafe { self.read_guest_memory_typed::<sys::BufferMut<'_>>(dest_ptr)? };
136
137 if guest_time_ptr.len() != 8 {
138 return Err(HostError::InvalidMemoryAccess.into());
139 }
140
141 let now = SystemTime::now()
142 .duration_since(UNIX_EPOCH)
143 .expect("Time went backwards to before the Unix epoch!")
144 .as_nanos() as u64;
145
146 let guest_time_out_buf: &mut [u8] = self.read_guest_memory_slice_mut(&guest_time_ptr);
148 guest_time_out_buf.copy_from_slice(&now.to_le_bytes());
149
150 Ok(())
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 use crate::logic::{
159 tests::{prepare_guest_buf_descriptor, setup_vm, SimpleMockStorage},
160 Cow, VMContext, VMLimits, VMLogic, DIGEST_SIZE,
161 };
162 use wasmer::{AsStoreMut, Store};
163
164 #[test]
165 fn test_random_bytes() {
166 let mut storage = SimpleMockStorage::new();
167 let limits = VMLimits::default();
168 let (mut logic, mut store) = setup_vm!(&mut storage, &limits, vec![]);
169 let mut host = logic.host_functions(store.as_store_mut());
170
171 let buf_ptr = 10u64;
172 let data_ptr = 200u64;
173 let data_len = 32u64;
174
175 let initial_pattern = vec![0xAB; data_len as usize];
179 host.borrow_memory()
180 .write(data_ptr, &initial_pattern)
181 .unwrap();
182
183 prepare_guest_buf_descriptor(&host, buf_ptr, data_ptr, data_len);
185
186 host.random_bytes(buf_ptr).unwrap();
188
189 let mut random_data = vec![0u8; data_len as usize];
192 host.borrow_memory()
193 .read(data_ptr, &mut random_data)
194 .unwrap();
195
196 assert_ne!(
198 random_data, initial_pattern,
199 "The data buffer should have been overwritten with random bytes, but it was not."
200 );
201 }
202
203 #[test]
205 fn test_time_now() {
206 let mut storage = SimpleMockStorage::new();
207 let limits = VMLimits::default();
208 let (mut logic, mut store) = setup_vm!(&mut storage, &limits, vec![]);
209 let mut host = logic.host_functions(store.as_store_mut());
210
211 let buf_ptr = 16u64;
212 let time_data_ptr = 200u64;
213 let time_data_len = u64::BITS as u64 / 8;
215 prepare_guest_buf_descriptor(&host, buf_ptr, time_data_ptr, time_data_len);
217
218 let time_before = SystemTime::now()
220 .duration_since(UNIX_EPOCH)
221 .unwrap()
222 .as_nanos() as u64;
223
224 host.time_now(buf_ptr).unwrap();
226
227 let time_after = SystemTime::now()
229 .duration_since(UNIX_EPOCH)
230 .unwrap()
231 .as_nanos() as u64;
232
233 let mut time_buffer = [0u8; 8];
235 host.borrow_memory()
236 .read(time_data_ptr, &mut time_buffer)
237 .unwrap();
238 let timestamp_from_host = u64::from_le_bytes(time_buffer);
239
240 assert!(timestamp_from_host >= time_before);
242 assert!(timestamp_from_host <= time_after);
243 }
244}