contract_store.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  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. r* 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::{collections::BTreeMap, io::Cursor};
  19. use darkfi_sdk::{
  20. crypto::contract_id::{
  21. ContractId, NATIVE_CONTRACT_IDS_BYTES, NATIVE_CONTRACT_ZKAS_DB_NAMES,
  22. SMART_CONTRACT_MONOTREE_DB_NAME, SMART_CONTRACT_ZKAS_DB_NAME,
  23. },
  24. monotree::{MemoryDb, Monotree, SledOverlayDb, SledTreeDb, EMPTY_HASH},
  25. };
  26. use darkfi_serial::{deserialize, serialize};
  27. use tracing::{debug, error};
  28. use sled_overlay::{serial::parse_record, sled};
  29. use crate::{
  30. zk::{empty_witnesses, VerifyingKey, ZkCircuit},
  31. zkas::ZkBinary,
  32. Error, Result,
  33. };
  34. use super::SledDbOverlayPtr;
  35. pub const SLED_CONTRACTS_TREE: &[u8] = b"_contracts";
  36. pub const SLED_CONTRACTS_TREES_TREE: &[u8] = b"_contracts_trees";
  37. pub const SLED_BINCODE_TREE: &[u8] = b"_wasm_bincode";
  38. /// The `ContractStore` is a structure representing all `sled` trees related
  39. /// to storing the blockchain's contracts information.
  40. #[derive(Clone)]
  41. pub struct ContractStore {
  42. /// The `sled` tree storing the wasm bincode for deployed contracts.
  43. /// The layout looks like this:
  44. /// ```plaintext
  45. /// tree: "_wasm_bincode"
  46. /// key: ContractId
  47. /// value: Vec<u8>
  48. pub wasm: sled::Tree,
  49. /// The `sled` tree storing the pointers to contracts' databases.
  50. /// See the rustdoc for the impl functions for more info.
  51. /// The layout looks like this:
  52. /// ```plaintext
  53. /// tree: "_contracts"
  54. /// key: ContractId
  55. /// value: Vec<blake3(ContractId || tree_name)>
  56. /// ```
  57. /// These values get mutated with `init()` and `remove()`.
  58. pub state: sled::Tree,
  59. /// The `sled` tree storing the inverse pointers to contracts'
  60. /// databases. See the rustdoc for the impl functions for more
  61. /// info.
  62. /// The layout looks like this:
  63. /// ```plaintext
  64. /// tree: "_contracts_trees"
  65. /// key: blake3(ContractId || tree_name)
  66. /// value: ContractId
  67. /// ```
  68. /// These values get mutated with `init()` and `remove()`.
  69. pub state_trees: sled::Tree,
  70. }
  71. impl ContractStore {
  72. /// Opens a new or existing `ContractStore` on the given sled database.
  73. pub fn new(db: &sled::Db) -> Result<Self> {
  74. let wasm = db.open_tree(SLED_BINCODE_TREE)?;
  75. let state = db.open_tree(SLED_CONTRACTS_TREE)?;
  76. let state_trees = db.open_tree(SLED_CONTRACTS_TREES_TREE)?;
  77. Ok(Self { wasm, state, state_trees })
  78. }
  79. /// Fetches the bincode for a given ContractId from the store's wasm tree.
  80. /// Returns an error if the bincode is not found.
  81. pub fn get(&self, contract_id: ContractId) -> Result<Vec<u8>> {
  82. if let Some(bincode) = self.wasm.get(serialize(&contract_id))? {
  83. return Ok(bincode.to_vec())
  84. }
  85. Err(Error::WasmBincodeNotFound)
  86. }
  87. /// Do a lookup of an existing contract state. In order to succeed, the
  88. /// state must have been previously initialized with `init()`. If the
  89. /// state has been found, a handle to it will be returned. Otherwise, we
  90. /// return an error.
  91. pub fn lookup(
  92. &self,
  93. db: &sled::Db,
  94. contract_id: &ContractId,
  95. tree_name: &str,
  96. ) -> Result<sled::Tree> {
  97. debug!(target: "blockchain::contractstore", "Looking up state tree for {contract_id}:{tree_name}");
  98. // A guard to make sure we went through init()
  99. let contract_id_bytes = serialize(contract_id);
  100. if !self.state.contains_key(&contract_id_bytes)? {
  101. return Err(Error::ContractNotFound(contract_id.to_string()))
  102. }
  103. let state_pointers = self.state.get(&contract_id_bytes)?.unwrap();
  104. let state_pointers: Vec<[u8; 32]> = deserialize(&state_pointers)?;
  105. // We assume the tree has been created already, so it should be listed
  106. // in this array. If not, that's an error.
  107. let ptr = contract_id.hash_state_id(tree_name);
  108. if !state_pointers.contains(&ptr) {
  109. return Err(Error::ContractStateNotFound)
  110. }
  111. // We open the tree and return its handle
  112. let tree = db.open_tree(ptr)?;
  113. Ok(tree)
  114. }
  115. /// Attempt to remove an existing contract state. In order to succeed, the
  116. /// state must have been previously initialized with `init()`. If the state
  117. /// has been found, its contents in the tree will be cleared, and the pointer
  118. /// will be removed from the main `ContractStateStore`. If anything is not
  119. /// found as initialized, an error is returned.
  120. /// NOTE: this function is not used right now, we keep it for future proofing,
  121. /// and its obviously untested.
  122. pub fn remove(&self, db: &sled::Db, contract_id: &ContractId, tree_name: &str) -> Result<()> {
  123. debug!(target: "blockchain::contractstore", "Removing state tree for {contract_id}:{tree_name}");
  124. // A guard to make sure we went through init()
  125. let contract_id_bytes = serialize(contract_id);
  126. if !self.state.contains_key(&contract_id_bytes)? {
  127. return Err(Error::ContractNotFound(contract_id.to_string()))
  128. }
  129. let state_pointers = self.state.get(&contract_id_bytes)?.unwrap();
  130. let mut state_pointers: Vec<[u8; 32]> = deserialize(&state_pointers)?;
  131. // We assume the tree has been created already, so it should be listed
  132. // in this array. If not, that's an error.
  133. let ptr = contract_id.hash_state_id(tree_name);
  134. if !state_pointers.contains(&ptr) {
  135. return Err(Error::ContractStateNotFound)
  136. }
  137. if !self.state_trees.contains_key(ptr)? {
  138. return Err(Error::ContractStateNotFound)
  139. }
  140. // Remove the deleted tree from the state pointer set.
  141. state_pointers.retain(|x| *x != ptr);
  142. self.state.insert(contract_id_bytes, serialize(&state_pointers))?;
  143. self.state_trees.remove(ptr)?;
  144. // Drop the deleted tree from the database
  145. db.drop_tree(ptr)?;
  146. Ok(())
  147. }
  148. /// Abstraction function for fetching a `ZkBinary` and its respective `VerifyingKey`
  149. /// from a contract's zkas sled tree.
  150. pub fn get_zkas(
  151. &self,
  152. db: &sled::Db,
  153. contract_id: &ContractId,
  154. zkas_ns: &str,
  155. ) -> Result<(ZkBinary, VerifyingKey)> {
  156. debug!(target: "blockchain::contractstore", "Looking up \"{contract_id}:{zkas_ns}\" zkas circuit & vk");
  157. let zkas_tree = self.lookup(db, contract_id, SMART_CONTRACT_ZKAS_DB_NAME)?;
  158. let Some(zkas_bytes) = zkas_tree.get(serialize(&zkas_ns))? else {
  159. return Err(Error::ZkasBincodeNotFound)
  160. };
  161. // If anything in this function panics, that means corrupted data managed
  162. // to get into this sled tree. This should not be possible.
  163. let (zkbin, vkbin): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes).unwrap();
  164. // The first vec is the compiled zkas binary
  165. let zkbin = ZkBinary::decode(&zkbin).unwrap();
  166. // Construct the circuit to be able to read the VerifyingKey
  167. let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
  168. // The second one is the serialized VerifyingKey for it
  169. let mut vk_buf = Cursor::new(vkbin);
  170. let vk = VerifyingKey::read::<Cursor<Vec<u8>>, ZkCircuit>(&mut vk_buf, circuit).unwrap();
  171. Ok((zkbin, vk))
  172. }
  173. /// Retrieve all wasm bincodes from the store's wasm tree in the form
  174. /// of a tuple (`contract_id`, `bincode`).
  175. /// Be careful as this will try to load everything in memory.
  176. pub fn get_all_wasm(&self) -> Result<Vec<(ContractId, Vec<u8>)>> {
  177. let mut bincodes = vec![];
  178. for bincode in self.wasm.iter() {
  179. let bincode = bincode.unwrap();
  180. let contract_id = deserialize(&bincode.0)?;
  181. bincodes.push((contract_id, bincode.1.to_vec()));
  182. }
  183. Ok(bincodes)
  184. }
  185. /// Retrieve all contract states from the store's state tree in the
  186. /// form of a tuple (`contract_id`, `state_hashes`).
  187. /// Be careful as this will try to load everything in memory.
  188. pub fn get_all_states(&self) -> Result<Vec<(ContractId, Vec<blake3::Hash>)>> {
  189. let mut contracts = vec![];
  190. for contract in self.state.iter() {
  191. contracts.push(parse_record(contract.unwrap())?);
  192. }
  193. Ok(contracts)
  194. }
  195. /// Retrieve provided key value bytes from a contract's zkas sled tree.
  196. pub fn get_state_tree_value(
  197. &self,
  198. db: &sled::Db,
  199. contract_id: &ContractId,
  200. tree_name: &str,
  201. key: &[u8],
  202. ) -> Result<Vec<u8>> {
  203. debug!(target: "blockchain::contractstore", "Looking up state tree value for {contract_id}:{tree_name}");
  204. // Grab the state tree
  205. let state_tree = self.lookup(db, contract_id, tree_name)?;
  206. // Grab the key value
  207. match state_tree.get(key)? {
  208. Some(value) => Ok(value.to_vec()),
  209. None => Err(Error::DatabaseError(format!(
  210. "State tree {contract_id}:{tree_name} doesn't contain key: {key:?}"
  211. ))),
  212. }
  213. }
  214. /// Retrieve all records from a contract's zkas sled tree, as a `BTreeMap`.
  215. /// Be careful as this will try to load everything in memory.
  216. pub fn get_state_tree_records(
  217. &self,
  218. db: &sled::Db,
  219. contract_id: &ContractId,
  220. tree_name: &str,
  221. ) -> Result<BTreeMap<Vec<u8>, Vec<u8>>> {
  222. debug!(target: "blockchain::contractstore", "Looking up state tree records for {contract_id}:{tree_name}");
  223. // Grab the state tree
  224. let state_tree = self.lookup(db, contract_id, tree_name)?;
  225. // Retrieve its records
  226. let mut ret = BTreeMap::new();
  227. for record in state_tree.iter() {
  228. let (key, value) = record.unwrap();
  229. ret.insert(key.to_vec(), value.to_vec());
  230. }
  231. Ok(ret)
  232. }
  233. /// Generate a Monotree(SMT) containing all contracts states
  234. /// roots, along with the wasm bincodes monotree root.
  235. ///
  236. /// Note: native contracts zkas tree and wasm bincodes are excluded.
  237. pub fn get_state_monotree(&self, db: &sled::Db) -> Result<Monotree<MemoryDb>> {
  238. // Initialize the monotree
  239. let mut root = None;
  240. let monotree_db = MemoryDb::new();
  241. let mut tree = Monotree::new(monotree_db);
  242. // Iterate over current contracts states records
  243. for state_record in self.state.iter() {
  244. // Grab its monotree pointer
  245. let (contract_id, state_pointers): (ContractId, Vec<[u8; 32]>) =
  246. parse_record(state_record?)?;
  247. let state_monotree_ptr = contract_id.hash_state_id(SMART_CONTRACT_MONOTREE_DB_NAME);
  248. // Check it exists
  249. if !state_pointers.contains(&state_monotree_ptr) {
  250. return Err(Error::ContractStateNotFound)
  251. }
  252. if !self.state_trees.contains_key(state_monotree_ptr)? {
  253. return Err(Error::ContractStateNotFound)
  254. }
  255. // Grab its monotree
  256. let state_tree = db.open_tree(state_monotree_ptr)?;
  257. let state_monotree_db = SledTreeDb::new(&state_tree);
  258. let state_monotree = Monotree::new(state_monotree_db);
  259. // Insert its root to the global monotree
  260. let state_monotree_root = match state_monotree.get_headroot()? {
  261. Some(hash) => hash,
  262. None => *EMPTY_HASH,
  263. };
  264. root = tree.insert(root.as_ref(), &contract_id.to_bytes(), &state_monotree_root)?;
  265. }
  266. // Iterate over current contracts wasm bincodes to compute its monotree root
  267. let mut wasm_monotree_root = None;
  268. let wasm_monotree_db = MemoryDb::new();
  269. let mut wasm_monotree = Monotree::new(wasm_monotree_db);
  270. for record in self.wasm.iter() {
  271. let (key, value) = record?;
  272. // Skip native ones
  273. if NATIVE_CONTRACT_IDS_BYTES.contains(&deserialize(&key)?) {
  274. continue
  275. }
  276. // Insert record
  277. wasm_monotree_root = wasm_monotree.insert(
  278. wasm_monotree_root.as_ref(),
  279. blake3::hash(&key).as_bytes(),
  280. blake3::hash(&value).as_bytes(),
  281. )?;
  282. }
  283. // Insert wasm bincodes root to the global monotree
  284. let wasm_monotree_root = match wasm_monotree_root {
  285. Some(hash) => hash,
  286. None => *EMPTY_HASH,
  287. };
  288. root = tree.insert(
  289. root.as_ref(),
  290. blake3::hash(SLED_BINCODE_TREE).as_bytes(),
  291. &wasm_monotree_root,
  292. )?;
  293. tree.set_headroot(root.as_ref());
  294. Ok(tree)
  295. }
  296. }
  297. /// Overlay structure over a [`ContractStore`] instance.
  298. pub struct ContractStoreOverlay(SledDbOverlayPtr);
  299. impl ContractStoreOverlay {
  300. pub fn new(overlay: &SledDbOverlayPtr) -> Result<Self> {
  301. overlay.lock().unwrap().open_tree(SLED_BINCODE_TREE, true)?;
  302. overlay.lock().unwrap().open_tree(SLED_CONTRACTS_TREE, true)?;
  303. overlay.lock().unwrap().open_tree(SLED_CONTRACTS_TREES_TREE, true)?;
  304. Ok(Self(overlay.clone()))
  305. }
  306. /// Fetches the bincode for a given ContractId from the overlay's wasm tree.
  307. /// Returns an error if the bincode is not found.
  308. pub fn get(&self, contract_id: ContractId) -> Result<Vec<u8>> {
  309. if let Some(bincode) =
  310. self.0.lock().unwrap().get(SLED_BINCODE_TREE, &serialize(&contract_id))?
  311. {
  312. return Ok(bincode.to_vec())
  313. }
  314. Err(Error::WasmBincodeNotFound)
  315. }
  316. /// Inserts or replaces the bincode for a given ContractId into the overlay's
  317. /// wasm tree.
  318. pub fn insert(&self, contract_id: ContractId, bincode: &[u8]) -> Result<()> {
  319. if let Err(e) =
  320. self.0.lock().unwrap().insert(SLED_BINCODE_TREE, &serialize(&contract_id), bincode)
  321. {
  322. error!(target: "blockchain::contractstoreoverlay", "Failed to insert bincode to Wasm tree: {e}");
  323. return Err(e.into())
  324. }
  325. Ok(())
  326. }
  327. /// Try to initialize a new contract state. Contracts can create a number
  328. /// of trees, separated by `tree_name`, which they can then use from the
  329. /// smart contract API. `init()` will look into the main `ContractStateStoreOverlay`
  330. /// tree to check if the smart contract was already deployed, and if so
  331. /// it will fetch a vector of these states that were initialized. If the
  332. /// state was already found, this function will return an error, because
  333. /// in this case the handle should be fetched using `lookup()`.
  334. /// If the tree was not initialized previously, it will be appended to
  335. /// the main `ContractStateStoreOverlay` tree and a handle to it will be
  336. /// returned.
  337. pub fn init(&self, contract_id: &ContractId, tree_name: &str) -> Result<[u8; 32]> {
  338. debug!(target: "blockchain::contractstoreoverlay", "Initializing state overlay tree for {contract_id}:{tree_name}");
  339. let mut lock = self.0.lock().unwrap();
  340. // See if there are existing state trees.
  341. // If not, just start with an empty vector.
  342. let contract_id_bytes = serialize(contract_id);
  343. let mut state_pointers: Vec<[u8; 32]> =
  344. if lock.contains_key(SLED_CONTRACTS_TREE, &contract_id_bytes)? {
  345. let bytes = lock.get(SLED_CONTRACTS_TREE, &contract_id_bytes)?.unwrap();
  346. deserialize(&bytes)?
  347. } else {
  348. vec![]
  349. };
  350. // If the db was never initialized, it should not be in here.
  351. let ptr = contract_id.hash_state_id(tree_name);
  352. if state_pointers.contains(&ptr) {
  353. return Err(Error::ContractAlreadyInitialized)
  354. }
  355. // Now we add it so it's marked as initialized and create its tree.
  356. state_pointers.push(ptr);
  357. lock.insert(SLED_CONTRACTS_TREE, &contract_id_bytes, &serialize(&state_pointers))?;
  358. lock.insert(SLED_CONTRACTS_TREES_TREE, &ptr, &contract_id_bytes)?;
  359. lock.open_tree(&ptr, false)?;
  360. Ok(ptr)
  361. }
  362. /// Do a lookup of an existing contract state. In order to succeed, the
  363. /// state must have been previously initialized with `init()`. If the
  364. /// state has been found, a handle to it will be returned. Otherwise, we
  365. /// return an error.
  366. pub fn lookup(&self, contract_id: &ContractId, tree_name: &str) -> Result<[u8; 32]> {
  367. debug!(target: "blockchain::contractstoreoverlay", "Looking up state tree for {contract_id}:{tree_name}");
  368. let mut lock = self.0.lock().unwrap();
  369. // A guard to make sure we went through init()
  370. let contract_id_bytes = serialize(contract_id);
  371. if !lock.contains_key(SLED_CONTRACTS_TREE, &contract_id_bytes)? {
  372. return Err(Error::ContractNotFound(contract_id.to_string()))
  373. }
  374. let state_pointers = lock.get(SLED_CONTRACTS_TREE, &contract_id_bytes)?.unwrap();
  375. let state_pointers: Vec<[u8; 32]> = deserialize(&state_pointers)?;
  376. // We assume the tree has been created already, so it should be listed
  377. // in this array. If not, that's an error.
  378. let ptr = contract_id.hash_state_id(tree_name);
  379. if !state_pointers.contains(&ptr) {
  380. return Err(Error::ContractStateNotFound)
  381. }
  382. if !lock.contains_key(SLED_CONTRACTS_TREES_TREE, &ptr)? {
  383. return Err(Error::ContractStateNotFound)
  384. }
  385. // We open the tree and return its handle
  386. lock.open_tree(&ptr, false)?;
  387. Ok(ptr)
  388. }
  389. /// Abstraction function for fetching a `ZkBinary` and its respective `VerifyingKey`
  390. /// from a contract's zkas sled tree.
  391. pub fn get_zkas(
  392. &self,
  393. contract_id: &ContractId,
  394. zkas_ns: &str,
  395. ) -> Result<(ZkBinary, VerifyingKey)> {
  396. debug!(target: "blockchain::contractstore", "Looking up \"{contract_id}:{zkas_ns}\" zkas circuit & vk");
  397. let zkas_tree = self.lookup(contract_id, SMART_CONTRACT_ZKAS_DB_NAME)?;
  398. let Some(zkas_bytes) = self.0.lock().unwrap().get(&zkas_tree, &serialize(&zkas_ns))? else {
  399. return Err(Error::ZkasBincodeNotFound)
  400. };
  401. // If anything in this function panics, that means corrupted data managed
  402. // to get into this sled tree. This should not be possible.
  403. let (zkbin, vkbin): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes).unwrap();
  404. // The first vec is the compiled zkas binary
  405. let zkbin = ZkBinary::decode(&zkbin).unwrap();
  406. // Construct the circuit to be able to read the VerifyingKey
  407. let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
  408. // The second one is the serialized VerifyingKey for it
  409. let mut vk_buf = Cursor::new(vkbin);
  410. let vk = VerifyingKey::read::<Cursor<Vec<u8>>, ZkCircuit>(&mut vk_buf, circuit).unwrap();
  411. Ok((zkbin, vk))
  412. }
  413. /// Generate a Monotree(SMT) containing all contracts states
  414. /// roots, along with the wasm bincodes monotree roots.
  415. /// Be carefull as this will open all states monotrees in the overlay.
  416. ///
  417. /// Note: native contracts zkas tree and wasm bincodes are excluded.
  418. pub fn get_state_monotree(&self) -> Result<Monotree<MemoryDb>> {
  419. let mut lock = self.0.lock().unwrap();
  420. // Grab all states monotrees pointers
  421. let mut states_monotrees_pointers = vec![];
  422. for state_record in lock.iter(SLED_CONTRACTS_TREE)? {
  423. // Grab its monotree pointer
  424. let (contract_id, state_pointers): (ContractId, Vec<[u8; 32]>) =
  425. parse_record(state_record?)?;
  426. let state_monotree_ptr = contract_id.hash_state_id(SMART_CONTRACT_MONOTREE_DB_NAME);
  427. // Check it exists
  428. if !state_pointers.contains(&state_monotree_ptr) {
  429. return Err(Error::ContractStateNotFound)
  430. }
  431. if !lock.contains_key(SLED_CONTRACTS_TREES_TREE, &state_monotree_ptr)? {
  432. return Err(Error::ContractStateNotFound)
  433. }
  434. states_monotrees_pointers.push((contract_id, state_monotree_ptr));
  435. }
  436. // Initialize the monotree
  437. let mut root = None;
  438. let monotree_db = MemoryDb::new();
  439. let mut tree = Monotree::new(monotree_db);
  440. // Iterate over contract states monotrees pointers
  441. for (contract_id, state_monotree_ptr) in states_monotrees_pointers {
  442. // Grab its monotree
  443. let state_monotree_db = SledOverlayDb::new(&mut lock, &state_monotree_ptr)?;
  444. let state_monotree = Monotree::new(state_monotree_db);
  445. // Insert its root to the global monotree
  446. let state_monotree_root = match state_monotree.get_headroot()? {
  447. Some(hash) => hash,
  448. None => *EMPTY_HASH,
  449. };
  450. root = tree.insert(root.as_ref(), &contract_id.to_bytes(), &state_monotree_root)?;
  451. }
  452. // Iterate over current contracts wasm bincodes to compute its monotree root
  453. let mut wasm_monotree_root = None;
  454. let wasm_monotree_db = MemoryDb::new();
  455. let mut wasm_monotree = Monotree::new(wasm_monotree_db);
  456. for record in lock.iter(SLED_BINCODE_TREE)? {
  457. let (key, value) = record?;
  458. // Skip native ones
  459. if NATIVE_CONTRACT_IDS_BYTES.contains(&deserialize(&key)?) {
  460. continue
  461. }
  462. // Insert record
  463. wasm_monotree_root = wasm_monotree.insert(
  464. wasm_monotree_root.as_ref(),
  465. blake3::hash(&key).as_bytes(),
  466. blake3::hash(&value).as_bytes(),
  467. )?;
  468. }
  469. // Insert wasm bincodes root to the global monotree
  470. let wasm_monotree_root = match wasm_monotree_root {
  471. Some(hash) => hash,
  472. None => *EMPTY_HASH,
  473. };
  474. root = tree.insert(
  475. root.as_ref(),
  476. blake3::hash(SLED_BINCODE_TREE).as_bytes(),
  477. &wasm_monotree_root,
  478. )?;
  479. tree.set_headroot(root.as_ref());
  480. drop(lock);
  481. // Update the monotree to the latest overlay changes
  482. self.update_state_monotree(&mut tree)?;
  483. Ok(tree)
  484. }
  485. /// Retrieve all updated contracts states and wasm bincodes
  486. /// monotrees roots and update their records in the provided
  487. /// Monotree(SMT).
  488. ///
  489. /// Note: native contracts zkas tree and wasm bincodes are excluded.
  490. pub fn update_state_monotree(&self, tree: &mut Monotree<MemoryDb>) -> Result<()> {
  491. let mut lock = self.0.lock().unwrap();
  492. // Iterate over overlay's caches
  493. let mut root = tree.get_headroot()?;
  494. let mut states_monotrees_pointers = vec![];
  495. for (state_key, state_cache) in &lock.state.caches {
  496. // Check if that cache is a contract state one.
  497. // Overlay protected trees are all the native/non-contract ones.
  498. if !lock.state.protected_tree_names.contains(state_key) {
  499. let state_key = deserialize(state_key)?;
  500. // Skip native zkas tree
  501. if NATIVE_CONTRACT_ZKAS_DB_NAMES.contains(&state_key) {
  502. continue
  503. }
  504. // Grab its contract id
  505. let Some(record) = lock.get(SLED_CONTRACTS_TREES_TREE, &state_key)? else {
  506. return Err(Error::ContractStateNotFound)
  507. };
  508. let contract_id: ContractId = deserialize(&record)?;
  509. // Skip the actual monotree state cache
  510. let state_monotree_ptr = contract_id.hash_state_id(SMART_CONTRACT_MONOTREE_DB_NAME);
  511. if state_monotree_ptr == state_key {
  512. continue
  513. }
  514. // Grab its monotree pointer and its cache state
  515. states_monotrees_pointers.push((
  516. contract_id,
  517. state_monotree_ptr,
  518. state_cache.state.removed.clone(),
  519. state_cache.state.cache.clone(),
  520. ));
  521. continue
  522. }
  523. // Skip if its not the wasm bincodes cache
  524. if state_key != SLED_BINCODE_TREE {
  525. continue
  526. }
  527. // Check if wasm bincodes cache is updated
  528. if state_cache.state.cache.is_empty() && state_cache.state.removed.is_empty() {
  529. continue
  530. }
  531. // Iterate over current contracts wasm bincodes to compute its monotree root
  532. debug!(target: "blockchain::contractstore::update_state_monotree", "Updating wasm bincodes monotree...");
  533. let mut wasm_monotree_root = None;
  534. let wasm_monotree_db = MemoryDb::new();
  535. let mut wasm_monotree = Monotree::new(wasm_monotree_db);
  536. for record in state_cache.iter() {
  537. let (key, value) = record?;
  538. // Skip native ones
  539. if NATIVE_CONTRACT_IDS_BYTES.contains(&deserialize(&key)?) {
  540. continue
  541. }
  542. // Insert record
  543. let key = blake3::hash(&key);
  544. let value = blake3::hash(&value);
  545. debug!(target: "blockchain::contractstore::update_state_monotree", "Inserting key {key} with value: {value}");
  546. wasm_monotree_root = wasm_monotree.insert(
  547. wasm_monotree_root.as_ref(),
  548. key.as_bytes(),
  549. value.as_bytes(),
  550. )?;
  551. }
  552. // Insert wasm bincodes root to the global monotree
  553. let wasm_monotree_root = match wasm_monotree_root {
  554. Some(hash) => hash,
  555. None => *EMPTY_HASH,
  556. };
  557. debug!(target: "blockchain::contractstore::update_state_monotree", "New root: {}", blake3::hash(&wasm_monotree_root));
  558. root = tree.insert(
  559. root.as_ref(),
  560. blake3::hash(SLED_BINCODE_TREE).as_bytes(),
  561. &wasm_monotree_root,
  562. )?;
  563. debug!(target: "blockchain::contractstore::update_state_monotree", "New global root: {}", blake3::hash(&root.unwrap()));
  564. }
  565. // Iterate over contract states monotrees pointers
  566. for (contract_id, state_monotree_ptr, removed, cache) in states_monotrees_pointers {
  567. debug!(target: "blockchain::contractstore::update_state_monotree", "Updating monotree for contract: {contract_id}");
  568. let state_monotree_db = SledOverlayDb::new(&mut lock, &state_monotree_ptr)?;
  569. let mut state_monotree = Monotree::new(state_monotree_db);
  570. let mut state_monotree_root = state_monotree.get_headroot()?;
  571. // Remove dropped records
  572. for key in &removed {
  573. let key = blake3::hash(key);
  574. debug!(target: "blockchain::contractstore::update_state_monotree", "Removed key: {key}");
  575. state_monotree_root =
  576. state_monotree.remove(state_monotree_root.as_ref(), key.as_bytes())?;
  577. }
  578. // Update or insert new records
  579. for (key, value) in &cache {
  580. let key = blake3::hash(key);
  581. let value = blake3::hash(value);
  582. debug!(target: "blockchain::contractstore::update_state_monotree", "Updating key {key} with value: {value}");
  583. state_monotree_root = state_monotree.insert(
  584. state_monotree_root.as_ref(),
  585. key.as_bytes(),
  586. value.as_bytes(),
  587. )?;
  588. }
  589. state_monotree.set_headroot(state_monotree_root.as_ref());
  590. // Insert its root to the global monotree
  591. let state_monotree_root = match state_monotree_root {
  592. Some(hash) => hash,
  593. None => *EMPTY_HASH,
  594. };
  595. debug!(target: "blockchain::contractstore::update_state_monotree", "New root: {}", blake3::hash(&state_monotree_root));
  596. root = tree.insert(root.as_ref(), &contract_id.to_bytes(), &state_monotree_root)?;
  597. debug!(target: "blockchain::contractstore::update_state_monotree", "New global root: {}", blake3::hash(&root.unwrap()));
  598. }
  599. tree.set_headroot(root.as_ref());
  600. Ok(())
  601. }
  602. }