db.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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. use std::{io::Cursor, ops::Index};
  19. use darkfi_sdk::{
  20. crypto::ContractId,
  21. db::{
  22. CALLER_ACCESS_DENIED, DB_CONTAINS_KEY_FAILED, DB_DEL_FAILED, DB_GET_FAILED, DB_INIT_FAILED,
  23. DB_LOOKUP_FAILED, DB_SET_FAILED, DB_SUCCESS,
  24. },
  25. };
  26. use darkfi_serial::{deserialize, serialize, Decodable};
  27. use log::{debug, error, info};
  28. use wasmer::{FunctionEnvMut, WasmPtr};
  29. use super::acl::acl_allow;
  30. use crate::{
  31. blockchain::contract_store::SMART_CONTRACT_ZKAS_DB_NAME,
  32. runtime::vm_runtime::{ContractSection, Env},
  33. zk::{empty_witnesses, VerifyingKey, ZkCircuit},
  34. zkas::ZkBinary,
  35. };
  36. /// Internal wasm runtime API for sled trees
  37. #[derive(PartialEq)]
  38. pub struct DbHandle {
  39. pub contract_id: ContractId,
  40. pub tree: [u8; 32],
  41. }
  42. impl DbHandle {
  43. pub fn new(contract_id: ContractId, tree: [u8; 32]) -> Self {
  44. Self { contract_id, tree }
  45. }
  46. }
  47. /// Create a new database instance for the calling contract.
  48. ///
  49. /// This function expects to receive a pointer from which a `ContractId`
  50. /// and the `db_name` will be read.
  51. ///
  52. /// This function should **only** be allowed in `ContractSection::Deploy`, as that
  53. /// is called when a contract is being (re)deployed and databases have to be created.
  54. pub(crate) fn db_init(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i32 {
  55. let env = ctx.data();
  56. let cid = &env.contract_id;
  57. // Enforce function ACL
  58. if let Err(e) = acl_allow(env, &[ContractSection::Deploy]) {
  59. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] db_init ACL denied: {}", cid, e);
  60. // TODO: FIXME: We have to fix up the errors used within runtime and the sdk
  61. return CALLER_ACCESS_DENIED
  62. }
  63. // Enforce the ptr_len is no more than 64 bytes.
  64. if ptr_len > 64 {
  65. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] db_init ptr len is >64", cid);
  66. return DB_INIT_FAILED
  67. }
  68. // This takes lock of the blockchain overlay reference in the wasm env
  69. let contracts = &env.blockchain.lock().unwrap().contracts;
  70. // Create a mem slice of the wasm VM memory
  71. let memory_view = env.memory_view(&ctx);
  72. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  73. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Failed to make slice from ptr", cid);
  74. return DB_INIT_FAILED
  75. };
  76. // Allocate a buffer and copy all the data from the pointer into the buffer
  77. let mut buf = vec![0_u8; ptr_len as usize];
  78. if let Err(e) = mem_slice.read_slice(&mut buf) {
  79. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Failed to read memory slice: {}", cid, e);
  80. return DB_INIT_FAILED
  81. };
  82. // Once the data is copied, we'll attempt to deserialize it into the objects
  83. // we're expecting.
  84. let mut buf_reader = Cursor::new(buf);
  85. let read_cid: ContractId = match Decodable::decode(&mut buf_reader) {
  86. Ok(v) => v,
  87. Err(e) => {
  88. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Failed decoding ContractId: {}", cid, e);
  89. return DB_INIT_FAILED
  90. }
  91. };
  92. let read_db_name: String = match Decodable::decode(&mut buf_reader) {
  93. Ok(v) => v,
  94. Err(e) => {
  95. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Failed decoding db_name: {}", cid, e);
  96. return DB_INIT_FAILED
  97. }
  98. };
  99. // Make sure we've read the entire buffer
  100. if buf_reader.position() != ptr_len as u64 {
  101. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Trailing bytes in argument stream", cid);
  102. return DB_INIT_FAILED
  103. }
  104. // We cannot allow initializing the special zkas db:
  105. if read_db_name == SMART_CONTRACT_ZKAS_DB_NAME {
  106. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Attempted to init zkas db", cid);
  107. return CALLER_ACCESS_DENIED
  108. }
  109. // Nor can we allow another contract to initialize a db for someone else:
  110. if cid != &read_cid {
  111. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Unauthorized ContractId for db_init", cid);
  112. return CALLER_ACCESS_DENIED
  113. }
  114. // Now try to initialize the tree. If this returns an error,
  115. // it usually means that this DB was already initialized.
  116. // An alternative error might happen if something in sled fails,
  117. // for this we should take care to stop the node or do something to
  118. // be able to gracefully recover.
  119. // (src/blockchain/contract_store.rs holds this init() function)
  120. let tree_handle = match contracts.init(&read_cid, &read_db_name) {
  121. Ok(v) => v,
  122. Err(e) => {
  123. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Failed to init db: {}", cid, e);
  124. return DB_INIT_FAILED
  125. }
  126. };
  127. // Create the DbHandle
  128. let db_handle = DbHandle::new(read_cid, tree_handle);
  129. let mut db_handles = env.db_handles.borrow_mut();
  130. // Make sure we don't duplicate the DbHandle in the vec.
  131. // It's not really an issue, but it's better to be pedantic.
  132. if db_handles.contains(&db_handle) {
  133. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] DbHandle initialized twice during execution", cid);
  134. return DB_INIT_FAILED
  135. }
  136. match db_handles.len().try_into() {
  137. Ok(db_handle_idx) => {
  138. db_handles.push(db_handle);
  139. db_handle_idx
  140. }
  141. Err(_) => {
  142. error!(target: "runtime::db::db_init", "[wasm-runtime] [Contract:{}] Too many open DbHandles", cid);
  143. DB_INIT_FAILED
  144. }
  145. }
  146. }
  147. /// Lookup a database handle from its name. If it does not exist, push it to the Vector of
  148. /// db_handles.
  149. /// Returns the index of the DbHandle in the db_handles Vector on success. Otherwise, returns
  150. /// a negative error value.
  151. /// This function can be called from any [`ContractSection`].
  152. pub(crate) fn db_lookup(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i32 {
  153. let env = ctx.data();
  154. let cid = &env.contract_id;
  155. // Enforce function ACL
  156. if let Err(e) = acl_allow(
  157. env,
  158. &[
  159. ContractSection::Deploy,
  160. ContractSection::Exec,
  161. ContractSection::Metadata,
  162. ContractSection::Update,
  163. ],
  164. ) {
  165. error!(target: "runtime::db::db_lookup", "[wasm-runtime] [Contract:{}] db_lookup ACL denied: {}", cid, e);
  166. // TODO: FIXME: We have to fix up the errors used within runtime and the sdk
  167. return CALLER_ACCESS_DENIED
  168. }
  169. // Enforce the ptr_len is no more than 64 bytes.
  170. if ptr_len > 64 {
  171. error!(target: "runtime::db::db_lookup", "[wasm-runtime] db_lookup ptr len is >64");
  172. return DB_LOOKUP_FAILED
  173. }
  174. // Read memory location that contains the ContractId and DB name
  175. let memory_view = env.memory_view(&ctx);
  176. let contracts = &env.blockchain.lock().unwrap().contracts;
  177. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  178. error!(target: "runtime::db::db_lookup", "[wasm-runtime] [Contract:{}] Failed to make slice from ptr.", cid);
  179. return DB_LOOKUP_FAILED
  180. };
  181. let mut buf = vec![0_u8; ptr_len as usize];
  182. if let Err(e) = mem_slice.read_slice(&mut buf) {
  183. error!(target: "runtime::db::db_lookup", "[wasm-runtime] [Contract:{}] Failed to read from memory slice: {}", cid, e);
  184. return DB_LOOKUP_FAILED
  185. };
  186. let mut buf_reader = Cursor::new(buf);
  187. // Decode ContractId from memory
  188. let cid: ContractId = match Decodable::decode(&mut buf_reader) {
  189. Ok(v) => v,
  190. Err(e) => {
  191. error!(target: "runtime::db::db_lookup", "[wasm-runtime] [Contract:{}] Failed to decode ContractId: {}", cid, e);
  192. return DB_LOOKUP_FAILED
  193. }
  194. };
  195. // Decode DB name from memory
  196. let db_name: String = match Decodable::decode(&mut buf_reader) {
  197. Ok(v) => v,
  198. Err(e) => {
  199. error!(target: "runtime::db::db_lookup", "[wasm-runtime] [Contract:{}] Failed to decode db_name: {}", cid, e);
  200. return DB_LOOKUP_FAILED
  201. }
  202. };
  203. // Make sure we've read the entire buffer
  204. if buf_reader.position() != ptr_len as u64 {
  205. error!(target: "runtime::db::db_lookup", "[wasm-runtime] Trailing bytes in argument stream");
  206. return DB_LOOKUP_FAILED
  207. }
  208. if db_name == SMART_CONTRACT_ZKAS_DB_NAME {
  209. error!(target: "runtime::db::db_lookup", "[wasm-runtime] [Contract:{}] Attempted to lookup zkas db", cid);
  210. return CALLER_ACCESS_DENIED
  211. }
  212. // Lookup contract state
  213. let tree_handle = match contracts.lookup(&cid, &db_name) {
  214. Ok(v) => v,
  215. Err(_) => return DB_LOOKUP_FAILED,
  216. };
  217. // Create the DbHandle
  218. let db_handle = DbHandle::new(cid, tree_handle);
  219. let mut db_handles = env.db_handles.borrow_mut();
  220. // Make sure we don't duplicate the DbHandle in the vec
  221. if let Some(index) = db_handles.iter().position(|x| x == &db_handle) {
  222. return index as i32
  223. }
  224. // Push the new DbHandle to the Vec of opened DbHandles
  225. match db_handles.len().try_into() {
  226. Ok(db_handle_idx) => {
  227. db_handles.push(db_handle);
  228. db_handle_idx
  229. }
  230. Err(_) => {
  231. error!(target: "runtime::db::db_lookup", "[wasm-runtime] [Contract:{}] Too many open DbHandles", cid);
  232. DB_INIT_FAILED
  233. }
  234. }
  235. }
  236. /// Set a value within the transaction. `ptr` must contain the DbHandle index and
  237. /// the key-value pair. The DbHandle must match the ContractId.
  238. /// This function can be called only from the Deploy or Update [`ContractSection`].
  239. /// Returns `0` on success, otherwise returns a (negative) error value.
  240. pub(crate) fn db_set(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i32 {
  241. let env = ctx.data();
  242. if let Err(e) = acl_allow(env, &[ContractSection::Deploy, ContractSection::Update]) {
  243. error!(target: "runtime::db::db_set", "[wasm-runtime] db_set ACL denied: {}", e);
  244. // TODO: FIXME: We have to fix up the errors used within runtime and the sdk
  245. return CALLER_ACCESS_DENIED
  246. }
  247. // Ensure that it is possible to read from the memory that this function needs
  248. let memory_view = env.memory_view(&ctx);
  249. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  250. error!(target: "runtime::db::db_set", "Failed to make slice from ptr");
  251. return DB_SET_FAILED
  252. };
  253. let mut buf = vec![0_u8; ptr_len as usize];
  254. if let Err(e) = mem_slice.read_slice(&mut buf) {
  255. error!(target: "runtime::db::db_set", "Failed to read from memory slice: {}", e);
  256. return DB_SET_FAILED
  257. };
  258. let mut buf_reader = Cursor::new(buf);
  259. // Decode DbHandle index
  260. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  261. Ok(v) => v,
  262. Err(e) => {
  263. error!(target: "runtime::db::db_set", "Failed to decode DbHandle: {}", e);
  264. return DB_SET_FAILED
  265. }
  266. };
  267. let db_handle_index = db_handle_index as usize;
  268. // Decode key and value
  269. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  270. Ok(v) => v,
  271. Err(e) => {
  272. error!(target: "runtime::db::db_set", "Failed to decode key vec: {}", e);
  273. return DB_SET_FAILED
  274. }
  275. };
  276. let value: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  277. Ok(v) => v,
  278. Err(e) => {
  279. error!(target: "runtime::db::db_set", "Failed to decode value vec: {}", e);
  280. return DB_SET_FAILED
  281. }
  282. };
  283. // Make sure we've read the entire buffer
  284. if buf_reader.position() != ptr_len as u64 {
  285. error!(target: "runtime::db::db_set", "[wasm-runtime] Trailing bytes in argument stream");
  286. return DB_SET_FAILED
  287. }
  288. let db_handles = env.db_handles.borrow();
  289. // Check DbHandle index is within bounds
  290. if db_handles.len() <= db_handle_index {
  291. error!(target: "runtime::db::db_set", "Requested DbHandle that is out of bounds");
  292. return DB_SET_FAILED
  293. }
  294. // Retrive DbHandle using the index
  295. let db_handle = &db_handles[db_handle_index];
  296. // Validate that the DbHandle matches the contract ID
  297. if db_handle.contract_id != env.contract_id {
  298. error!(target: "runtime::db::db_set", "Unauthorized to write to DbHandle");
  299. return CALLER_ACCESS_DENIED
  300. }
  301. // Insert key-value pair into the database corresponding to this contract
  302. if env
  303. .blockchain
  304. .lock()
  305. .unwrap()
  306. .overlay
  307. .lock()
  308. .unwrap()
  309. .insert(&db_handle.tree, &key, &value)
  310. .is_err()
  311. {
  312. error!(target: "runtime::db::db_set", "Couldn't insert to db_handle tree");
  313. return DB_SET_FAILED
  314. }
  315. DB_SUCCESS
  316. }
  317. /// Remove a key from the database.
  318. /// This function can be called only from the Deploy or Update [`ContractSection`].
  319. /// Returns `0` on success, otherwise returns a (negative) error value.
  320. pub(crate) fn db_del(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i32 {
  321. let env = ctx.data();
  322. if let Err(e) = acl_allow(env, &[ContractSection::Deploy, ContractSection::Update]) {
  323. error!(target: "runtime::db::db_del", "[wasm-runtime] db_del ACL denied: {}", e);
  324. // TODO: FIXME: We have to fix up the errors used within runtime and the sdk
  325. return CALLER_ACCESS_DENIED
  326. }
  327. // Ensure that it is possible to read from the memory that this function needs
  328. let memory_view = env.memory_view(&ctx);
  329. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  330. error!(target: "runtime::db::db_del", "Failed to make slice from ptr");
  331. return DB_DEL_FAILED
  332. };
  333. let mut buf = vec![0_u8; ptr_len as usize];
  334. if let Err(e) = mem_slice.read_slice(&mut buf) {
  335. error!(target: "runtime::db::db_del", "Failed to read from memory slice: {}", e);
  336. return DB_DEL_FAILED
  337. };
  338. let mut buf_reader = Cursor::new(buf);
  339. // Decode DbHandle index
  340. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  341. Ok(v) => v,
  342. Err(e) => {
  343. error!(target: "runtime::db::db_del", "Failed to decode DbHandle: {}", e);
  344. return DB_DEL_FAILED
  345. }
  346. };
  347. let db_handle_index = db_handle_index as usize;
  348. // Decode key corresponding to the value that will be deleted
  349. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  350. Ok(v) => v,
  351. Err(e) => {
  352. error!(target: "runtime::db::db_del", "Failed to decode key vec: {}", e);
  353. return DB_DEL_FAILED
  354. }
  355. };
  356. // Make sure we've read the entire buffer
  357. if buf_reader.position() != ptr_len as u64 {
  358. error!(target: "runtime::db::db_del", "[wasm-runtime] Trailing bytes in argument stream");
  359. return DB_SET_FAILED
  360. }
  361. let db_handles = env.db_handles.borrow();
  362. if db_handles.len() <= db_handle_index {
  363. error!(target: "runtime::db::db_del()", "Requested DbHandle that is out of bounds");
  364. return DB_DEL_FAILED
  365. }
  366. // Retrive DbHandle using the index
  367. let db_handle = &db_handles[db_handle_index];
  368. // Validate that the DbHandle matches the contract ID
  369. if db_handle.contract_id != env.contract_id {
  370. error!(target: "runtime::db::db_del()", "Unauthorized to write to DbHandle");
  371. return CALLER_ACCESS_DENIED
  372. }
  373. // Remove key-value pair from the database corresponding to this contract
  374. if env.blockchain.lock().unwrap().overlay.lock().unwrap().remove(&db_handle.tree, &key).is_err()
  375. {
  376. error!(target: "runtime::db::db_del()", "Couldn't remove key from db_handle tree");
  377. return DB_DEL_FAILED
  378. }
  379. DB_SUCCESS
  380. }
  381. /// Reads a key from the key-value store.
  382. /// Thie function can be called from the Deploy, Exec, or Metadata [`ContractSection`].
  383. /// On success, returns the length of the `objects` Vector in the environment.
  384. /// Otherwise, returns a negative error code.
  385. pub(crate) fn db_get(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  386. let env = ctx.data();
  387. if let Err(e) =
  388. acl_allow(env, &[ContractSection::Deploy, ContractSection::Exec, ContractSection::Metadata])
  389. {
  390. error!(target: "runtime::db::db_get", "[wasm-runtime] db_get ACL denied: {}", e);
  391. // TODO: FIXME: We have to fix up the errors used within runtime and the sdk
  392. return CALLER_ACCESS_DENIED.into()
  393. }
  394. // Ensure that it is possible to read memory
  395. let memory_view = env.memory_view(&ctx);
  396. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  397. error!(target: "runtime::db::db_get", "Failed to make slice from ptr");
  398. return DB_GET_FAILED.into()
  399. };
  400. let mut buf = vec![0_u8; ptr_len as usize];
  401. if let Err(e) = mem_slice.read_slice(&mut buf) {
  402. error!(target: "runtime::db::db_get", "Failed to read from memory slice: {}", e);
  403. return DB_GET_FAILED.into()
  404. };
  405. let mut buf_reader = Cursor::new(buf);
  406. // Decode DbHandle index
  407. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  408. Ok(v) => v,
  409. Err(e) => {
  410. error!(target: "runtime::db::db_get", "Failed to decode DbHandle: {}", e);
  411. return DB_GET_FAILED.into()
  412. }
  413. };
  414. let db_handle_index = db_handle_index as usize;
  415. // Decode key for key-value pair that we wish to retrieve
  416. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  417. Ok(v) => v,
  418. Err(e) => {
  419. error!(target: "runtime::db::db_get", "Failed to decode key from vec: {}", e);
  420. return DB_GET_FAILED.into()
  421. }
  422. };
  423. // Make sure there are no trailing bytes in the buffer. This means we've used all data that was
  424. // supplied.
  425. if buf_reader.position() != ptr_len as u64 {
  426. error!(target: "runtime::db::db_get", "[wasm-runtime] Trailing bytes in argument stream");
  427. return DB_GET_FAILED.into()
  428. }
  429. let db_handles = env.db_handles.borrow();
  430. // Ensure that the index is within bounds
  431. if db_handles.len() <= db_handle_index {
  432. error!(target: "runtime::db::db_get", "Requested DbHandle that is out of bounds");
  433. return DB_GET_FAILED.into()
  434. }
  435. // Get DbHandle using db_handle_index
  436. let db_handle = &db_handles[db_handle_index];
  437. // Retrieve data using the `key`
  438. let ret =
  439. match env.blockchain.lock().unwrap().overlay.lock().unwrap().get(&db_handle.tree, &key) {
  440. Ok(v) => v,
  441. Err(e) => {
  442. error!(target: "runtime::db::db_get", "Internal error getting from tree: {}", e);
  443. return DB_GET_FAILED.into()
  444. }
  445. };
  446. // Return error if the data is empty
  447. let Some(return_data) = ret else {
  448. debug!(target: "runtime::db::db_get", "Return data is empty");
  449. return -127
  450. };
  451. // Copy the data (Vec<u8>) to the VM by pushing it to the objects Vector.
  452. let mut objects = env.objects.borrow_mut();
  453. objects.push(return_data.to_vec());
  454. // Return the length of the objects Vector. This is the location of the data that was retrieved
  455. // and pushed
  456. (objects.len() - 1) as i64
  457. }
  458. /// Everyone can call this. Will check if a given db contains given key.
  459. pub(crate) fn db_contains_key(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
  460. let env = ctx.data();
  461. if env.contract_section != ContractSection::Deploy &&
  462. env.contract_section != ContractSection::Exec &&
  463. env.contract_section != ContractSection::Update &&
  464. env.contract_section != ContractSection::Metadata
  465. {
  466. error!(target: "runtime::db::db_contains_key()", "db_contains_key called in unauthorized section");
  467. return CALLER_ACCESS_DENIED
  468. }
  469. let memory_view = env.memory_view(&ctx);
  470. let Ok(mem_slice) = ptr.slice(&memory_view, len) else {
  471. error!(target: "runtime::db::db_contains_key()", "Failed to make slice from ptr");
  472. return DB_CONTAINS_KEY_FAILED
  473. };
  474. let mut buf = vec![0_u8; len as usize];
  475. if let Err(e) = mem_slice.read_slice(&mut buf) {
  476. error!(target: "runtime::db::db_contains_key()", "Failed to read from memory slice: {}", e);
  477. return DB_CONTAINS_KEY_FAILED
  478. };
  479. let mut buf_reader = Cursor::new(buf);
  480. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  481. Ok(v) => v,
  482. Err(e) => {
  483. error!(target: "runtime::db::db_contains_key()", "Failed to decode DbHandle: {}", e);
  484. return DB_CONTAINS_KEY_FAILED
  485. }
  486. };
  487. let db_handle_index = db_handle_index as usize;
  488. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  489. Ok(v) => v,
  490. Err(e) => {
  491. error!(target: "runtime::db::db_contains_key()", "Failed to decode key vec: {}", e);
  492. return DB_CONTAINS_KEY_FAILED
  493. }
  494. };
  495. // TODO: Disabled until cursor_remaining feature is available on master.
  496. // Then enable #![feature(cursor_remaining)] in src/lib.rs
  497. // unstable feature, open issue https://github.com/rust-lang/rust/issues/86369
  498. /*if !buf_reader.is_empty() {
  499. error!(target: "runtime::db::db_contains_key()", "Trailing bytes in argument stream");
  500. return DB_CONTAINS_KEY_FAILED
  501. }*/
  502. let db_handles = env.db_handles.borrow();
  503. if db_handles.len() <= db_handle_index {
  504. error!(target: "runtime::db::db_contains_key()", "Requested DbHandle that is out of bounds");
  505. return DB_CONTAINS_KEY_FAILED
  506. }
  507. let db_handle = &db_handles[db_handle_index];
  508. match env.blockchain.lock().unwrap().overlay.lock().unwrap().contains_key(&db_handle.tree, &key)
  509. {
  510. Ok(v) => i32::from(v), // <- 0=false, 1=true
  511. Err(e) => {
  512. error!(target: "runtime::db::db_contains_key()", "sled.tree.contains_key failed: {}", e);
  513. DB_CONTAINS_KEY_FAILED
  514. }
  515. }
  516. }
  517. /// Only `deploy()` can call this. Given a zkas circuit, create a VerifyingKey and insert
  518. /// them both into the db.
  519. pub(crate) fn zkas_db_set(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
  520. let env = ctx.data();
  521. if env.contract_section != ContractSection::Deploy {
  522. error!(target: "runtime::db::zkas_db_set()", "zkas_db_set called in unauthorized section");
  523. return CALLER_ACCESS_DENIED
  524. }
  525. let memory_view = env.memory_view(&ctx);
  526. let contract_id = &env.contract_id;
  527. let Ok(mem_slice) = ptr.slice(&memory_view, len) else {
  528. error!(target: "runtime::db::zkas_db_set()", "Failed to make slice from ptr");
  529. return DB_SET_FAILED
  530. };
  531. let mut buf = vec![0u8; len as usize];
  532. if let Err(e) = mem_slice.read_slice(&mut buf) {
  533. error!(target: "runtime::db::zkas_db_set()", "Failed to read from memory slice: {}", e);
  534. return DB_SET_FAILED
  535. };
  536. let mut buf_reader = Cursor::new(buf);
  537. let zkas_bincode: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  538. Ok(v) => v,
  539. Err(e) => {
  540. error!(target: "runtime::db::zkas_db_set()", "Failed to decode zkas bincode bytes: {}", e);
  541. return DB_SET_FAILED
  542. }
  543. };
  544. // Make sure that we're actually working on legitimate bincode.
  545. let Ok(zkbin) = ZkBinary::decode(&zkas_bincode) else {
  546. error!(target: "runtime::db::zkas_db_set()", "Invalid zkas bincode passed to function");
  547. return DB_SET_FAILED
  548. };
  549. // Because of `Runtime::Deploy`, we should be sure that the zkas db is index zero.
  550. let db_handles = env.db_handles.borrow();
  551. let db_handle = &db_handles[0];
  552. // Redundant check
  553. if &db_handle.contract_id != contract_id {
  554. error!(target: "runtime::db::zkas_db_set()", "Internal error, zkas db at index 0 incorrect");
  555. return DB_SET_FAILED
  556. }
  557. // Check if there is existing bincode and compare it. Return DB_SUCCESS if
  558. // they're the same. The assumption should be that VerifyingKey was generated
  559. // already so we can skip things after this guard.
  560. match env
  561. .blockchain
  562. .lock()
  563. .unwrap()
  564. .overlay
  565. .lock()
  566. .unwrap()
  567. .get(&db_handle.tree, &serialize(&zkbin.namespace))
  568. {
  569. Ok(v) => {
  570. if let Some(bytes) = v {
  571. // We allow a panic here because this db should never be corrupted in this way.
  572. let (existing_zkbin, _): (Vec<u8>, Vec<u8>) =
  573. deserialize(&bytes).expect("deserialize tuple");
  574. if existing_zkbin == zkas_bincode {
  575. debug!(target: "runtime::db::zkas_db_set()", "Existing zkas bincode is the same. Skipping.");
  576. return DB_SUCCESS
  577. }
  578. }
  579. }
  580. Err(e) => {
  581. error!(target: "runtime::db::zkas_db_set()", "Internal error getting from tree: {}", e);
  582. return DB_SET_FAILED
  583. }
  584. };
  585. // We didn't find any existing bincode, so let's create a new VerifyingKey and write it all.
  586. info!(target: "runtime::db::zkas_db_set()", "Creating VerifyingKey for {} zkas circuit", zkbin.namespace);
  587. let witnesses = match empty_witnesses(&zkbin) {
  588. Ok(w) => w,
  589. Err(e) => {
  590. error!(target: "runtime::db::zkas_db_set()", "Failed to create empty witnesses: {}", e);
  591. return DB_SET_FAILED
  592. }
  593. };
  594. // Construct the circuit and build the VerifyingKey
  595. let circuit = ZkCircuit::new(witnesses, &zkbin);
  596. let vk = VerifyingKey::build(zkbin.k, &circuit);
  597. let mut vk_buf = vec![];
  598. if let Err(e) = vk.write(&mut vk_buf) {
  599. error!(target: "runtime::db::zkas_db_set()", "Failed to serialize VerifyingKey: {}", e);
  600. return DB_SET_FAILED
  601. }
  602. let key = serialize(&zkbin.namespace);
  603. let value = serialize(&(zkas_bincode, vk_buf));
  604. if env
  605. .blockchain
  606. .lock()
  607. .unwrap()
  608. .overlay
  609. .lock()
  610. .unwrap()
  611. .insert(&db_handle.tree, &key, &value)
  612. .is_err()
  613. {
  614. error!(target: "runtime::db::zkas_db_set()", "Couldn't insert to db_handle tree");
  615. return DB_SET_FAILED
  616. }
  617. DB_SUCCESS
  618. }