db.rs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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 darkfi_serial::Encodable;
  19. use crate::{
  20. crypto::ContractId,
  21. error::{ContractError, GenericResult},
  22. wasm,
  23. };
  24. pub type DbHandle = u32;
  25. /// Create a new on-chain database instance for the given contract.
  26. /// A contract is only able to create a db for itself.
  27. ///
  28. /// Returns a `DbHandle` which provides methods for reading and writing.
  29. ///
  30. /// ## Permissions
  31. /// * `ContractSection::Deploy`
  32. pub fn db_init(contract_id: ContractId, db_name: &str) -> GenericResult<DbHandle> {
  33. let mut len = 0;
  34. let mut buf = vec![];
  35. len += contract_id.encode(&mut buf)?;
  36. len += db_name.to_string().encode(&mut buf)?;
  37. let ret = unsafe { db_init_(buf.as_ptr(), len as u32) };
  38. if ret < 0 {
  39. return Err(ContractError::from(ret))
  40. }
  41. Ok(ret as u32)
  42. }
  43. /// Open an existing on-chain database instance for the given contract.
  44. /// A contract is able to read any on-chain database.
  45. ///
  46. /// Returns a `DbHandle` which is used with methods for reading and writing.
  47. ///
  48. /// ## Permissions
  49. /// * `ContractSection::Deploy`
  50. /// * `ContractSection::Metadata`
  51. /// * `ContractSection::Exec`
  52. /// * `ContractSection::Update`
  53. pub fn db_lookup(contract_id: ContractId, db_name: &str) -> GenericResult<DbHandle> {
  54. db_lookup_internal(contract_id, db_name, false)
  55. }
  56. /// Open a tx-local database instance for the given contract.
  57. /// A contract is able to read any tx-local database.
  58. ///
  59. /// If the calling contract is opening its own db, the db will be created
  60. /// and initialized in-memory.
  61. ///
  62. /// Returns a `DbHandle` which is used with methods for reading and writing.
  63. ///
  64. /// ## Permissions
  65. /// * `ContractSection::Deploy`
  66. /// * `ContractSection::Metadata`
  67. /// * `ContractSection::Exec`
  68. /// * `ContractSection::Update`
  69. pub fn db_lookup_local(contract_id: ContractId, db_name: &str) -> GenericResult<DbHandle> {
  70. db_lookup_internal(contract_id, db_name, true)
  71. }
  72. /// Internal function for `db_lookup` which branches to either on-chain or
  73. /// transaction-local.
  74. fn db_lookup_internal(
  75. contract_id: ContractId,
  76. db_name: &str,
  77. local: bool,
  78. ) -> GenericResult<DbHandle> {
  79. let mut len = 0;
  80. let mut buf = vec![];
  81. len += contract_id.encode(&mut buf)?;
  82. len += db_name.to_string().encode(&mut buf)?;
  83. let ret = unsafe {
  84. if local {
  85. db_lookup_local_(buf.as_ptr(), len as u32)
  86. } else {
  87. db_lookup_(buf.as_ptr(), len as u32)
  88. }
  89. };
  90. if ret < 0 {
  91. return Err(ContractError::from(ret))
  92. }
  93. Ok(ret as u32)
  94. }
  95. /// Read a key from the on-chain key-value store given a `DbHandle` and `key`.
  96. ///
  97. /// Returns the `Vec<u8>` value if the key exists, otherwise `None`.
  98. ///
  99. /// ## Permissions
  100. /// * `ContractSection::Deploy`
  101. /// * `ContractSection::Metadata`
  102. /// * `ContractSection::Exec`
  103. pub fn db_get(db_handle: DbHandle, key: &[u8]) -> GenericResult<Option<Vec<u8>>> {
  104. db_get_internal(db_handle, key, false)
  105. }
  106. /// Read a key from the tx-local key-value store given a `DbHandle` and `key`.
  107. ///
  108. /// Returns the `Vec<u8>` value if the key exists, otherwise `None`.
  109. ///
  110. /// ## Permissions
  111. /// * `ContractSection::Deploy`
  112. /// * `ContractSection::Metadata`
  113. /// * `ContractSection::Exec`
  114. pub fn db_get_local(db_handle: DbHandle, key: &[u8]) -> GenericResult<Option<Vec<u8>>> {
  115. db_get_internal(db_handle, key, true)
  116. }
  117. /// Internal function for `db_get` which branches to either on-chain or
  118. /// transaction-local.
  119. fn db_get_internal(db_handle: DbHandle, key: &[u8], local: bool) -> GenericResult<Option<Vec<u8>>> {
  120. let mut len = 0;
  121. let mut buf = vec![];
  122. len += db_handle.encode(&mut buf)?;
  123. len += key.encode(&mut buf)?;
  124. let ret = unsafe {
  125. if local {
  126. db_get_local_(buf.as_ptr(), len as u32)
  127. } else {
  128. db_get_(buf.as_ptr(), len as u32)
  129. }
  130. };
  131. wasm::util::parse_ret(ret)
  132. }
  133. /// Check if a key is contained in the on-chain key-value store given a
  134. /// `DbHandle` and `key`.
  135. ///
  136. /// Returns a boolean value.
  137. ///
  138. /// ## Permissions
  139. /// * `ContractSection::Deploy`
  140. /// * `ContractSection::Metadata`
  141. /// * `ContractSection::Exec`
  142. pub fn db_contains_key(db_handle: DbHandle, key: &[u8]) -> GenericResult<bool> {
  143. db_contains_key_internal(db_handle, key, false)
  144. }
  145. /// Check if a key is contained in the tx-local key-value store given a
  146. /// `DbHandle` and `key`.
  147. ///
  148. /// Returns a boolean value.
  149. ///
  150. /// ## Permissions
  151. /// * `ContractSection::Deploy`
  152. /// * `ContractSection::Metadata`
  153. /// * `ContractSection::Exec`
  154. pub fn db_contains_key_local(db_handle: DbHandle, key: &[u8]) -> GenericResult<bool> {
  155. db_contains_key_internal(db_handle, key, true)
  156. }
  157. /// Internal function for `db_contains_key` which branches to either on-chain
  158. /// or transaction-local.
  159. fn db_contains_key_internal(db_handle: DbHandle, key: &[u8], local: bool) -> GenericResult<bool> {
  160. let mut len = 0;
  161. let mut buf = vec![];
  162. len += db_handle.encode(&mut buf)?;
  163. len += key.encode(&mut buf)?;
  164. let ret = unsafe {
  165. if local {
  166. db_contains_key_local_(buf.as_ptr(), len as u32)
  167. } else {
  168. db_contains_key_(buf.as_ptr(), len as u32)
  169. }
  170. };
  171. if ret < 0 {
  172. return Err(ContractError::from(ret))
  173. }
  174. match ret {
  175. 0 => Ok(false),
  176. 1 => Ok(true),
  177. _ => unreachable!(),
  178. }
  179. }
  180. /// Set a key and value in the on-chain database for the given `DbHandle`.
  181. ///
  182. /// Returns `Ok` on success.
  183. ///
  184. /// ## Permissions
  185. /// * `ContractSection::Deploy`
  186. /// * `ContractSection::Update`
  187. pub fn db_set(db_handle: DbHandle, key: &[u8], value: &[u8]) -> GenericResult<()> {
  188. db_set_internal(db_handle, key, value, false)
  189. }
  190. /// Set a key and value in the tx-local database for the given `DbHandle`.
  191. ///
  192. /// Returns `Ok` on success.
  193. ///
  194. /// ## Permissions
  195. /// * `ContractSection::Deploy`
  196. /// * `ContractSection::Update`
  197. pub fn db_set_local(db_handle: DbHandle, key: &[u8], value: &[u8]) -> GenericResult<()> {
  198. db_set_internal(db_handle, key, value, true)
  199. }
  200. /// Internal function for `db_set` which branches to either on-chain or
  201. /// transaction-local.
  202. fn db_set_internal(
  203. db_handle: DbHandle,
  204. key: &[u8],
  205. value: &[u8],
  206. local: bool,
  207. ) -> GenericResult<()> {
  208. let mut len = 0;
  209. let mut buf = vec![];
  210. len += db_handle.encode(&mut buf)?;
  211. len += key.encode(&mut buf)?;
  212. len += value.encode(&mut buf)?;
  213. let ret = unsafe {
  214. if local {
  215. db_set_local_(buf.as_ptr(), len as u32)
  216. } else {
  217. db_set_(buf.as_ptr(), len as u32)
  218. }
  219. };
  220. if ret != wasm::entrypoint::SUCCESS {
  221. return Err(ContractError::from(ret))
  222. }
  223. Ok(())
  224. }
  225. /// Remove a key from the on-chain database given a `DbHandle` and `key`.
  226. ///
  227. /// Returns `Ok` on success.
  228. ///
  229. /// ## Permissions
  230. /// * `ContractSection::Deploy`
  231. /// * `ContractSection::Update`
  232. pub fn db_del(db_handle: DbHandle, key: &[u8]) -> GenericResult<()> {
  233. db_del_internal(db_handle, key, false)
  234. }
  235. /// Remove a key from the tx-local database given a `DbHandle` and `key`.
  236. ///
  237. /// Returns `Ok` on success.
  238. ///
  239. /// ## Permissions
  240. /// * `ContractSection::Deploy`
  241. /// * `ContractSection::Update`
  242. pub fn db_del_local(db_handle: DbHandle, key: &[u8]) -> GenericResult<()> {
  243. db_del_internal(db_handle, key, true)
  244. }
  245. /// Internal function for `db_del` which branches to either on-chain or
  246. /// transaction-local.
  247. fn db_del_internal(db_handle: DbHandle, key: &[u8], local: bool) -> GenericResult<()> {
  248. let mut len = 0;
  249. let mut buf = vec![];
  250. len += db_handle.encode(&mut buf)?;
  251. len += key.encode(&mut buf)?;
  252. let ret = unsafe {
  253. if local {
  254. db_del_local_(buf.as_ptr(), len as u32)
  255. } else {
  256. db_del_(buf.as_ptr(), len as u32)
  257. }
  258. };
  259. if ret != wasm::entrypoint::SUCCESS {
  260. return Err(ContractError::from(ret))
  261. }
  262. Ok(())
  263. }
  264. /// Given a zkas circuit, create a VerifyingKey and insert them both
  265. /// into the on-chain db.
  266. ///
  267. /// Returns `Ok` on success, otherwise returns an error code.
  268. ///
  269. /// ## Permissions
  270. /// * `ContractSection::Deploy`
  271. pub fn zkas_db_set(bincode: &[u8]) -> GenericResult<()> {
  272. let mut len = 0;
  273. let mut buf = vec![];
  274. len += bincode.encode(&mut buf)?;
  275. let ret = unsafe { zkas_db_set_(buf.as_ptr(), len as u32) };
  276. if ret != wasm::entrypoint::SUCCESS {
  277. return Err(ContractError::from(ret))
  278. }
  279. Ok(())
  280. }
  281. extern "C" {
  282. fn db_init_(ptr: *const u8, len: u32) -> i64;
  283. fn db_lookup_(ptr: *const u8, len: u32) -> i64;
  284. fn db_lookup_local_(ptr: *const u8, len: u32) -> i64;
  285. fn db_get_(ptr: *const u8, len: u32) -> i64;
  286. fn db_get_local_(ptr: *const u8, len: u32) -> i64;
  287. fn db_contains_key_(ptr: *const u8, len: u32) -> i64;
  288. fn db_contains_key_local_(ptr: *const u8, len: u32) -> i64;
  289. fn db_set_(ptr: *const u8, len: u32) -> i64;
  290. fn db_set_local_(ptr: *const u8, len: u32) -> i64;
  291. fn db_del_(ptr: *const u8, len: u32) -> i64;
  292. fn db_del_local_(ptr: *const u8, len: u32) -> i64;
  293. fn zkas_db_set_(ptr: *const u8, len: u32) -> i64;
  294. }