util.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. // NOTE: temporary imports
  19. use sled::IVec;
  20. use std::collections::BTreeMap as Map;
  21. use log::error;
  22. use wasmer::{FunctionEnvMut, WasmPtr};
  23. use crate::runtime::vm_runtime::{ContractSection, Env};
  24. /// Host function for logging strings.
  25. /// This is injected into the runtime with wasmer's `imports!` macro.
  26. pub(crate) fn drk_log(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) {
  27. let env = ctx.data();
  28. let memory_view = env.memory_view(&ctx);
  29. match ptr.read_utf8_string(&memory_view, len) {
  30. Ok(msg) => {
  31. let mut logs = env.logs.borrow_mut();
  32. logs.push(msg);
  33. std::mem::drop(logs);
  34. }
  35. Err(_) => {
  36. error!(target: "runtime::util", "Failed to read UTF-8 string from VM memory");
  37. }
  38. }
  39. }
  40. pub(crate) fn set_return_data(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i64 {
  41. let env = ctx.data();
  42. match env.contract_section {
  43. ContractSection::Exec | ContractSection::Metadata => {
  44. let memory_view = env.memory_view(&ctx);
  45. let Ok(slice) = ptr.slice(&memory_view, len) else {
  46. return darkfi_sdk::error::INTERNAL_ERROR
  47. };
  48. let Ok(return_data) = slice.read_to_vec() else {
  49. return darkfi_sdk::error::INTERNAL_ERROR
  50. };
  51. // This function should only ever be called once on the runtime.
  52. if env.contract_return_data.take().is_some() {
  53. return darkfi_sdk::error::SET_RETVAL_ERROR
  54. }
  55. env.contract_return_data.set(Some(return_data));
  56. 0
  57. }
  58. _ => darkfi_sdk::error::CALLER_ACCESS_DENIED,
  59. }
  60. }
  61. pub(crate) fn put_object_bytes(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i64 {
  62. let env = ctx.data();
  63. let memory_view = env.memory_view(&ctx);
  64. //debug!(target: "runtime::util", "diagnostic:");
  65. //let pages = memory_view.size().0;
  66. //debug!(target: "runtime::util", " pages: {}", pages);
  67. let Ok(slice) = ptr.slice(&memory_view, len) else {
  68. error!(target: "runtime::util", "Failed to make slice from ptr");
  69. return -2
  70. };
  71. let mut buf = vec![0_u8; len as usize];
  72. if let Err(e) = slice.read_slice(&mut buf) {
  73. error!(target: "runtime::util", "Failed to read from memory slice: {}", e);
  74. return -2
  75. };
  76. // There would be a serious problem if this is zero.
  77. // The number of pages is calculated as a quantity X + 1 where X >= 0
  78. //assert!(pages > 0);
  79. //debug!(target: "runtime::util", " memory: {:02x?}", &buf[0..32]);
  80. //debug!(target: "runtime::util", " {:x?}", &buf[32..64]);
  81. //debug!(target: "runtime::util", " ptr location: {}", ptr.offset());
  82. let mut objects = env.objects.borrow_mut();
  83. objects.push(buf);
  84. let obj_idx = objects.len() - 1;
  85. obj_idx as i64
  86. }
  87. pub(crate) fn get_object_bytes(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, idx: u32) -> i64 {
  88. // Get the slice, where we will read the size of the buffer
  89. let env = ctx.data();
  90. let memory_view = env.memory_view(&ctx);
  91. // Get the object from env
  92. let objects = env.objects.borrow();
  93. if idx as usize >= objects.len() {
  94. error!(target: "runtime::util", "Tried to access object out of bounds");
  95. return -5
  96. }
  97. let obj = &objects[idx as usize];
  98. // Read N bytes from the object and write onto the ptr.
  99. // We need to re-read the slice, since in the first run, we just read n
  100. let Ok(slice) = ptr.slice(&memory_view, obj.len() as u32) else {
  101. error!(target: "runtime::util", "Failed to make slice from ptr");
  102. return -2
  103. };
  104. // Put the result in the VM
  105. if let Err(e) = slice.write_slice(obj) {
  106. error!(target: "runtime::util", "Failed to write to memory slice: {}", e);
  107. return -4
  108. };
  109. 0
  110. }
  111. pub(crate) fn get_object_size(ctx: FunctionEnvMut<Env>, idx: u32) -> i64 {
  112. // Get the slice, where we will read the size of the buffer
  113. let env = ctx.data();
  114. //let memory_view = env.memory_view(&ctx);
  115. // Get the object from env
  116. let objects = env.objects.borrow();
  117. if idx as usize >= objects.len() {
  118. error!(target: "runtime::util", "Tried to access object out of bounds");
  119. return -5
  120. }
  121. let obj = &objects[idx as usize];
  122. obj.len() as i64
  123. }
  124. // TODO: This is a direct copy of [`sled::Batch`](late night adventures).
  125. // Options:
  126. // 1. Upstream a get_writes() function
  127. // 2. Make writes public to external crates in upstream
  128. // 3. Drop Batches usage since we can write directly to the overlay
  129. // 4. Upstream batches support to sled_overlay
  130. #[derive(Debug, Default, Clone, PartialEq, Eq)]
  131. pub struct Batch {
  132. pub(crate) writes: Map<IVec, Option<IVec>>,
  133. }
  134. impl Batch {
  135. /// Set a key to a new value
  136. pub fn insert<K, V>(&mut self, key: K, value: V)
  137. where
  138. K: Into<IVec>,
  139. V: Into<IVec>,
  140. {
  141. self.writes.insert(key.into(), Some(value.into()));
  142. }
  143. /// Remove a key
  144. pub fn remove<K>(&mut self, key: K)
  145. where
  146. K: Into<IVec>,
  147. {
  148. self.writes.insert(key.into(), None);
  149. }
  150. /// Get a value if it is present in the `Batch`.
  151. /// `Some(None)` means it's present as a deletion.
  152. pub fn get<K: AsRef<[u8]>>(&self, k: K) -> Option<Option<&IVec>> {
  153. let inner = self.writes.get(k.as_ref())?;
  154. Some(inner.as_ref())
  155. }
  156. }