db.rs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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;
  19. use darkfi_sdk::crypto::ContractId;
  20. use darkfi_serial::{deserialize, serialize, Decodable};
  21. use log::{debug, error, info};
  22. use wasmer::{FunctionEnvMut, WasmPtr};
  23. use super::acl::acl_allow;
  24. use crate::{
  25. blockchain::contract_store::SMART_CONTRACT_ZKAS_DB_NAME,
  26. runtime::vm_runtime::{ContractSection, Env},
  27. zk::{empty_witnesses, VerifyingKey, ZkCircuit},
  28. zkas::ZkBinary,
  29. };
  30. /// Internal wasm runtime API for sled trees
  31. #[derive(PartialEq)]
  32. pub struct DbHandle {
  33. pub contract_id: ContractId,
  34. pub tree: [u8; 32],
  35. }
  36. impl DbHandle {
  37. pub fn new(contract_id: ContractId, tree: [u8; 32]) -> Self {
  38. Self { contract_id, tree }
  39. }
  40. }
  41. /// Create a new database instance for the calling contract.
  42. ///
  43. /// This function expects to receive a pointer from which a `ContractId`
  44. /// and the `db_name` will be read.
  45. ///
  46. /// This function should **only** be allowed in `ContractSection::Deploy`, as that
  47. /// is called when a contract is being (re)deployed and databases have to be created.
  48. pub(crate) fn db_init(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  49. let (env, mut store) = ctx.data_and_store_mut();
  50. let cid = env.contract_id;
  51. // Enforce function ACL
  52. if let Err(e) = acl_allow(env, &[ContractSection::Deploy]) {
  53. error!(
  54. target: "runtime::db::db_init",
  55. "[WASM] [{}] db_init(): Called in unauthorized section: {}", cid, e,
  56. );
  57. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  58. }
  59. // Subtract used gas. Here we count the length read from the memory slice.
  60. // TODO: There should probably be an additional fee to open a new sled tree.
  61. env.subtract_gas(&mut store, ptr_len as u64);
  62. // This takes lock of the blockchain overlay reference in the wasm env
  63. let contracts = &env.blockchain.lock().unwrap().contracts;
  64. // Create a mem slice of the wasm VM memory
  65. let memory_view = env.memory_view(&store);
  66. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  67. error!(
  68. target: "runtime::db::db_init",
  69. "[WASM] [{}] db_init(): Failed to make slice from ptr", cid,
  70. );
  71. return darkfi_sdk::error::DB_INIT_FAILED
  72. };
  73. // Allocate a buffer and copy all the data from the pointer into the buffer
  74. let mut buf = vec![0_u8; ptr_len as usize];
  75. if let Err(e) = mem_slice.read_slice(&mut buf) {
  76. error!(
  77. target: "runtime::db::db_init",
  78. "[WASM] [{}] db_init(): Failed to read memory slice: {}", cid, e,
  79. );
  80. return darkfi_sdk::error::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!(
  89. target: "runtime::db::db_init",
  90. "[WASM] [{}] db_init(): Failed decoding ContractId: {}", cid, e,
  91. );
  92. return darkfi_sdk::error::DB_INIT_FAILED
  93. }
  94. };
  95. let read_db_name: String = match Decodable::decode(&mut buf_reader) {
  96. Ok(v) => v,
  97. Err(e) => {
  98. error!(
  99. target: "runtime::db::db_init",
  100. "[WASM] [{}] db_init(): Failed decoding db_name: {}", cid, e,
  101. );
  102. return darkfi_sdk::error::DB_INIT_FAILED
  103. }
  104. };
  105. // Make sure we've read the entire buffer
  106. if buf_reader.position() != ptr_len as u64 {
  107. error!(
  108. target: "runtime::db::db_init",
  109. "[WASM] [{}] db_init(): Trailing bytes in argument stream", cid,
  110. );
  111. return darkfi_sdk::error::DB_INIT_FAILED
  112. }
  113. // We cannot allow initializing the special zkas db:
  114. if read_db_name == SMART_CONTRACT_ZKAS_DB_NAME {
  115. error!(
  116. target: "runtime::db::db_init",
  117. "[WASM] [{}] db_init(): Attempted to init zkas db", cid,
  118. );
  119. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  120. }
  121. // Nor can we allow another contract to initialize a db for someone else:
  122. if cid != read_cid {
  123. error!(
  124. target: "runtime::db::db_init",
  125. "[WASM] [{}] db_init(): Unauthorized ContractId", cid,
  126. );
  127. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  128. }
  129. // Now try to initialize the tree. If this returns an error,
  130. // it usually means that this DB was already initialized.
  131. // An alternative error might happen if something in sled fails,
  132. // for this we should take care to stop the node or do something to
  133. // be able to gracefully recover.
  134. // (src/blockchain/contract_store.rs holds this init() function)
  135. let tree_handle = match contracts.init(&read_cid, &read_db_name) {
  136. Ok(v) => v,
  137. Err(e) => {
  138. error!(
  139. target: "runtime::db::db_init",
  140. "[WASM] [{}] db_init(): Failed to init db: {}", cid, e,
  141. );
  142. return darkfi_sdk::error::DB_INIT_FAILED
  143. }
  144. };
  145. // Create the DbHandle
  146. let db_handle = DbHandle::new(read_cid, tree_handle);
  147. let mut db_handles = env.db_handles.borrow_mut();
  148. // Make sure we don't duplicate the DbHandle in the vec.
  149. // It's not really an issue, but it's better to be pedantic.
  150. if db_handles.contains(&db_handle) {
  151. error!(
  152. target: "runtime::db::db_init",
  153. "[WASM] [{}] db_init(): DbHandle initialized twice during execution", cid,
  154. );
  155. return darkfi_sdk::error::DB_INIT_FAILED
  156. }
  157. // This tries to cast into u32
  158. match db_handles.len().try_into() {
  159. Ok(db_handle_idx) => {
  160. db_handles.push(db_handle);
  161. // Return the db handle index
  162. db_handle_idx
  163. }
  164. Err(_) => {
  165. error!(
  166. target: "runtime::db::db_init",
  167. "[WASM] [{}] db_init(): Too many open DbHandles", cid,
  168. );
  169. darkfi_sdk::error::DB_INIT_FAILED
  170. }
  171. }
  172. }
  173. /// Lookup a database handle from its name.
  174. /// If it exists, push it to the Vector of db_handles.
  175. ///
  176. /// Returns the index of the DbHandle in the db_handles Vector on success.
  177. /// Otherwise, returns an error value.
  178. ///
  179. /// This function can be called from any [`ContractSection`].
  180. pub(crate) fn db_lookup(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  181. let (env, mut store) = ctx.data_and_store_mut();
  182. let cid = env.contract_id;
  183. // Enforce function ACL
  184. if let Err(e) = acl_allow(
  185. env,
  186. &[
  187. ContractSection::Deploy,
  188. ContractSection::Exec,
  189. ContractSection::Metadata,
  190. ContractSection::Update,
  191. ],
  192. ) {
  193. error!(
  194. target: "runtime::db::db_lookup",
  195. "[WASM] [{}] db_lookup() called in unauthorized section: {}", cid, e,
  196. );
  197. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  198. }
  199. // Subtract used gas. Here we count the length read from the memory slice.
  200. env.subtract_gas(&mut store, ptr_len as u64);
  201. // Read memory location that contains the ContractId and DB name
  202. let memory_view = env.memory_view(&store);
  203. let contracts = &env.blockchain.lock().unwrap().contracts;
  204. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  205. error!(
  206. target: "runtime::db::db_lookup",
  207. "[WASM] [{}] db_lookup(): Failed to make slice from ptr.", cid,
  208. );
  209. return darkfi_sdk::error::DB_LOOKUP_FAILED
  210. };
  211. let mut buf = vec![0_u8; ptr_len as usize];
  212. if let Err(e) = mem_slice.read_slice(&mut buf) {
  213. error!(
  214. target: "runtime::db::db_lookup",
  215. "[WASM] [{}] db_lookup(): Failed to read from memory slice: {}", cid, e,
  216. );
  217. return darkfi_sdk::error::DB_LOOKUP_FAILED
  218. };
  219. // Wrap the buffer into a Cursor for stream reading
  220. let mut buf_reader = Cursor::new(buf);
  221. // Decode ContractId from memory
  222. let cid: ContractId = match Decodable::decode(&mut buf_reader) {
  223. Ok(v) => v,
  224. Err(e) => {
  225. error!(
  226. target: "runtime::db::db_lookup",
  227. "[WASM] [{}] db_lookup(): Failed to decode ContractId: {}", cid, e,
  228. );
  229. return darkfi_sdk::error::DB_LOOKUP_FAILED
  230. }
  231. };
  232. // Decode DB name from memory
  233. let db_name: String = match Decodable::decode(&mut buf_reader) {
  234. Ok(v) => v,
  235. Err(e) => {
  236. error!(
  237. target: "runtime::db::db_lookup",
  238. "[WASM] [{}] db_lookup(): Failed to decode db_name: {}", cid, e,
  239. );
  240. return darkfi_sdk::error::DB_LOOKUP_FAILED
  241. }
  242. };
  243. // Make sure we've read the entire buffer
  244. if buf_reader.position() != ptr_len as u64 {
  245. error!(
  246. target: "runtime::db::db_lookup",
  247. "[WASM] [{}] db_lookup(), Trailing bytes in argument stream", cid,
  248. );
  249. return darkfi_sdk::error::DB_LOOKUP_FAILED
  250. }
  251. if db_name == SMART_CONTRACT_ZKAS_DB_NAME {
  252. error!(
  253. target: "runtime::db::db_lookup",
  254. "[WASM] [{}] db_lookup(): Attempted to lookup zkas db", cid,
  255. );
  256. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  257. }
  258. // Lookup contract state
  259. let tree_handle = match contracts.lookup(&cid, &db_name) {
  260. Ok(v) => v,
  261. Err(_) => return darkfi_sdk::error::DB_LOOKUP_FAILED,
  262. };
  263. // Create the DbHandle
  264. let db_handle = DbHandle::new(cid, tree_handle);
  265. let mut db_handles = env.db_handles.borrow_mut();
  266. // Make sure we don't duplicate the DbHandle in the vec
  267. if let Some(index) = db_handles.iter().position(|x| x == &db_handle) {
  268. return index as i64
  269. }
  270. // Push the new DbHandle to the Vec of opened DbHandles
  271. match db_handles.len().try_into() {
  272. Ok(db_handle_idx) => {
  273. db_handles.push(db_handle);
  274. db_handle_idx
  275. }
  276. Err(_) => {
  277. error!(
  278. target: "runtime::db::db_lookup",
  279. "[WASM] [{}] db_lookup(): Too many open DbHandles", cid,
  280. );
  281. darkfi_sdk::error::DB_LOOKUP_FAILED
  282. }
  283. }
  284. }
  285. /// Set a value within the transaction.
  286. ///
  287. /// * `ptr` must contain the DbHandle index and the key-value pair.
  288. /// * The DbHandle must match the ContractId.
  289. ///
  290. /// This function can be called only from the Deploy or Update [`ContractSection`].
  291. /// Returns `SUCCESS` on success, otherwise returns an error value.
  292. pub(crate) fn db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  293. let (env, mut store) = ctx.data_and_store_mut();
  294. let cid = env.contract_id;
  295. if let Err(e) = acl_allow(env, &[ContractSection::Deploy, ContractSection::Update]) {
  296. error!(
  297. target: "runtime::db::db_set",
  298. "[WASM] [{}] db_set(): Called in unauthorized section: {}", cid, e,
  299. );
  300. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  301. }
  302. // Subtract used gas. Here we count the length hread from the memory slice.
  303. env.subtract_gas(&mut store, ptr_len as u64);
  304. // Ensure that it is possible to read from the memory that this function needs
  305. let memory_view = env.memory_view(&store);
  306. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  307. error!(
  308. target: "runtime::db::db_set",
  309. "[WASM] [{}] db_set(): Failed to make slice from ptr", cid,
  310. );
  311. return darkfi_sdk::error::DB_SET_FAILED
  312. };
  313. let mut buf = vec![0_u8; ptr_len as usize];
  314. if let Err(e) = mem_slice.read_slice(&mut buf) {
  315. error!(
  316. target: "runtime::db::db_set",
  317. "[WASM] [{}] db_set(): Failed to read from memory slice: {}", cid, e,
  318. );
  319. return darkfi_sdk::error::DB_SET_FAILED
  320. };
  321. let mut buf_reader = Cursor::new(buf);
  322. // Decode DbHandle index
  323. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  324. Ok(v) => v,
  325. Err(e) => {
  326. error!(
  327. target: "runtime::db::db_set",
  328. "[WASM] [{}] db_set(): Failed to decode DbHandle: {}", cid, e,
  329. );
  330. return darkfi_sdk::error::DB_SET_FAILED
  331. }
  332. };
  333. let db_handle_index = db_handle_index as usize;
  334. // Decode key and value
  335. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  336. Ok(v) => v,
  337. Err(e) => {
  338. error!(
  339. target: "runtime::db::db_set",
  340. "[WASM] [{}] db_set(): Failed to decode key vec: {}", cid, e,
  341. );
  342. return darkfi_sdk::error::DB_SET_FAILED
  343. }
  344. };
  345. let value: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  346. Ok(v) => v,
  347. Err(e) => {
  348. error!(
  349. target: "runtime::db::db_set",
  350. "[WASM] [{}] db_set(): Failed to decode value vec: {}", cid, e,
  351. );
  352. return darkfi_sdk::error::DB_SET_FAILED
  353. }
  354. };
  355. // Make sure we've read the entire buffer
  356. if buf_reader.position() != ptr_len as u64 {
  357. error!(
  358. target: "runtime::db::db_set",
  359. "[WASM] [{}] db_set(): Trailing bytes in argument stream", cid,
  360. );
  361. return darkfi_sdk::error::DB_SET_FAILED
  362. }
  363. let db_handles = env.db_handles.borrow();
  364. // Check DbHandle index is within bounds
  365. if db_handles.len() <= db_handle_index {
  366. error!(
  367. target: "runtime::db::db_set",
  368. "[WASM] [{}] db_set(): Requested DbHandle that is out of bounds", cid,
  369. );
  370. return darkfi_sdk::error::DB_SET_FAILED
  371. }
  372. // Retrive DbHandle using the index
  373. let db_handle = &db_handles[db_handle_index];
  374. // Validate that the DbHandle matches the contract ID
  375. if db_handle.contract_id != env.contract_id {
  376. error!(
  377. target: "runtime::db::db_set",
  378. "[WASM] [{}] db_set(): Unauthorized to write to DbHandle", cid,
  379. );
  380. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  381. }
  382. // Insert key-value pair into the database corresponding to this contract
  383. if env
  384. .blockchain
  385. .lock()
  386. .unwrap()
  387. .overlay
  388. .lock()
  389. .unwrap()
  390. .insert(&db_handle.tree, &key, &value)
  391. .is_err()
  392. {
  393. error!(
  394. target: "runtime::db::db_set",
  395. "[WASM] [{}] db_set(): Couldn't insert to db_handle tree", cid,
  396. );
  397. return darkfi_sdk::error::DB_SET_FAILED
  398. }
  399. darkfi_sdk::entrypoint::SUCCESS
  400. }
  401. /// Remove a key from the database.
  402. ///
  403. /// This function can be called only from the Deploy or Update [`ContractSection`].
  404. /// Returns `SUCCESS` on success, otherwise returns an error value.
  405. pub(crate) fn db_del(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  406. let (env, mut store) = ctx.data_and_store_mut();
  407. let cid = env.contract_id;
  408. if let Err(e) = acl_allow(env, &[ContractSection::Deploy, ContractSection::Update]) {
  409. error!(
  410. target: "runtime::db::db_del",
  411. "[WASM] [{}] db_del(): Called in unauthorized section: {}", cid, e,
  412. );
  413. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  414. }
  415. // Subtract used gas. Here we count the length of the looked-up key.
  416. env.subtract_gas(&mut store, ptr_len as u64);
  417. // Ensure that it is possible to read from the memory that this function needs
  418. let memory_view = env.memory_view(&store);
  419. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  420. error!(
  421. target: "runtime::db::db_del",
  422. "[WASM] [{}] db_del(): Failed to make slice from ptr", cid,
  423. );
  424. return darkfi_sdk::error::DB_DEL_FAILED
  425. };
  426. let mut buf = vec![0_u8; ptr_len as usize];
  427. if let Err(e) = mem_slice.read_slice(&mut buf) {
  428. error!(
  429. target: "runtime::db::db_del",
  430. "[WASM] [{}] db_del(): Failed to read from memory slice: {}", cid, e,
  431. );
  432. return darkfi_sdk::error::DB_DEL_FAILED
  433. };
  434. let mut buf_reader = Cursor::new(buf);
  435. // Decode DbHandle index
  436. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  437. Ok(v) => v,
  438. Err(e) => {
  439. error!(
  440. target: "runtime::db::db_del",
  441. "[WASM] [{}] db_del(): Failed to decode DbHandle: {}", cid, e,
  442. );
  443. return darkfi_sdk::error::DB_DEL_FAILED
  444. }
  445. };
  446. let db_handle_index = db_handle_index as usize;
  447. // Decode key corresponding to the value that will be deleted
  448. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  449. Ok(v) => v,
  450. Err(e) => {
  451. error!(
  452. target: "runtime::db::db_del",
  453. "[WASM] [{}] db_del(): Failed to decode key vec: {}", cid, e,
  454. );
  455. return darkfi_sdk::error::DB_DEL_FAILED
  456. }
  457. };
  458. // Make sure we've read the entire buffer
  459. if buf_reader.position() != ptr_len as u64 {
  460. error!(
  461. target: "runtime::db::db_del",
  462. "[WASM] [{}] db_del(): Trailing bytes in argument stream", cid,
  463. );
  464. return darkfi_sdk::error::DB_DEL_FAILED
  465. }
  466. let db_handles = env.db_handles.borrow();
  467. if db_handles.len() <= db_handle_index {
  468. error!(
  469. target: "runtime::db::db_del",
  470. "[WASM] [{}] db_del(): Requested DbHandle that is out of bounds", cid,
  471. );
  472. return darkfi_sdk::error::DB_DEL_FAILED
  473. }
  474. // Retrive DbHandle using the index
  475. let db_handle = &db_handles[db_handle_index];
  476. // Validate that the DbHandle matches the contract ID
  477. if db_handle.contract_id != cid {
  478. error!(
  479. target: "runtime::db::db_del",
  480. "[WASM] [{}] db_del(): Unauthorized to write to DbHandle", cid,
  481. );
  482. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  483. }
  484. // Remove key-value pair from the database corresponding to this contract
  485. if env.blockchain.lock().unwrap().overlay.lock().unwrap().remove(&db_handle.tree, &key).is_err()
  486. {
  487. error!(
  488. target: "runtime::db::db_del",
  489. "[WASM] [{}] db_del(): Couldn't remove key from db_handle tree", cid,
  490. );
  491. return darkfi_sdk::error::DB_DEL_FAILED
  492. }
  493. darkfi_sdk::entrypoint::SUCCESS
  494. }
  495. /// Reads a value by key from the key-value store.
  496. ///
  497. /// This function can be called from the Deploy, Exec, or Metadata [`ContractSection`].
  498. ///
  499. /// On success, returns the length of the `objects` Vector in the environment.
  500. /// Otherwise, returns an error code.
  501. pub(crate) fn db_get(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  502. let (env, mut store) = ctx.data_and_store_mut();
  503. let cid = env.contract_id;
  504. if let Err(e) =
  505. acl_allow(env, &[ContractSection::Deploy, ContractSection::Exec, ContractSection::Metadata])
  506. {
  507. error!(
  508. target: "runtime::db::db_get",
  509. "[WASM] [{}] db_get(): Called in unauthorized section: {}", cid, e,
  510. );
  511. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  512. }
  513. // Subtract used gas. Here we count the length of the looked-up key.
  514. env.subtract_gas(&mut store, ptr_len as u64);
  515. // Ensure that it is possible to read memory
  516. let memory_view = env.memory_view(&store);
  517. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  518. error!(
  519. target: "runtime::db::db_get",
  520. "[WASM] [{}] db_get(): Failed to make slice from ptr", cid,
  521. );
  522. return darkfi_sdk::error::DB_GET_FAILED
  523. };
  524. let mut buf = vec![0_u8; ptr_len as usize];
  525. if let Err(e) = mem_slice.read_slice(&mut buf) {
  526. error!(
  527. target: "runtime::db::db_get",
  528. "[WASM] [{}] db_get(): Failed to read from memory slice: {}", cid, e,
  529. );
  530. return darkfi_sdk::error::DB_GET_FAILED
  531. };
  532. let mut buf_reader = Cursor::new(buf);
  533. // Decode DbHandle index
  534. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  535. Ok(v) => v,
  536. Err(e) => {
  537. error!(
  538. target: "runtime::db::db_get",
  539. "[WASM] [{}] db_get(): Failed to decode DbHandle: {}", cid, e,
  540. );
  541. return darkfi_sdk::error::DB_GET_FAILED
  542. }
  543. };
  544. let db_handle_index = db_handle_index as usize;
  545. // Decode key for key-value pair that we wish to retrieve
  546. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  547. Ok(v) => v,
  548. Err(e) => {
  549. error!(
  550. target: "runtime::db::db_get",
  551. "[WASM] [{}] db_get(): Failed to decode key from vec: {}", cid, e,
  552. );
  553. return darkfi_sdk::error::DB_GET_FAILED
  554. }
  555. };
  556. // Make sure there are no trailing bytes in the buffer. This means we've used all data that was
  557. // supplied.
  558. if buf_reader.position() != ptr_len as u64 {
  559. error!(
  560. target: "runtime::db::db_get",
  561. "[WASM] [{}] db_get(): Trailing bytes in argument stream", cid,
  562. );
  563. return darkfi_sdk::error::DB_GET_FAILED
  564. }
  565. let db_handles = env.db_handles.borrow();
  566. // Ensure that the index is within bounds
  567. if db_handles.len() <= db_handle_index {
  568. error!(
  569. target: "runtime::db::db_get",
  570. "[WASM] [{}] db_get(): Requested DbHandle that is out of bounds", cid,
  571. );
  572. return darkfi_sdk::error::DB_GET_FAILED
  573. }
  574. // Get DbHandle using db_handle_index
  575. let db_handle = &db_handles[db_handle_index];
  576. // Retrieve data using the `key`
  577. let ret =
  578. match env.blockchain.lock().unwrap().overlay.lock().unwrap().get(&db_handle.tree, &key) {
  579. Ok(v) => v,
  580. Err(e) => {
  581. error!(
  582. target: "runtime::db::db_get",
  583. "[WASM] [{}] db_get(): Internal error getting from tree: {}", cid, e,
  584. );
  585. return darkfi_sdk::error::DB_GET_FAILED
  586. }
  587. };
  588. drop(db_handles);
  589. // Return special error if the data is empty
  590. let Some(return_data) = ret else {
  591. debug!(
  592. target: "runtime::db::db_get",
  593. "[WASM] [{}] db_get(): Return data is empty", cid,
  594. );
  595. return darkfi_sdk::error::DB_GET_EMPTY
  596. };
  597. if return_data.len() > u32::MAX as usize {
  598. return darkfi_sdk::error::DATA_TOO_LARGE
  599. }
  600. // Subtract used gas. Here we count the length of the data read from db.
  601. env.subtract_gas(&mut store, return_data.len() as u64);
  602. // Copy the data (Vec<u8>) to the VM by pushing it to the objects Vector.
  603. let mut objects = env.objects.borrow_mut();
  604. if objects.len() == u32::MAX as usize {
  605. return darkfi_sdk::error::DATA_TOO_LARGE
  606. }
  607. // Return the length of the objects Vector.
  608. // This is the location of the data that was retrieved and pushed
  609. objects.push(return_data.to_vec());
  610. (objects.len() - 1) as i64
  611. }
  612. /// Check if a database contains a given key.
  613. ///
  614. /// Returns `1` if the key is found.
  615. /// Returns `0` if the key is not found and there are no errors.
  616. /// Otherwise, returns an error code.
  617. pub(crate) fn db_contains_key(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  618. let (env, mut store) = ctx.data_and_store_mut();
  619. let cid = env.contract_id;
  620. if let Err(e) =
  621. acl_allow(env, &[ContractSection::Deploy, ContractSection::Exec, ContractSection::Metadata])
  622. {
  623. error!(
  624. target: "runtime::db::db_contains_key",
  625. "[WASM] [{}] db_contains_key(): Called in unauthorized section: {}", cid, e,
  626. );
  627. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  628. }
  629. // Subtract used gas. Here we count the length of the looked-up key.
  630. env.subtract_gas(&mut store, ptr_len as u64);
  631. // Ensure memory is readable
  632. let memory_view = env.memory_view(&store);
  633. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  634. error!(
  635. target: "runtime::db::db_contains_key",
  636. "[WASM] [{}] db_contains_key(): Failed to make slice from ptr", cid,
  637. );
  638. return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
  639. };
  640. let mut buf = vec![0_u8; ptr_len as usize];
  641. if let Err(e) = mem_slice.read_slice(&mut buf) {
  642. error!(
  643. target: "runtime::db::db_contains_key",
  644. "[WASM] [{}] db_contains_key(): Failed to read from memory slice: {}", cid, e,
  645. );
  646. return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
  647. };
  648. let mut buf_reader = Cursor::new(buf);
  649. // Decode DbHandle index
  650. let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
  651. Ok(v) => v,
  652. Err(e) => {
  653. error!(
  654. target: "runtime::db::db_contains_key",
  655. "[WASM] [{}] db_contains_key(): Failed to decode DbHandle: {}", cid, e,
  656. );
  657. return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
  658. }
  659. };
  660. let db_handle_index = db_handle_index as usize;
  661. // Decode key
  662. let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
  663. Ok(v) => v,
  664. Err(e) => {
  665. error!(
  666. target: "runtime::db::db_contains_key",
  667. "[WASM] [{}] db_contains_key(): Failed to decode key vec: {}", cid, e,
  668. );
  669. return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
  670. }
  671. };
  672. // Make sure there are no trailing bytes in the buffer.
  673. // This means we've used all data that was supplied.
  674. if buf_reader.position() != ptr_len as u64 {
  675. error!(
  676. target: "runtime::db::db_contains_key",
  677. "[WASM] [{}] db_contains_key(): Trailing bytes in argument stream", cid,
  678. );
  679. return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
  680. }
  681. let db_handles = env.db_handles.borrow();
  682. // Ensure DbHandle index is within bounds
  683. if db_handles.len() <= db_handle_index {
  684. error!(
  685. target: "runtime::db::db_contains_key",
  686. "[WASM] [{}] db_contains_key(): Requested DbHandle that is out of bounds", cid,
  687. );
  688. return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
  689. }
  690. // Retrieve DbHandle using the index
  691. let db_handle = &db_handles[db_handle_index];
  692. // Lookup key parameter in the database
  693. match env.blockchain.lock().unwrap().overlay.lock().unwrap().contains_key(&db_handle.tree, &key)
  694. {
  695. Ok(v) => i64::from(v), // <- 0=false, 1=true. Convert bool to i64.
  696. Err(e) => {
  697. error!(
  698. target: "runtime::db::db_contains_key",
  699. "[WASM] [{}] db_contains_key(): sled.tree.contains_key failed: {}", cid, e,
  700. );
  701. darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
  702. }
  703. }
  704. }
  705. /// Given a zkas circuit, create a VerifyingKey and insert them both into the db.
  706. ///
  707. /// This function can only be called from the Deploy [`ContractSection`].
  708. /// Returns `SUCCESS` on success, otherwise returns an error code.
  709. pub(crate) fn zkas_db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
  710. let (env, mut store) = ctx.data_and_store_mut();
  711. let cid = env.contract_id;
  712. if let Err(e) = acl_allow(env, &[ContractSection::Deploy]) {
  713. error!(
  714. target: "runtime::db::zkas_db_set",
  715. "[WASM] [{}] zkas_db_set(): Called in unauthorized section: {}", cid, e,
  716. );
  717. return darkfi_sdk::error::CALLER_ACCESS_DENIED
  718. }
  719. // Subtract used gas. Here we count the length read from the memory slice.
  720. env.subtract_gas(&mut store, ptr_len as u64);
  721. let memory_view = env.memory_view(&store);
  722. // Ensure that the memory is readable
  723. let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
  724. error!(
  725. target: "runtime::db::zkas_db_set",
  726. "[WASM] [{}] zkas_db_set(): Failed to make slice from ptr", cid,
  727. );
  728. return darkfi_sdk::error::DB_SET_FAILED
  729. };
  730. let mut buf = vec![0u8; ptr_len as usize];
  731. if let Err(e) = mem_slice.read_slice(&mut buf) {
  732. error!(
  733. target: "runtime::db::zkas_db_set",
  734. "[WASM] [{}] zkas_db_set(): Failed to read from memory slice: {}", cid, e,
  735. );
  736. return darkfi_sdk::error::DB_SET_FAILED
  737. };
  738. // Deserialize the ZkBinary bytes from the buffer
  739. let zkbin_bytes: Vec<u8> = match deserialize(&buf) {
  740. Ok(zkbin) => zkbin,
  741. Err(e) => {
  742. error!(
  743. target: "runtime::db::zkas_db_set",
  744. "[WASM] [{}] zkas_db_set(): Could not deserialize bytes from buffer: {}", cid, e,
  745. );
  746. return darkfi_sdk::error::DB_SET_FAILED
  747. }
  748. };
  749. // Validate the bytes by decoding them into the ZkBinary format
  750. let zkbin = match ZkBinary::decode(&zkbin_bytes) {
  751. Ok(zkbin) => zkbin,
  752. Err(e) => {
  753. error!(
  754. target: "runtime::db::zkas_db_set",
  755. "[WASM] [{}] zkas_db_set(): Invalid zkas bincode passed to function: {}", cid, e,
  756. );
  757. return darkfi_sdk::error::DB_SET_FAILED
  758. }
  759. };
  760. // Subtract used gas. We count 100 gas per opcode, witness, and literal.
  761. // This is likely bad.
  762. // TODO: This should be better-priced.
  763. let gas_cost =
  764. (zkbin.literals.len() + zkbin.witnesses.len() + zkbin.opcodes.len()) as u64 * 100;
  765. env.subtract_gas(&mut store, gas_cost);
  766. // Because of `Runtime::Deploy`, we should be sure that the zkas db is index zero.
  767. let db_handles = env.db_handles.borrow();
  768. let db_handle = &db_handles[0];
  769. // Redundant check
  770. if db_handle.contract_id != cid {
  771. error!(
  772. target: "runtime::db::zkas_db_set",
  773. "[WASM] [{}] zkas_db_set(): Internal error, zkas db at index 0 incorrect", cid,
  774. );
  775. return darkfi_sdk::error::DB_SET_FAILED
  776. }
  777. // Check if there is existing bincode and compare it. Return DB_SUCCESS if
  778. // they're the same. The assumption should be that VerifyingKey was generated
  779. // already so we can skip things after this guard.
  780. match env
  781. .blockchain
  782. .lock()
  783. .unwrap()
  784. .overlay
  785. .lock()
  786. .unwrap()
  787. .get(&db_handle.tree, &serialize(&zkbin.namespace))
  788. {
  789. Ok(v) => {
  790. if let Some(bytes) = v {
  791. // We allow a panic here because this db should never be corrupted in this way.
  792. let (existing_zkbin, _): (Vec<u8>, Vec<u8>) =
  793. deserialize(&bytes).expect("deserialize tuple");
  794. if existing_zkbin == zkbin_bytes {
  795. debug!(
  796. target: "runtime::db::zkas_db_set",
  797. "[WASM] [{}] zkas_db_set(): Existing zkas bincode is the same. Skipping.",
  798. cid,
  799. );
  800. return darkfi_sdk::entrypoint::SUCCESS
  801. }
  802. }
  803. }
  804. Err(e) => {
  805. error!(
  806. target: "runtime::db::zkas_db_set",
  807. "[WASM] [{}] zkas_db_set(): Internal error getting from tree: {}", cid, e,
  808. );
  809. return darkfi_sdk::error::DB_SET_FAILED
  810. }
  811. };
  812. // We didn't find any existing bincode, so let's create a new VerifyingKey and write it all.
  813. info!(
  814. target: "runtime::db::zkas_db_set",
  815. "[WASM] [{}] zkas_db_set(): Creating VerifyingKey for {} zkas circuit",
  816. cid, zkbin.namespace,
  817. );
  818. let witnesses = match empty_witnesses(&zkbin) {
  819. Ok(w) => w,
  820. Err(e) => {
  821. error!(
  822. target: "runtime::db::zkas_db_set",
  823. "[WASM] [{}] zkas_db_set(): Failed to create empty witnesses: {}", cid, e,
  824. );
  825. return darkfi_sdk::error::DB_SET_FAILED
  826. }
  827. };
  828. // Construct the circuit and build the VerifyingKey
  829. let circuit = ZkCircuit::new(witnesses, &zkbin);
  830. let vk = VerifyingKey::build(zkbin.k, &circuit);
  831. let mut vk_buf = vec![];
  832. if let Err(e) = vk.write(&mut vk_buf) {
  833. error!(
  834. target: "runtime::db::zkas_db_set",
  835. "[WASM] [{}] zkas_db_set(): Failed to serialize VerifyingKey: {}", cid, e,
  836. );
  837. return darkfi_sdk::error::DB_SET_FAILED
  838. }
  839. // Insert the key-value pair into the database.
  840. let key = serialize(&zkbin.namespace);
  841. let value = serialize(&(zkbin_bytes, vk_buf));
  842. if env
  843. .blockchain
  844. .lock()
  845. .unwrap()
  846. .overlay
  847. .lock()
  848. .unwrap()
  849. .insert(&db_handle.tree, &key, &value)
  850. .is_err()
  851. {
  852. error!(
  853. target: "runtime::db::zkas_db_set",
  854. "[WASM] [{}] zkas_db_set(): Couldn't insert to db_handle tree", cid,
  855. );
  856. return darkfi_sdk::error::DB_SET_FAILED
  857. }
  858. drop(db_handles);
  859. // Subtract used gas. Here we count the bytes written into the db.
  860. env.subtract_gas(&mut store, (key.len() + value.len()) as u64);
  861. darkfi_sdk::entrypoint::SUCCESS
  862. }