1use std::io::Cursor;
20
21use darkfi_sdk::wasm;
22use darkfi_serial::Decodable;
23use log::{debug, error};
24use wasmer::{FunctionEnvMut, WasmPtr};
25
26use super::acl::acl_allow;
27use crate::runtime::vm_runtime::{ContractSection, Env};
28
29pub(crate) fn drk_log(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) {
31 let (env, mut store) = ctx.data_and_store_mut();
32
33 env.subtract_gas(&mut store, len as u64);
35
36 let memory_view = env.memory_view(&store);
37 match ptr.read_utf8_string(&memory_view, len) {
38 Ok(msg) => {
39 let mut logs = env.logs.borrow_mut();
40 logs.push(msg);
41 std::mem::drop(logs);
42 }
43 Err(_) => {
44 error!(
45 target: "runtime::util::drk_log",
46 "[WASM] [{}] drk_log(): Failed to read UTF-8 string from VM memory",
47 env.contract_id,
48 );
49 }
50 }
51}
52
53pub(crate) fn set_return_data(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i64 {
61 let (env, mut store) = ctx.data_and_store_mut();
62 let cid = &env.contract_id;
63
64 if let Err(e) = acl_allow(env, &[ContractSection::Metadata, ContractSection::Exec]) {
66 error!(
67 target: "runtime::util::set_return_data",
68 "[WASM] [{}] set_return_data(): Called in unauthorized section: {}", cid, e,
69 );
70 return darkfi_sdk::error::CALLER_ACCESS_DENIED
71 }
72
73 env.subtract_gas(&mut store, len as u64);
75
76 let memory_view = env.memory_view(&store);
77 let Ok(slice) = ptr.slice(&memory_view, len) else { return darkfi_sdk::error::INTERNAL_ERROR };
78 let Ok(return_data) = slice.read_to_vec() else { return darkfi_sdk::error::INTERNAL_ERROR };
79
80 if env.contract_return_data.take().is_some() {
82 return darkfi_sdk::error::SET_RETVAL_ERROR
83 }
84 env.contract_return_data.set(Some(return_data));
85
86 wasm::entrypoint::SUCCESS
87}
88
89pub(crate) fn get_object_bytes(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, idx: u32) -> i64 {
96 let (env, mut store) = ctx.data_and_store_mut();
98 let cid = env.contract_id;
99
100 if let Err(e) =
102 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
103 {
104 error!(
105 target: "runtime::util::get_object_bytes()",
106 "[WASM] [{}] get_object_bytes(): Called in unauthorized section: {}", cid, e,
107 );
108 return darkfi_sdk::error::CALLER_ACCESS_DENIED
109 }
110
111 let objects = env.objects.borrow();
113 if idx as usize >= objects.len() {
114 error!(
115 target: "runtime::util::get_object_bytes",
116 "[WASM] [{}] get_object_bytes(): Tried to access object out of bounds", cid,
117 );
118 return darkfi_sdk::error::DATA_TOO_LARGE
119 }
120 let obj = objects[idx as usize].clone();
121 drop(objects);
122
123 if obj.len() > u32::MAX as usize {
124 return darkfi_sdk::error::DATA_TOO_LARGE
125 }
126
127 env.subtract_gas(&mut store, obj.len() as u64);
129
130 let memory_view = env.memory_view(&store);
132 let Ok(slice) = ptr.slice(&memory_view, obj.len() as u32) else {
133 error!(
134 target: "runtime::util::get_object_bytes",
135 "[WASM] [{}] get_object_bytes(): Failed to make slice from ptr", cid,
136 );
137 return darkfi_sdk::error::INTERNAL_ERROR
138 };
139
140 if let Err(e) = slice.write_slice(&obj) {
142 error!(
143 target: "runtime::util::get_object_bytes",
144 "[WASM] [{}] get_object_bytes(): Failed to write to memory slice: {}", cid, e,
145 );
146 return darkfi_sdk::error::INTERNAL_ERROR
147 };
148
149 wasm::entrypoint::SUCCESS
150}
151
152pub(crate) fn get_object_size(mut ctx: FunctionEnvMut<Env>, idx: u32) -> i64 {
157 let (env, mut store) = ctx.data_and_store_mut();
159 let cid = env.contract_id;
160
161 if let Err(e) =
163 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
164 {
165 error!(
166 target: "runtime::util::get_object_size()",
167 "[WASM] [{}] get_object_size(): Called in unauthorized section: {}", cid, e,
168 );
169 return darkfi_sdk::error::CALLER_ACCESS_DENIED
170 }
171
172 let objects = env.objects.borrow();
174 if idx as usize >= objects.len() {
175 error!(
176 target: "runtime::util::get_object_size",
177 "[WASM] [{}] get_object_size(): Tried to access object out of bounds", cid,
178 );
179 return darkfi_sdk::error::DATA_TOO_LARGE
180 }
181
182 let obj = &objects[idx as usize];
183 let obj_len = obj.len();
184 drop(objects);
185
186 if obj_len > u32::MAX as usize {
187 return darkfi_sdk::error::DATA_TOO_LARGE
188 }
189
190 env.subtract_gas(&mut store, obj_len as u64);
193
194 obj_len as i64
195}
196
197pub(crate) fn get_verifying_block_height(mut ctx: FunctionEnvMut<Env>) -> i64 {
201 let (env, mut store) = ctx.data_and_store_mut();
202 let cid = env.contract_id;
203
204 if let Err(e) =
205 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
206 {
207 error!(
208 target: "runtime::util::get_verifying_block_height",
209 "[WASM] [{}] get_verifying_block_height(): Called in unauthorized section: {}", cid, e,
210 );
211 return darkfi_sdk::error::CALLER_ACCESS_DENIED
212 }
213
214 env.subtract_gas(&mut store, 4);
217
218 env.verifying_block_height as i64
219}
220
221pub(crate) fn get_block_target(mut ctx: FunctionEnvMut<Env>) -> i64 {
225 let (env, mut store) = ctx.data_and_store_mut();
226 let cid = env.contract_id;
227
228 if let Err(e) =
229 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
230 {
231 error!(
232 target: "runtime::util::get_block_target",
233 "[WASM] [{}] get_block_target(): Called in unauthorized section: {}", cid, e,
234 );
235 return darkfi_sdk::error::CALLER_ACCESS_DENIED
236 }
237
238 env.subtract_gas(&mut store, 4);
241
242 env.block_target as i64
243}
244
245pub(crate) fn get_tx_hash(mut ctx: FunctionEnvMut<Env>) -> i64 {
249 let (env, mut store) = ctx.data_and_store_mut();
250 let cid = env.contract_id;
251
252 if let Err(e) =
253 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
254 {
255 error!(
256 target: "runtime::util::get_tx_hash",
257 "[WASM] [{}] get_tx_hash(): Called in unauthorized section: {}", cid, e,
258 );
259 return darkfi_sdk::error::CALLER_ACCESS_DENIED
260 }
261
262 env.subtract_gas(&mut store, 32);
264
265 let mut objects = env.objects.borrow_mut();
268 objects.push(env.tx_hash.inner().to_vec());
269 (objects.len() - 1) as i64
270}
271
272pub(crate) fn get_call_index(mut ctx: FunctionEnvMut<Env>) -> i64 {
276 let (env, mut store) = ctx.data_and_store_mut();
277 let cid = env.contract_id;
278
279 if let Err(e) =
280 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
281 {
282 error!(
283 target: "runtime::util::get_call_index",
284 "[WASM] [{}] get_call_index(): Called in unauthorized section: {}", cid, e,
285 );
286 return darkfi_sdk::error::CALLER_ACCESS_DENIED
287 }
288
289 env.subtract_gas(&mut store, 1);
292
293 env.call_idx as i64
294}
295
296pub(crate) fn get_blockchain_time(mut ctx: FunctionEnvMut<Env>) -> i64 {
301 let (env, mut store) = ctx.data_and_store_mut();
302 let cid = &env.contract_id;
303
304 if let Err(e) =
305 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
306 {
307 error!(
308 target: "runtime::util::get_blockchain_time",
309 "[WASM] [{}] get_blockchain_time(): Called in unauthorized section: {}", cid, e,
310 );
311 return darkfi_sdk::error::CALLER_ACCESS_DENIED
312 }
313
314 let timestamp = match env.blockchain.lock().unwrap().last_block_timestamp() {
316 Ok(b) => b,
317 Err(e) => {
318 error!(
319 target: "runtime::util::get_blockchain_time",
320 "[WASM] [{}] get_blockchain_time(): Internal error getting from blocks tree: {}", cid, e,
321 );
322 return darkfi_sdk::error::DB_GET_FAILED
323 }
324 };
325
326 env.subtract_gas(&mut store, 8);
329
330 let mut ret = Vec::with_capacity(8);
332 ret.extend_from_slice(×tamp.inner().to_be_bytes());
333
334 let mut objects = env.objects.borrow_mut();
336 objects.push(ret.to_vec());
337 if objects.len() > u32::MAX as usize {
338 return darkfi_sdk::error::DATA_TOO_LARGE
339 }
340
341 (objects.len() - 1) as i64
342}
343
344pub(crate) fn get_last_block_height(mut ctx: FunctionEnvMut<Env>) -> i64 {
352 let (env, mut store) = ctx.data_and_store_mut();
353 let cid = &env.contract_id;
354
355 if let Err(e) =
357 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
358 {
359 error!(
360 target: "runtime::util::get_last_block_height",
361 "[WASM] [{}] get_last_block_height(): Called in unauthorized section: {}", cid, e,
362 );
363 return darkfi_sdk::error::CALLER_ACCESS_DENIED
364 }
365
366 let height = match env.blockchain.lock().unwrap().last_block_height() {
368 Ok(b) => b,
369 Err(e) => {
370 error!(
371 target: "runtime::util::get_last_block_height",
372 "[WASM] [{}] get_last_block_height(): Internal error getting from blocks tree: {}", cid, e,
373 );
374 return darkfi_sdk::error::DB_GET_FAILED
375 }
376 };
377
378 env.subtract_gas(&mut store, 8);
381
382 let mut ret = Vec::with_capacity(8);
384 ret.extend_from_slice(&darkfi_serial::serialize(&height));
385
386 let mut objects = env.objects.borrow_mut();
388 objects.push(ret.to_vec());
389 if objects.len() > u32::MAX as usize {
390 return darkfi_sdk::error::DATA_TOO_LARGE
391 }
392
393 (objects.len() - 1) as i64
394}
395
396pub(crate) fn get_tx(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>) -> i64 {
405 let (env, mut store) = ctx.data_and_store_mut();
406 let cid = env.contract_id;
407
408 if let Err(e) =
409 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
410 {
411 error!(
412 target: "runtime::util::get_tx",
413 "[WASM] [{}] get_tx(): Called in unauthorized section: {}", cid, e,
414 );
415 return darkfi_sdk::error::CALLER_ACCESS_DENIED
416 }
417
418 env.subtract_gas(&mut store, blake3::OUT_LEN as u64);
420
421 let memory_view = env.memory_view(&store);
423 let Ok(mem_slice) = ptr.slice(&memory_view, blake3::OUT_LEN as u32) else {
424 error!(
425 target: "runtime::util::get_tx",
426 "[WASM] [{}] get_tx(): Failed to make slice from ptr", cid,
427 );
428 return darkfi_sdk::error::DB_GET_FAILED
429 };
430
431 let mut buf = vec![0_u8; blake3::OUT_LEN];
432 if let Err(e) = mem_slice.read_slice(&mut buf) {
433 error!(
434 target: "runtime::util::get_tx",
435 "[WASM] [{}] get_tx(): Failed to read from memory slice: {}", cid, e,
436 );
437 return darkfi_sdk::error::DB_GET_FAILED
438 };
439
440 let mut buf_reader = Cursor::new(buf);
441
442 let hash: [u8; blake3::OUT_LEN] = match Decodable::decode(&mut buf_reader) {
444 Ok(v) => v,
445 Err(e) => {
446 error!(
447 target: "runtime::util::get_tx",
448 "[WASM] [{}] get_tx(): Failed to decode hash from vec: {}", cid, e,
449 );
450 return darkfi_sdk::error::DB_GET_FAILED
451 }
452 };
453
454 if buf_reader.position() != blake3::OUT_LEN as u64 {
457 error!(
458 target: "runtime::util::get_tx",
459 "[WASM] [{}] get_tx(): Trailing bytes in argument stream", cid,
460 );
461 return darkfi_sdk::error::DB_GET_FAILED
462 }
463
464 let ret = match env.blockchain.lock().unwrap().transactions.get_raw(&hash) {
466 Ok(v) => v,
467 Err(e) => {
468 error!(
469 target: "runtime::util::get_tx",
470 "[WASM] [{}] get_tx(): Internal error getting from tree: {}", cid, e,
471 );
472 return darkfi_sdk::error::DB_GET_FAILED
473 }
474 };
475
476 let Some(return_data) = ret else {
478 debug!(
479 target: "runtime::util::get_tx",
480 "[WASM] [{}] get_tx(): Return data is empty", cid,
481 );
482 return darkfi_sdk::error::DB_GET_EMPTY
483 };
484
485 if return_data.len() > u32::MAX as usize {
486 return darkfi_sdk::error::DATA_TOO_LARGE
487 }
488
489 env.subtract_gas(&mut store, return_data.len() as u64);
491
492 let mut objects = env.objects.borrow_mut();
494 if objects.len() == u32::MAX as usize {
495 return darkfi_sdk::error::DATA_TOO_LARGE
496 }
497
498 objects.push(return_data.to_vec());
501 (objects.len() - 1) as i64
502}
503
504pub(crate) fn get_tx_location(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>) -> i64 {
513 let (env, mut store) = ctx.data_and_store_mut();
514 let cid = env.contract_id;
515
516 if let Err(e) =
517 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
518 {
519 error!(
520 target: "runtime::util::get_tx_location",
521 "[WASM] [{}] get_tx_location(): Called in unauthorized section: {}", cid, e,
522 );
523 return darkfi_sdk::error::CALLER_ACCESS_DENIED
524 }
525
526 env.subtract_gas(&mut store, blake3::OUT_LEN as u64);
528
529 let memory_view = env.memory_view(&store);
531 let Ok(mem_slice) = ptr.slice(&memory_view, blake3::OUT_LEN as u32) else {
532 error!(
533 target: "runtime::util::get_tx_location",
534 "[WASM] [{}] get_tx_location(): Failed to make slice from ptr", cid,
535 );
536 return darkfi_sdk::error::DB_GET_FAILED
537 };
538
539 let mut buf = vec![0_u8; blake3::OUT_LEN];
540 if let Err(e) = mem_slice.read_slice(&mut buf) {
541 error!(
542 target: "runtime::util::get_tx_location",
543 "[WASM] [{}] get_tx_location(): Failed to read from memory slice: {}", cid, e,
544 );
545 return darkfi_sdk::error::DB_GET_FAILED
546 };
547
548 let mut buf_reader = Cursor::new(buf);
549
550 let hash: [u8; blake3::OUT_LEN] = match Decodable::decode(&mut buf_reader) {
552 Ok(v) => v,
553 Err(e) => {
554 error!(
555 target: "runtime::util::get_tx_location",
556 "[WASM] [{}] get_tx_location(): Failed to decode hash from vec: {}", cid, e,
557 );
558 return darkfi_sdk::error::DB_GET_FAILED
559 }
560 };
561
562 if buf_reader.position() != blake3::OUT_LEN as u64 {
565 error!(
566 target: "runtime::util::get_tx_location",
567 "[WASM] [{}] get_tx_location(): Trailing bytes in argument stream", cid,
568 );
569 return darkfi_sdk::error::DB_GET_FAILED
570 }
571
572 let ret = match env.blockchain.lock().unwrap().transactions.get_location_raw(&hash) {
574 Ok(v) => v,
575 Err(e) => {
576 error!(
577 target: "runtime::util::get_tx_location",
578 "[WASM] [{}] get_tx_location(): Internal error getting from tree: {}", cid, e,
579 );
580 return darkfi_sdk::error::DB_GET_FAILED
581 }
582 };
583
584 let Some(return_data) = ret else {
586 debug!(
587 target: "runtime::util::get_tx_location",
588 "[WASM] [{}] get_tx_location(): Return data is empty", cid,
589 );
590 return darkfi_sdk::error::DB_GET_EMPTY
591 };
592
593 if return_data.len() > u32::MAX as usize {
594 return darkfi_sdk::error::DATA_TOO_LARGE
595 }
596
597 env.subtract_gas(&mut store, return_data.len() as u64);
599
600 let mut objects = env.objects.borrow_mut();
602 if objects.len() == u32::MAX as usize {
603 return darkfi_sdk::error::DATA_TOO_LARGE
604 }
605
606 objects.push(return_data.to_vec());
609 (objects.len() - 1) as i64
610}