1use std::io::Cursor;
20
21use darkfi_sdk::{
22 crypto::contract_id::{
23 ContractId, SMART_CONTRACT_MONOTREE_DB_NAME, SMART_CONTRACT_ZKAS_DB_NAME,
24 },
25 wasm,
26};
27use darkfi_serial::{deserialize, serialize, Decodable};
28use tracing::{debug, error, info};
29use wasmer::{FunctionEnvMut, WasmPtr};
30
31use super::acl::acl_allow;
32use crate::{
33 runtime::vm_runtime::{ContractSection, Env},
34 zk::{empty_witnesses, VerifyingKey, ZkCircuit},
35 zkas::ZkBinary,
36};
37
38#[derive(PartialEq)]
40pub struct DbHandle {
41 pub contract_id: ContractId,
42 pub tree: [u8; 32],
43}
44
45impl DbHandle {
46 pub fn new(contract_id: ContractId, tree: [u8; 32]) -> Self {
47 Self { contract_id, tree }
48 }
49}
50
51pub(crate) fn db_init(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_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::Deploy]) {
66 error!(
67 target: "runtime::db::db_init",
68 "[WASM] [{cid}] db_init(): Called in unauthorized section: {e}"
69 );
70 return darkfi_sdk::error::CALLER_ACCESS_DENIED
71 }
72
73 env.subtract_gas(&mut store, 1);
76
77 let contracts = &env.blockchain.lock().unwrap().contracts;
79
80 let memory_view = env.memory_view(&store);
82 let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
83 error!(
84 target: "runtime::db::db_init",
85 "[WASM] [{cid}] db_init(): Failed to make slice from ptr"
86 );
87 return darkfi_sdk::error::DB_INIT_FAILED
88 };
89
90 let mut buf = vec![0_u8; ptr_len as usize];
92 if let Err(e) = mem_slice.read_slice(&mut buf) {
93 error!(
94 target: "runtime::db::db_init",
95 "[WASM] [{cid}] db_init(): Failed to read memory slice: {e}"
96 );
97 return darkfi_sdk::error::DB_INIT_FAILED
98 };
99
100 let mut buf_reader = Cursor::new(buf);
103 let read_cid: ContractId = match Decodable::decode(&mut buf_reader) {
104 Ok(v) => v,
105 Err(e) => {
106 error!(
107 target: "runtime::db::db_init",
108 "[WASM] [{cid}] db_init(): Failed decoding ContractId: {e}"
109 );
110 return darkfi_sdk::error::DB_INIT_FAILED
111 }
112 };
113
114 let read_db_name: String = match Decodable::decode(&mut buf_reader) {
115 Ok(v) => v,
116 Err(e) => {
117 error!(
118 target: "runtime::db::db_init",
119 "[WASM] [{cid}] db_init(): Failed decoding db_name: {e}"
120 );
121 return darkfi_sdk::error::DB_INIT_FAILED
122 }
123 };
124
125 if buf_reader.position() != ptr_len as u64 {
127 error!(
128 target: "runtime::db::db_init",
129 "[WASM] [{cid}] db_init(): Trailing bytes in argument stream"
130 );
131 return darkfi_sdk::error::DB_INIT_FAILED
132 }
133
134 if read_db_name == SMART_CONTRACT_ZKAS_DB_NAME {
136 error!(
137 target: "runtime::db::db_init",
138 "[WASM] [{cid}] db_init(): Attempted to init zkas db"
139 );
140 return darkfi_sdk::error::CALLER_ACCESS_DENIED
141 }
142
143 if read_db_name == SMART_CONTRACT_MONOTREE_DB_NAME {
145 error!(
146 target: "runtime::db::db_init",
147 "[WASM] [{cid}] db_init(): Attempted to init monotree db"
148 );
149 return darkfi_sdk::error::CALLER_ACCESS_DENIED
150 }
151
152 if cid != read_cid {
154 error!(
155 target: "runtime::db::db_init",
156 "[WASM] [{cid}] db_init(): Unauthorized ContractId"
157 );
158 return darkfi_sdk::error::CALLER_ACCESS_DENIED
159 }
160
161 let tree_handle = match contracts.init(&read_cid, &read_db_name) {
168 Ok(v) => v,
169 Err(e) => {
170 error!(
171 target: "runtime::db::db_init",
172 "[WASM] [{cid}] db_init(): Failed to init db: {e}"
173 );
174 return darkfi_sdk::error::DB_INIT_FAILED
175 }
176 };
177
178 let db_handle = DbHandle::new(read_cid, tree_handle);
180 let mut db_handles = env.db_handles.borrow_mut();
181
182 if db_handles.contains(&db_handle) {
185 error!(
186 target: "runtime::db::db_init",
187 "[WASM] [{cid}] db_init(): DbHandle initialized twice during execution"
188 );
189 return darkfi_sdk::error::DB_INIT_FAILED
190 }
191
192 match db_handles.len().try_into() {
194 Ok(db_handle_idx) => {
195 db_handles.push(db_handle);
196 db_handle_idx
198 }
199 Err(_) => {
200 error!(
201 target: "runtime::db::db_init",
202 "[WASM] [{cid}] db_init(): Too many open DbHandles"
203 );
204 darkfi_sdk::error::DB_INIT_FAILED
205 }
206 }
207}
208
209pub(crate) fn db_lookup(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
219 let (env, mut store) = ctx.data_and_store_mut();
220 let cid = env.contract_id;
221
222 if let Err(e) = acl_allow(
224 env,
225 &[
226 ContractSection::Deploy,
227 ContractSection::Metadata,
228 ContractSection::Exec,
229 ContractSection::Update,
230 ],
231 ) {
232 error!(
233 target: "runtime::db::db_lookup",
234 "[WASM] [{cid}] db_lookup() called in unauthorized section: {e}"
235 );
236 return darkfi_sdk::error::CALLER_ACCESS_DENIED
237 }
238
239 env.subtract_gas(&mut store, 1);
241
242 let memory_view = env.memory_view(&store);
244 let contracts = &env.blockchain.lock().unwrap().contracts;
245
246 let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
247 error!(
248 target: "runtime::db::db_lookup",
249 "[WASM] [{cid}] db_lookup(): Failed to make slice from ptr."
250 );
251 return darkfi_sdk::error::DB_LOOKUP_FAILED
252 };
253
254 let mut buf = vec![0_u8; ptr_len as usize];
255 if let Err(e) = mem_slice.read_slice(&mut buf) {
256 error!(
257 target: "runtime::db::db_lookup",
258 "[WASM] [{cid}] db_lookup(): Failed to read from memory slice: {e}"
259 );
260 return darkfi_sdk::error::DB_LOOKUP_FAILED
261 };
262
263 let mut buf_reader = Cursor::new(buf);
265
266 let cid: ContractId = match Decodable::decode(&mut buf_reader) {
268 Ok(v) => v,
269 Err(e) => {
270 error!(
271 target: "runtime::db::db_lookup",
272 "[WASM] [{cid}] db_lookup(): Failed to decode ContractId: {e}"
273 );
274 return darkfi_sdk::error::DB_LOOKUP_FAILED
275 }
276 };
277
278 let db_name: String = match Decodable::decode(&mut buf_reader) {
280 Ok(v) => v,
281 Err(e) => {
282 error!(
283 target: "runtime::db::db_lookup",
284 "[WASM] [{cid}] db_lookup(): Failed to decode db_name: {e}"
285 );
286 return darkfi_sdk::error::DB_LOOKUP_FAILED
287 }
288 };
289
290 if buf_reader.position() != ptr_len as u64 {
292 error!(
293 target: "runtime::db::db_lookup",
294 "[WASM] [{cid}] db_lookup(), Trailing bytes in argument stream"
295 );
296 return darkfi_sdk::error::DB_LOOKUP_FAILED
297 }
298
299 if db_name == SMART_CONTRACT_ZKAS_DB_NAME {
300 error!(
301 target: "runtime::db::db_lookup",
302 "[WASM] [{cid}] db_lookup(): Attempted to lookup zkas db"
303 );
304 return darkfi_sdk::error::CALLER_ACCESS_DENIED
305 }
306
307 if db_name == SMART_CONTRACT_MONOTREE_DB_NAME {
308 error!(
309 target: "runtime::db::db_lookup",
310 "[WASM] [{cid}] db_lookup(): Attempted to lookup monotree db"
311 );
312 return darkfi_sdk::error::CALLER_ACCESS_DENIED
313 }
314
315 let tree_handle = match contracts.lookup(&cid, &db_name) {
317 Ok(v) => v,
318 Err(_) => return darkfi_sdk::error::DB_LOOKUP_FAILED,
319 };
320
321 let db_handle = DbHandle::new(cid, tree_handle);
323 let mut db_handles = env.db_handles.borrow_mut();
324
325 if let Some(index) = db_handles.iter().position(|x| x == &db_handle) {
327 return index as i64
328 }
329
330 match db_handles.len().try_into() {
332 Ok(db_handle_idx) => {
333 db_handles.push(db_handle);
334 db_handle_idx
335 }
336 Err(_) => {
337 error!(
338 target: "runtime::db::db_lookup",
339 "[WASM] [{cid}] db_lookup(): Too many open DbHandles"
340 );
341 darkfi_sdk::error::DB_LOOKUP_FAILED
342 }
343 }
344}
345
346pub(crate) fn db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
356 let (env, mut store) = ctx.data_and_store_mut();
357 let cid = env.contract_id;
358
359 if let Err(e) = acl_allow(env, &[ContractSection::Deploy, ContractSection::Update]) {
360 error!(
361 target: "runtime::db::db_set",
362 "[WASM] [{cid}] db_set(): Called in unauthorized section: {e}"
363 );
364 return darkfi_sdk::error::CALLER_ACCESS_DENIED
365 }
366
367 env.subtract_gas(&mut store, ptr_len as u64);
371
372 let memory_view = env.memory_view(&store);
374 let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
375 error!(
376 target: "runtime::db::db_set",
377 "[WASM] [{cid}] db_set(): Failed to make slice from ptr"
378 );
379 return darkfi_sdk::error::DB_SET_FAILED
380 };
381
382 let mut buf = vec![0_u8; ptr_len as usize];
383 if let Err(e) = mem_slice.read_slice(&mut buf) {
384 error!(
385 target: "runtime::db::db_set",
386 "[WASM] [{cid}] db_set(): Failed to read from memory slice: {e}"
387 );
388 return darkfi_sdk::error::DB_SET_FAILED
389 };
390
391 let mut buf_reader = Cursor::new(buf);
392
393 let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
395 Ok(v) => v,
396 Err(e) => {
397 error!(
398 target: "runtime::db::db_set",
399 "[WASM] [{cid}] db_set(): Failed to decode DbHandle: {e}"
400 );
401 return darkfi_sdk::error::DB_SET_FAILED
402 }
403 };
404
405 let db_handle_index = db_handle_index as usize;
406
407 let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
409 Ok(v) => v,
410 Err(e) => {
411 error!(
412 target: "runtime::db::db_set",
413 "[WASM] [{cid}] db_set(): Failed to decode key vec: {e}"
414 );
415 return darkfi_sdk::error::DB_SET_FAILED
416 }
417 };
418
419 let value: Vec<u8> = match Decodable::decode(&mut buf_reader) {
420 Ok(v) => v,
421 Err(e) => {
422 error!(
423 target: "runtime::db::db_set",
424 "[WASM] [{cid}] db_set(): Failed to decode value vec: {e}"
425 );
426 return darkfi_sdk::error::DB_SET_FAILED
427 }
428 };
429
430 if buf_reader.position() != ptr_len as u64 {
432 error!(
433 target: "runtime::db::db_set",
434 "[WASM] [{cid}] db_set(): Trailing bytes in argument stream"
435 );
436 return darkfi_sdk::error::DB_SET_FAILED
437 }
438
439 let db_handles = env.db_handles.borrow();
440
441 if db_handles.len() <= db_handle_index {
443 error!(
444 target: "runtime::db::db_set",
445 "[WASM] [{cid}] db_set(): Requested DbHandle that is out of bounds"
446 );
447 return darkfi_sdk::error::DB_SET_FAILED
448 }
449
450 let db_handle = &db_handles[db_handle_index];
452
453 if db_handle.contract_id != env.contract_id {
455 error!(
456 target: "runtime::db::db_set",
457 "[WASM] [{cid}] db_set(): Unauthorized to write to DbHandle"
458 );
459 return darkfi_sdk::error::CALLER_ACCESS_DENIED
460 }
461
462 if env
464 .blockchain
465 .lock()
466 .unwrap()
467 .overlay
468 .lock()
469 .unwrap()
470 .insert(&db_handle.tree, &key, &value)
471 .is_err()
472 {
473 error!(
474 target: "runtime::db::db_set",
475 "[WASM] [{cid}] db_set(): Couldn't insert to db_handle tree"
476 );
477 return darkfi_sdk::error::DB_SET_FAILED
478 }
479
480 wasm::entrypoint::SUCCESS
481}
482
483pub(crate) fn db_del(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
490 let (env, mut store) = ctx.data_and_store_mut();
491 let cid = env.contract_id;
492
493 if let Err(e) = acl_allow(env, &[ContractSection::Deploy, ContractSection::Update]) {
494 error!(
495 target: "runtime::db::db_del",
496 "[WASM] [{cid}] db_del(): Called in unauthorized section: {e}"
497 );
498 return darkfi_sdk::error::CALLER_ACCESS_DENIED
499 }
500
501 env.subtract_gas(&mut store, 1);
503
504 let memory_view = env.memory_view(&store);
506
507 let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
508 error!(
509 target: "runtime::db::db_del",
510 "[WASM] [{cid}] db_del(): Failed to make slice from ptr"
511 );
512 return darkfi_sdk::error::DB_DEL_FAILED
513 };
514
515 let mut buf = vec![0_u8; ptr_len as usize];
516 if let Err(e) = mem_slice.read_slice(&mut buf) {
517 error!(
518 target: "runtime::db::db_del",
519 "[WASM] [{cid}] db_del(): Failed to read from memory slice: {e}"
520 );
521 return darkfi_sdk::error::DB_DEL_FAILED
522 };
523
524 let mut buf_reader = Cursor::new(buf);
525
526 let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
528 Ok(v) => v,
529 Err(e) => {
530 error!(
531 target: "runtime::db::db_del",
532 "[WASM] [{cid}] db_del(): Failed to decode DbHandle: {e}"
533 );
534 return darkfi_sdk::error::DB_DEL_FAILED
535 }
536 };
537 let db_handle_index = db_handle_index as usize;
538
539 let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
541 Ok(v) => v,
542 Err(e) => {
543 error!(
544 target: "runtime::db::db_del",
545 "[WASM] [{cid}] db_del(): Failed to decode key vec: {e}"
546 );
547 return darkfi_sdk::error::DB_DEL_FAILED
548 }
549 };
550
551 if buf_reader.position() != ptr_len as u64 {
553 error!(
554 target: "runtime::db::db_del",
555 "[WASM] [{cid}] db_del(): Trailing bytes in argument stream"
556 );
557 return darkfi_sdk::error::DB_DEL_FAILED
558 }
559
560 let db_handles = env.db_handles.borrow();
561
562 if db_handles.len() <= db_handle_index {
563 error!(
564 target: "runtime::db::db_del",
565 "[WASM] [{cid}] db_del(): Requested DbHandle that is out of bounds"
566 );
567 return darkfi_sdk::error::DB_DEL_FAILED
568 }
569
570 let db_handle = &db_handles[db_handle_index];
572
573 if db_handle.contract_id != cid {
575 error!(
576 target: "runtime::db::db_del",
577 "[WASM] [{cid}] db_del(): Unauthorized to write to DbHandle"
578 );
579 return darkfi_sdk::error::CALLER_ACCESS_DENIED
580 }
581
582 if env.blockchain.lock().unwrap().overlay.lock().unwrap().remove(&db_handle.tree, &key).is_err()
584 {
585 error!(
586 target: "runtime::db::db_del",
587 "[WASM] [{cid}] db_del(): Couldn't remove key from db_handle tree"
588 );
589 return darkfi_sdk::error::DB_DEL_FAILED
590 }
591
592 wasm::entrypoint::SUCCESS
593}
594
595pub(crate) fn db_get(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
604 let (env, mut store) = ctx.data_and_store_mut();
605 let cid = env.contract_id;
606
607 if let Err(e) =
608 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
609 {
610 error!(
611 target: "runtime::db::db_get",
612 "[WASM] [{cid}] db_get(): Called in unauthorized section: {e}"
613 );
614 return darkfi_sdk::error::CALLER_ACCESS_DENIED
615 }
616
617 env.subtract_gas(&mut store, 1);
619
620 let memory_view = env.memory_view(&store);
622 let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
623 error!(
624 target: "runtime::db::db_get",
625 "[WASM] [{cid}] db_get(): Failed to make slice from ptr"
626 );
627 return darkfi_sdk::error::DB_GET_FAILED
628 };
629
630 let mut buf = vec![0_u8; ptr_len as usize];
631 if let Err(e) = mem_slice.read_slice(&mut buf) {
632 error!(
633 target: "runtime::db::db_get",
634 "[WASM] [{cid}] db_get(): Failed to read from memory slice: {e}"
635 );
636 return darkfi_sdk::error::DB_GET_FAILED
637 };
638
639 let mut buf_reader = Cursor::new(buf);
640
641 let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
643 Ok(v) => v,
644 Err(e) => {
645 error!(
646 target: "runtime::db::db_get",
647 "[WASM] [{cid}] db_get(): Failed to decode DbHandle: {e}"
648 );
649 return darkfi_sdk::error::DB_GET_FAILED
650 }
651 };
652
653 let db_handle_index = db_handle_index as usize;
654
655 let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
657 Ok(v) => v,
658 Err(e) => {
659 error!(
660 target: "runtime::db::db_get",
661 "[WASM] [{cid}] db_get(): Failed to decode key from vec: {e}"
662 );
663 return darkfi_sdk::error::DB_GET_FAILED
664 }
665 };
666
667 if buf_reader.position() != ptr_len as u64 {
670 error!(
671 target: "runtime::db::db_get",
672 "[WASM] [{cid}] db_get(): Trailing bytes in argument stream"
673 );
674 return darkfi_sdk::error::DB_GET_FAILED
675 }
676
677 let db_handles = env.db_handles.borrow();
678
679 if db_handles.len() <= db_handle_index {
681 error!(
682 target: "runtime::db::db_get",
683 "[WASM] [{cid}] db_get(): Requested DbHandle that is out of bounds"
684 );
685 return darkfi_sdk::error::DB_GET_FAILED
686 }
687
688 let db_handle = &db_handles[db_handle_index];
690
691 let ret =
693 match env.blockchain.lock().unwrap().overlay.lock().unwrap().get(&db_handle.tree, &key) {
694 Ok(v) => v,
695 Err(e) => {
696 error!(
697 target: "runtime::db::db_get",
698 "[WASM] [{cid}] db_get(): Internal error getting from tree: {e}"
699 );
700 return darkfi_sdk::error::DB_GET_FAILED
701 }
702 };
703 drop(db_handles);
704
705 let Some(return_data) = ret else {
707 debug!(
708 target: "runtime::db::db_get",
709 "[WASM] [{cid}] db_get(): Return data is empty"
710 );
711 return darkfi_sdk::error::DB_GET_EMPTY
712 };
713
714 if return_data.len() > u32::MAX as usize {
715 return darkfi_sdk::error::DATA_TOO_LARGE
716 }
717
718 env.subtract_gas(&mut store, return_data.len() as u64);
720
721 let mut objects = env.objects.borrow_mut();
723 if objects.len() == u32::MAX as usize {
724 return darkfi_sdk::error::DATA_TOO_LARGE
725 }
726
727 objects.push(return_data.to_vec());
730 (objects.len() - 1) as i64
731}
732
733pub(crate) fn db_contains_key(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
741 let (env, mut store) = ctx.data_and_store_mut();
742 let cid = env.contract_id;
743
744 if let Err(e) =
745 acl_allow(env, &[ContractSection::Deploy, ContractSection::Metadata, ContractSection::Exec])
746 {
747 error!(
748 target: "runtime::db::db_contains_key",
749 "[WASM] [{cid}] db_contains_key(): Called in unauthorized section: {e}"
750 );
751 return darkfi_sdk::error::CALLER_ACCESS_DENIED
752 }
753
754 env.subtract_gas(&mut store, 1);
756
757 let memory_view = env.memory_view(&store);
759 let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
760 error!(
761 target: "runtime::db::db_contains_key",
762 "[WASM] [{cid}] db_contains_key(): Failed to make slice from ptr"
763 );
764 return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
765 };
766
767 let mut buf = vec![0_u8; ptr_len as usize];
768 if let Err(e) = mem_slice.read_slice(&mut buf) {
769 error!(
770 target: "runtime::db::db_contains_key",
771 "[WASM] [{cid}] db_contains_key(): Failed to read from memory slice: {e}"
772 );
773 return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
774 };
775
776 let mut buf_reader = Cursor::new(buf);
777
778 let db_handle_index: u32 = match Decodable::decode(&mut buf_reader) {
780 Ok(v) => v,
781 Err(e) => {
782 error!(
783 target: "runtime::db::db_contains_key",
784 "[WASM] [{cid}] db_contains_key(): Failed to decode DbHandle: {e}"
785 );
786 return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
787 }
788 };
789
790 let db_handle_index = db_handle_index as usize;
791
792 let key: Vec<u8> = match Decodable::decode(&mut buf_reader) {
794 Ok(v) => v,
795 Err(e) => {
796 error!(
797 target: "runtime::db::db_contains_key",
798 "[WASM] [{cid}] db_contains_key(): Failed to decode key vec: {e}"
799 );
800 return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
801 }
802 };
803
804 if buf_reader.position() != ptr_len as u64 {
807 error!(
808 target: "runtime::db::db_contains_key",
809 "[WASM] [{cid}] db_contains_key(): Trailing bytes in argument stream"
810 );
811 return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
812 }
813
814 let db_handles = env.db_handles.borrow();
815
816 if db_handles.len() <= db_handle_index {
818 error!(
819 target: "runtime::db::db_contains_key",
820 "[WASM] [{cid}] db_contains_key(): Requested DbHandle that is out of bounds"
821 );
822 return darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
823 }
824
825 let db_handle = &db_handles[db_handle_index];
827
828 match env.blockchain.lock().unwrap().overlay.lock().unwrap().contains_key(&db_handle.tree, &key)
830 {
831 Ok(v) => i64::from(v), Err(e) => {
833 error!(
834 target: "runtime::db::db_contains_key",
835 "[WASM] [{cid}] db_contains_key(): sled.tree.contains_key failed: {e}"
836 );
837 darkfi_sdk::error::DB_CONTAINS_KEY_FAILED
838 }
839 }
840}
841
842pub(crate) fn zkas_db_set(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, ptr_len: u32) -> i64 {
849 let (env, mut store) = ctx.data_and_store_mut();
850 let cid = env.contract_id;
851
852 if let Err(e) = acl_allow(env, &[ContractSection::Deploy]) {
853 error!(
854 target: "runtime::db::zkas_db_set",
855 "[WASM] [{cid}] zkas_db_set(): Called in unauthorized section: {e}"
856 );
857 return darkfi_sdk::error::CALLER_ACCESS_DENIED
858 }
859
860 let memory_view = env.memory_view(&store);
861
862 let Ok(mem_slice) = ptr.slice(&memory_view, ptr_len) else {
864 error!(
865 target: "runtime::db::zkas_db_set",
866 "[WASM] [{cid}] zkas_db_set(): Failed to make slice from ptr"
867 );
868 return darkfi_sdk::error::DB_SET_FAILED
869 };
870
871 let mut buf = vec![0u8; ptr_len as usize];
872 if let Err(e) = mem_slice.read_slice(&mut buf) {
873 error!(
874 target: "runtime::db::zkas_db_set",
875 "[WASM] [{cid}] zkas_db_set(): Failed to read from memory slice: {e}"
876 );
877 return darkfi_sdk::error::DB_SET_FAILED
878 };
879
880 let zkbin_bytes: Vec<u8> = match deserialize(&buf) {
882 Ok(zkbin) => zkbin,
883 Err(e) => {
884 error!(
885 target: "runtime::db::zkas_db_set",
886 "[WASM] [{cid}] zkas_db_set(): Could not deserialize bytes from buffer: {e}"
887 );
888 return darkfi_sdk::error::DB_SET_FAILED
889 }
890 };
891
892 let zkbin = match ZkBinary::decode(&zkbin_bytes, false) {
894 Ok(zkbin) => zkbin,
895 Err(e) => {
896 error!(
897 target: "runtime::db::zkas_db_set",
898 "[WASM] [{cid}] zkas_db_set(): Invalid zkas bincode passed to function: {e}"
899 );
900 return darkfi_sdk::error::DB_SET_FAILED
901 }
902 };
903
904 let gas_cost =
908 (zkbin.literals.len() + zkbin.witnesses.len() + zkbin.opcodes.len()) as u64 * 100;
909 env.subtract_gas(&mut store, gas_cost);
910
911 let db_handles = env.db_handles.borrow();
913 let db_handle = &db_handles[0];
914 if db_handle.contract_id != cid {
916 error!(
917 target: "runtime::db::zkas_db_set",
918 "[WASM] [{cid}] zkas_db_set(): Internal error, zkas db at index 0 incorrect"
919 );
920 return darkfi_sdk::error::DB_SET_FAILED
921 }
922
923 match env
927 .blockchain
928 .lock()
929 .unwrap()
930 .overlay
931 .lock()
932 .unwrap()
933 .get(&db_handle.tree, &serialize(&zkbin.namespace))
934 {
935 Ok(v) => {
936 if let Some(bytes) = v {
937 let (existing_zkbin, _): (Vec<u8>, Vec<u8>) =
939 deserialize(&bytes).expect("deserialize tuple");
940
941 if existing_zkbin == zkbin_bytes {
942 debug!(
943 target: "runtime::db::zkas_db_set",
944 "[WASM] [{cid}] zkas_db_set(): Existing zkas bincode is the same. Skipping."
945 );
946 return wasm::entrypoint::SUCCESS
947 }
948 }
949 }
950 Err(e) => {
951 error!(
952 target: "runtime::db::zkas_db_set",
953 "[WASM] [{cid}] zkas_db_set(): Internal error getting from tree: {e}"
954 );
955 return darkfi_sdk::error::DB_SET_FAILED
956 }
957 };
958
959 info!(
961 target: "runtime::db::zkas_db_set",
962 "[WASM] [{cid}] zkas_db_set(): Creating VerifyingKey for {} zkas circuit",
963 zkbin.namespace,
964 );
965
966 let witnesses = match empty_witnesses(&zkbin) {
967 Ok(w) => w,
968 Err(e) => {
969 error!(
970 target: "runtime::db::zkas_db_set",
971 "[WASM] [{cid}] zkas_db_set(): Failed to create empty witnesses: {e}"
972 );
973 return darkfi_sdk::error::DB_SET_FAILED
974 }
975 };
976
977 let circuit = ZkCircuit::new(witnesses, &zkbin);
979 let vk = VerifyingKey::build(zkbin.k, &circuit);
980 let mut vk_buf = vec![];
981 if let Err(e) = vk.write(&mut vk_buf) {
982 error!(
983 target: "runtime::db::zkas_db_set",
984 "[WASM] [{cid}] zkas_db_set(): Failed to serialize VerifyingKey: {e}"
985 );
986 return darkfi_sdk::error::DB_SET_FAILED
987 }
988
989 let key = serialize(&zkbin.namespace);
991 let value = serialize(&(zkbin_bytes, vk_buf));
992 if env
993 .blockchain
994 .lock()
995 .unwrap()
996 .overlay
997 .lock()
998 .unwrap()
999 .insert(&db_handle.tree, &key, &value)
1000 .is_err()
1001 {
1002 error!(
1003 target: "runtime::db::zkas_db_set",
1004 "[WASM] [{cid}] zkas_db_set(): Couldn't insert to db_handle tree"
1005 );
1006 return darkfi_sdk::error::DB_SET_FAILED
1007 }
1008 drop(db_handles);
1009
1010 env.subtract_gas(&mut store, (key.len() + value.len()) as u64);
1012
1013 wasm::entrypoint::SUCCESS
1014}