1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 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 */
1819use darkfi_serial::Encodable;
2021use crate::{
22 crypto::ContractId,
23 error::{ContractError, GenericResult},
24 wasm,
25};
2627pub type DbHandle = u32;
2829/// Create a new database instance for the given contract.
30/// This should be called in the `init_contract()` section to create any databases
31/// that the contract might need or use.
32///
33/// Returns a `DbHandle` which provides methods for reading and writing.
34pub fn db_init(contract_id: ContractId, db_name: &str) -> GenericResult<DbHandle> {
35unsafe {
36let mut len = 0;
37let mut buf = vec![];
38 len += contract_id.encode(&mut buf)?;
39 len += db_name.to_string().encode(&mut buf)?;
4041let ret = db_init_(buf.as_ptr(), len as u32);
4243if ret < 0 {
44return Err(ContractError::from(ret))
45 }
4647Ok(ret as u32)
48 }
49}
5051/// Everyone can call this. Assumes that the database already went through `db_init()`.
52pub fn db_lookup(contract_id: ContractId, db_name: &str) -> GenericResult<DbHandle> {
53unsafe {
54let mut len = 0;
55let mut buf = vec![];
56 len += contract_id.encode(&mut buf)?;
57 len += db_name.to_string().encode(&mut buf)?;
5859let ret = db_lookup_(buf.as_ptr(), len as u32);
6061if ret < 0 {
62return Err(ContractError::from(ret))
63 }
6465Ok(ret as u32)
66 }
67}
6869/// Everyone can call this. Will read a key from the key-value store.
70///
71/// ```
72/// value = db_get(db_handle, key);
73/// ```
74pub fn db_get(db_handle: DbHandle, key: &[u8]) -> GenericResult<Option<Vec<u8>>> {
75let mut len = 0;
76let mut buf = vec![];
77 len += db_handle.encode(&mut buf)?;
78 len += key.to_vec().encode(&mut buf)?;
7980let ret = unsafe { db_get_(buf.as_ptr(), len as u32) };
81 wasm::util::parse_ret(ret)
82}
8384/// Everyone can call this. Checks if a key is contained in the key-value store.
85///
86/// ```
87/// if db_contains_key(db_handle, key) {
88/// println!("true");
89/// }
90/// ```
91pub fn db_contains_key(db_handle: DbHandle, key: &[u8]) -> GenericResult<bool> {
92let mut len = 0;
93let mut buf = vec![];
94 len += db_handle.encode(&mut buf)?;
95 len += key.to_vec().encode(&mut buf)?;
9697let ret = unsafe { db_contains_key_(buf.as_ptr(), len as u32) };
9899if ret < 0 {
100return Err(ContractError::from(ret))
101 }
102103match ret {
1040 => Ok(false),
1051 => Ok(true),
106_ => unreachable!(),
107 }
108}
109110/// Only update() can call this. Set a value within the transaction.
111///
112/// ```
113/// db_set(tx_handle, key, value);
114/// ```
115pub fn db_set(db_handle: DbHandle, key: &[u8], value: &[u8]) -> GenericResult<()> {
116// Check entry for tx_handle is not None
117unsafe {
118let mut len = 0;
119let mut buf = vec![];
120 len += db_handle.encode(&mut buf)?;
121 len += key.to_vec().encode(&mut buf)?;
122 len += value.to_vec().encode(&mut buf)?;
123124let ret = db_set_(buf.as_ptr(), len as u32);
125126if ret != wasm::entrypoint::SUCCESS {
127return Err(ContractError::from(ret))
128 }
129130Ok(())
131 }
132}
133134/// Only update() can call this. Removes a key from the db.
135///
136/// ```
137/// db_del(tx_handle, key);
138/// ```
139pub fn db_del(db_handle: DbHandle, key: &[u8]) -> GenericResult<()> {
140// Check entry for tx_handle is not None
141unsafe {
142let mut len = 0;
143let mut buf = vec![];
144 len += db_handle.encode(&mut buf)?;
145 len += key.to_vec().encode(&mut buf)?;
146147let ret = db_del_(buf.as_ptr(), len as u32);
148149if ret != wasm::entrypoint::SUCCESS {
150return Err(ContractError::from(ret))
151 }
152153Ok(())
154 }
155}
156157/// Only deploy() can call this.
158pub fn zkas_db_set(bincode: &[u8]) -> GenericResult<()> {
159unsafe {
160let mut len = 0;
161let mut buf = vec![];
162 len += bincode.to_vec().encode(&mut buf)?;
163164let ret = zkas_db_set_(buf.as_ptr(), len as u32);
165166if ret != wasm::entrypoint::SUCCESS {
167return Err(ContractError::from(ret))
168 }
169170Ok(())
171 }
172}
173174extern "C" {
175fn db_init_(ptr: *const u8, len: u32) -> i64;
176fn db_lookup_(ptr: *const u8, len: u32) -> i64;
177fn db_get_(ptr: *const u8, len: u32) -> i64;
178fn db_contains_key_(ptr: *const u8, len: u32) -> i64;
179fn db_set_(ptr: *const u8, len: u32) -> i64;
180fn db_del_(ptr: *const u8, len: u32) -> i64;
181182fn zkas_db_set_(ptr: *const u8, len: u32) -> i64;
183}