1use std::{collections::BTreeMap, io::Cursor};
20
21use darkfi_sdk::{
22 crypto::contract_id::{
23 ContractId, NATIVE_CONTRACT_IDS_BYTES, SMART_CONTRACT_MONOTREE_DB_NAME,
24 SMART_CONTRACT_ZKAS_DB_NAME,
25 },
26 monotree::{Hash as StateHash, Monotree, SledOverlayDb, SledTreeDb, EMPTY_HASH},
27};
28use darkfi_serial::{deserialize, serialize};
29use sled_overlay::{sled, SledDbOverlayStateDiff};
30use tracing::{debug, error};
31
32use crate::{
33 zk::{empty_witnesses, VerifyingKey, ZkCircuit},
34 zkas::ZkBinary,
35 Error, Result,
36};
37
38use super::{parse_record, SledDbOverlayPtr};
39
40pub const SLED_CONTRACTS_TREE: &[u8] = b"_contracts";
41pub const SLED_CONTRACTS_TREES_TREE: &[u8] = b"_contracts_trees";
42pub const SLED_CONTRACTS_MONOTREE_TREE: &[u8; 32] = &[
44 82, 161, 124, 97, 228, 243, 197, 75, 11, 86, 60, 214, 241, 24, 64, 100, 86, 48, 159, 147, 254,
45 116, 94, 17, 165, 22, 39, 3, 149, 120, 122, 175,
46];
47pub const SLED_BINCODE_TREE: &[u8] = b"_wasm_bincode";
48
49#[derive(Clone)]
52pub struct ContractStore {
53 pub wasm: sled::Tree,
60 pub state: sled::Tree,
70 pub state_trees: sled::Tree,
81 pub state_monotree: sled::Tree,
92}
93
94impl ContractStore {
95 pub fn new(db: &sled::Db) -> Result<Self> {
97 let wasm = db.open_tree(SLED_BINCODE_TREE)?;
98 let state = db.open_tree(SLED_CONTRACTS_TREE)?;
99 let state_trees = db.open_tree(SLED_CONTRACTS_TREES_TREE)?;
100 let state_monotree = db.open_tree(SLED_CONTRACTS_MONOTREE_TREE)?;
101 Ok(Self { wasm, state, state_trees, state_monotree })
102 }
103
104 pub fn get(&self, contract_id: ContractId) -> Result<Vec<u8>> {
107 if let Some(bincode) = self.wasm.get(serialize(&contract_id))? {
108 return Ok(bincode.to_vec())
109 }
110
111 Err(Error::WasmBincodeNotFound)
112 }
113
114 pub fn lookup(
119 &self,
120 db: &sled::Db,
121 contract_id: &ContractId,
122 tree_name: &str,
123 ) -> Result<sled::Tree> {
124 debug!(target: "blockchain::contractstore::lookup", "Looking up state tree for {contract_id}:{tree_name}");
125
126 let contract_id_bytes = serialize(contract_id);
128 if !self.state.contains_key(&contract_id_bytes)? {
129 return Err(Error::ContractNotFound(contract_id.to_string()))
130 }
131
132 let state_pointers = self.state.get(&contract_id_bytes)?.unwrap();
133 let state_pointers: Vec<[u8; 32]> = deserialize(&state_pointers)?;
134
135 let ptr = contract_id.hash_state_id(tree_name);
138 if !state_pointers.contains(&ptr) {
139 return Err(Error::ContractStateNotFound)
140 }
141
142 let tree = db.open_tree(ptr)?;
144 Ok(tree)
145 }
146
147 pub fn remove(&self, db: &sled::Db, contract_id: &ContractId, tree_name: &str) -> Result<()> {
155 debug!(target: "blockchain::contractstore::remove", "Removing state tree for {contract_id}:{tree_name}");
156
157 let contract_id_bytes = serialize(contract_id);
159 if !self.state.contains_key(&contract_id_bytes)? {
160 return Err(Error::ContractNotFound(contract_id.to_string()))
161 }
162
163 let state_pointers = self.state.get(&contract_id_bytes)?.unwrap();
164 let mut state_pointers: Vec<[u8; 32]> = deserialize(&state_pointers)?;
165
166 let ptr = contract_id.hash_state_id(tree_name);
169 if !state_pointers.contains(&ptr) {
170 return Err(Error::ContractStateNotFound)
171 }
172 if !self.state_trees.contains_key(ptr)? {
173 return Err(Error::ContractStateNotFound)
174 }
175
176 state_pointers.retain(|x| *x != ptr);
178 self.state.insert(contract_id_bytes, serialize(&state_pointers))?;
179 self.state_trees.remove(ptr)?;
180
181 db.drop_tree(ptr)?;
183
184 Ok(())
185 }
186
187 pub fn get_zkas(
190 &self,
191 db: &sled::Db,
192 contract_id: &ContractId,
193 zkas_ns: &str,
194 ) -> Result<(ZkBinary, VerifyingKey)> {
195 debug!(target: "blockchain::contractstore::get_zkas", "Looking up \"{contract_id}:{zkas_ns}\" zkas circuit & vk");
196
197 let zkas_tree = self.lookup(db, contract_id, SMART_CONTRACT_ZKAS_DB_NAME)?;
198
199 let Some(zkas_bytes) = zkas_tree.get(serialize(&zkas_ns))? else {
200 return Err(Error::ZkasBincodeNotFound)
201 };
202
203 let (zkbin, vkbin): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes).unwrap();
206
207 let zkbin = ZkBinary::decode(&zkbin, false).unwrap();
209
210 let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
212
213 let mut vk_buf = Cursor::new(vkbin);
215 let vk = VerifyingKey::read::<Cursor<Vec<u8>>, ZkCircuit>(&mut vk_buf, circuit).unwrap();
216
217 Ok((zkbin, vk))
218 }
219
220 pub fn get_all_wasm(&self) -> Result<Vec<(ContractId, Vec<u8>)>> {
224 let mut bincodes = vec![];
225
226 for bincode in self.wasm.iter() {
227 let bincode = bincode.unwrap();
228 let contract_id = deserialize(&bincode.0)?;
229 bincodes.push((contract_id, bincode.1.to_vec()));
230 }
231
232 Ok(bincodes)
233 }
234
235 pub fn get_all_states(&self) -> Result<Vec<(ContractId, Vec<blake3::Hash>)>> {
239 let mut contracts = vec![];
240
241 for contract in self.state.iter() {
242 contracts.push(parse_record(contract.unwrap())?);
243 }
244
245 Ok(contracts)
246 }
247
248 pub fn get_state_tree_value(
250 &self,
251 db: &sled::Db,
252 contract_id: &ContractId,
253 tree_name: &str,
254 key: &[u8],
255 ) -> Result<Vec<u8>> {
256 debug!(target: "blockchain::contractstore::get_state_tree_value", "Looking up state tree value for {contract_id}:{tree_name}");
257
258 let state_tree = self.lookup(db, contract_id, tree_name)?;
260
261 match state_tree.get(key)? {
263 Some(value) => Ok(value.to_vec()),
264 None => Err(Error::DatabaseError(format!(
265 "State tree {contract_id}:{tree_name} doesn't contain key: {key:?}"
266 ))),
267 }
268 }
269
270 pub fn get_state_tree_records(
273 &self,
274 db: &sled::Db,
275 contract_id: &ContractId,
276 tree_name: &str,
277 ) -> Result<BTreeMap<Vec<u8>, Vec<u8>>> {
278 debug!(target: "blockchain::contractstore::get_state_tree_records", "Looking up state tree records for {contract_id}:{tree_name}");
279
280 let state_tree = self.lookup(db, contract_id, tree_name)?;
282
283 let mut ret = BTreeMap::new();
285 for record in state_tree.iter() {
286 let (key, value) = record.unwrap();
287 ret.insert(key.to_vec(), value.to_vec());
288 }
289
290 Ok(ret)
291 }
292
293 pub fn get_state_monotree_root(&self) -> Result<StateHash> {
297 let monotree_db = SledTreeDb::new(&self.state_monotree);
298 let monotree = Monotree::new(monotree_db);
299 Ok(match monotree.get_headroot()? {
300 Some(hash) => hash,
301 None => *EMPTY_HASH,
302 })
303 }
304}
305
306pub struct ContractStoreOverlay(SledDbOverlayPtr);
308
309impl ContractStoreOverlay {
310 pub fn new(overlay: &SledDbOverlayPtr) -> Result<Self> {
311 overlay.lock().unwrap().open_tree(SLED_BINCODE_TREE, true)?;
312 overlay.lock().unwrap().open_tree(SLED_CONTRACTS_TREE, true)?;
313 overlay.lock().unwrap().open_tree(SLED_CONTRACTS_TREES_TREE, true)?;
314 overlay.lock().unwrap().open_tree(SLED_CONTRACTS_MONOTREE_TREE, true)?;
315 Ok(Self(overlay.clone()))
316 }
317
318 pub fn get(&self, contract_id: ContractId) -> Result<Vec<u8>> {
321 if let Some(bincode) =
322 self.0.lock().unwrap().get(SLED_BINCODE_TREE, &serialize(&contract_id))?
323 {
324 return Ok(bincode.to_vec())
325 }
326
327 Err(Error::WasmBincodeNotFound)
328 }
329
330 pub fn insert(&self, contract_id: ContractId, bincode: &[u8]) -> Result<()> {
333 if let Err(e) =
334 self.0.lock().unwrap().insert(SLED_BINCODE_TREE, &serialize(&contract_id), bincode)
335 {
336 error!(target: "blockchain::contractstoreoverlay::insert", "Failed to insert bincode to Wasm tree: {e}");
337 return Err(e.into())
338 }
339
340 Ok(())
341 }
342
343 pub fn init(&self, contract_id: &ContractId, tree_name: &str) -> Result<[u8; 32]> {
354 debug!(target: "blockchain::contractstoreoverlay::init", "Initializing state overlay tree for {contract_id}:{tree_name}");
355 let mut lock = self.0.lock().unwrap();
356
357 let contract_id_bytes = serialize(contract_id);
360 let mut state_pointers: Vec<[u8; 32]> =
361 if lock.contains_key(SLED_CONTRACTS_TREE, &contract_id_bytes)? {
362 let bytes = lock.get(SLED_CONTRACTS_TREE, &contract_id_bytes)?.unwrap();
363 deserialize(&bytes)?
364 } else {
365 vec![]
366 };
367
368 let ptr = contract_id.hash_state_id(tree_name);
370 if state_pointers.contains(&ptr) {
371 return Err(Error::ContractAlreadyInitialized)
372 }
373
374 state_pointers.push(ptr);
376 lock.insert(SLED_CONTRACTS_TREE, &contract_id_bytes, &serialize(&state_pointers))?;
377 lock.insert(SLED_CONTRACTS_TREES_TREE, &ptr, &contract_id_bytes)?;
378 lock.open_tree(&ptr, false)?;
379
380 Ok(ptr)
381 }
382
383 pub fn lookup(&self, contract_id: &ContractId, tree_name: &str) -> Result<[u8; 32]> {
388 debug!(target: "blockchain::contractstoreoverlay::lookup", "Looking up state tree for {contract_id}:{tree_name}");
389 let mut lock = self.0.lock().unwrap();
390
391 let contract_id_bytes = serialize(contract_id);
393 if !lock.contains_key(SLED_CONTRACTS_TREE, &contract_id_bytes)? {
394 return Err(Error::ContractNotFound(contract_id.to_string()))
395 }
396
397 let state_pointers = lock.get(SLED_CONTRACTS_TREE, &contract_id_bytes)?.unwrap();
398 let state_pointers: Vec<[u8; 32]> = deserialize(&state_pointers)?;
399
400 let ptr = contract_id.hash_state_id(tree_name);
403 if !state_pointers.contains(&ptr) {
404 return Err(Error::ContractStateNotFound)
405 }
406 if !lock.contains_key(SLED_CONTRACTS_TREES_TREE, &ptr)? {
407 return Err(Error::ContractStateNotFound)
408 }
409
410 lock.open_tree(&ptr, false)?;
412 Ok(ptr)
413 }
414
415 pub fn get_zkas(
418 &self,
419 contract_id: &ContractId,
420 zkas_ns: &str,
421 ) -> Result<(ZkBinary, VerifyingKey)> {
422 debug!(target: "blockchain::contractstoreoverlay::get_zkas", "Looking up \"{contract_id}:{zkas_ns}\" zkas circuit & vk");
423
424 let zkas_tree = self.lookup(contract_id, SMART_CONTRACT_ZKAS_DB_NAME)?;
425
426 let Some(zkas_bytes) = self.0.lock().unwrap().get(&zkas_tree, &serialize(&zkas_ns))? else {
427 return Err(Error::ZkasBincodeNotFound)
428 };
429
430 let (zkbin, vkbin): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes).unwrap();
433
434 let zkbin = ZkBinary::decode(&zkbin, false).unwrap();
436
437 let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin);
439
440 let mut vk_buf = Cursor::new(vkbin);
442 let vk = VerifyingKey::read::<Cursor<Vec<u8>>, ZkCircuit>(&mut vk_buf, circuit).unwrap();
443
444 Ok((zkbin, vk))
445 }
446
447 pub fn get_state_monotree_root(&self) -> Result<StateHash> {
451 let mut lock = self.0.lock().unwrap();
452 let monotree_db = SledOverlayDb::new(&mut lock, SLED_CONTRACTS_MONOTREE_TREE)?;
453 let monotree = Monotree::new(monotree_db);
454 Ok(match monotree.get_headroot()? {
455 Some(hash) => hash,
456 None => *EMPTY_HASH,
457 })
458 }
459
460 pub fn update_state_monotree(&self, diff: &SledDbOverlayStateDiff) -> Result<StateHash> {
469 let mut lock = self.0.lock().unwrap();
471 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "Retrieving contracts updates...");
472
473 let mut contracts_updates: BTreeMap<[u8; 32], ContractMonotreeUpdates> = BTreeMap::new();
475 for (state_key, (state_cache, _)) in &diff.caches {
476 if state_key == SLED_BINCODE_TREE {
479 for (contract_id_bytes, (_, value)) in &state_cache.cache {
480 let contract_id_bytes = deserialize(contract_id_bytes)?;
482
483 if NATIVE_CONTRACT_IDS_BYTES.contains(&contract_id_bytes) {
485 continue
486 }
487
488 let contract_id: ContractId = deserialize(&contract_id_bytes)?;
490 let monotree_pointer =
491 contract_id.hash_state_id(SMART_CONTRACT_MONOTREE_DB_NAME);
492
493 let mut contract_updates = match contracts_updates.remove(&contract_id_bytes) {
495 Some(r) => r,
496 None => ContractMonotreeUpdates::new(monotree_pointer),
497 };
498
499 let key = blake3::hash(&contract_id_bytes);
501 let value = blake3::hash(value);
502 contract_updates.inserts.push((key, value));
503
504 contracts_updates.insert(contract_id_bytes, contract_updates);
506 }
507 continue
508 }
509
510 if lock.state.protected_tree_names.contains(state_key) {
514 continue
515 }
516
517 let state_key: [u8; 32] = deserialize(state_key)?;
519
520 let Some(contract_id_bytes) = lock.get(SLED_CONTRACTS_TREES_TREE, &state_key)? else {
522 return Err(Error::ContractStateNotFound)
523 };
524 let contract_id_bytes: [u8; 32] = deserialize(&contract_id_bytes)?;
525 let contract_id: ContractId = deserialize(&contract_id_bytes)?;
526
527 let monotree_pointer = contract_id.hash_state_id(SMART_CONTRACT_MONOTREE_DB_NAME);
529 if monotree_pointer == state_key {
530 continue
531 }
532
533 let mut contract_updates = match contracts_updates.remove(&contract_id_bytes) {
535 Some(r) => r,
536 None => ContractMonotreeUpdates::new(monotree_pointer),
537 };
538
539 if contract_id.hash_state_id(SMART_CONTRACT_ZKAS_DB_NAME) == state_key {
541 for (key, (_, value)) in &state_cache.cache {
543 let mut hasher = blake3::Hasher::new();
545 hasher.update(&state_key);
546 hasher.update(key);
547 let key = hasher.finalize();
548
549 let (zkbin, _): (Vec<u8>, Vec<u8>) = deserialize(value)?;
551 let value = blake3::hash(&zkbin);
552 contract_updates.inserts.push((key, value));
553 }
554
555 contracts_updates.insert(contract_id_bytes, contract_updates);
557 continue
558 }
559
560 for (key, (_, value)) in &state_cache.cache {
562 let mut hasher = blake3::Hasher::new();
564 hasher.update(&state_key);
565 hasher.update(key);
566 let key = hasher.finalize();
567 let value = blake3::hash(value);
568 contract_updates.inserts.push((key, value));
569 }
570
571 for key in state_cache.removed.keys() {
573 let mut hasher = blake3::Hasher::new();
575 hasher.update(&state_key);
576 hasher.update(key);
577 let key = hasher.finalize();
578 contract_updates.removals.push(key);
579 }
580
581 contracts_updates.insert(contract_id_bytes, contract_updates);
583 }
584
585 let mut contracts_roots = BTreeMap::new();
587 for (contract_id_bytes, contract_updates) in contracts_updates {
588 let contract_id: ContractId = deserialize(&contract_id_bytes)?;
589 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "Updating monotree for contract: {contract_id}");
590
591 let monotree_db = SledOverlayDb::new(&mut lock, &contract_updates.monotree_pointer)?;
593 let mut monotree = Monotree::new(monotree_db);
594 let mut monotree_root = monotree.get_headroot()?;
595 let monotree_root_hash = match monotree_root {
596 Some(hash) => blake3::Hash::from(hash),
597 None => blake3::Hash::from(*EMPTY_HASH),
598 };
599 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "Current root: {monotree_root_hash}");
600
601 for (key, value) in &contract_updates.inserts {
603 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "Inserting key {key} with value: {value}");
604 monotree_root =
605 monotree.insert(monotree_root.as_ref(), key.as_bytes(), value.as_bytes())?;
606 }
607
608 for key in &contract_updates.removals {
610 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "Removing key: {key}");
611 monotree_root = monotree.remove(monotree_root.as_ref(), key.as_bytes())?;
612 }
613
614 monotree.set_headroot(monotree_root.as_ref());
616
617 let monotree_root = match monotree_root {
619 Some(hash) => hash,
620 None => *EMPTY_HASH,
621 };
622 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "New root: {}", blake3::Hash::from(monotree_root));
623 contracts_roots.insert(contract_id_bytes, monotree_root);
624 }
625
626 let monotree_db = SledOverlayDb::new(&mut lock, SLED_CONTRACTS_MONOTREE_TREE)?;
628 let mut monotree = Monotree::new(monotree_db);
629 let mut monotree_root = monotree.get_headroot()?;
630 let monotree_root_hash = match monotree_root {
631 Some(hash) => blake3::Hash::from(hash),
632 None => blake3::Hash::from(*EMPTY_HASH),
633 };
634 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "Updating global monotree with root: {monotree_root_hash}");
635
636 for (contract_id_bytes, contract_monotree_root) in &contracts_roots {
638 let contract_id: ContractId = deserialize(contract_id_bytes)?;
639 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "Inserting key {contract_id} with value: {}", blake3::Hash::from(*contract_monotree_root));
640 monotree_root = monotree.insert(
641 monotree_root.as_ref(),
642 contract_id_bytes,
643 contract_monotree_root,
644 )?;
645 }
646
647 monotree.set_headroot(monotree_root.as_ref());
649
650 let monotree_root = match monotree_root {
652 Some(hash) => hash,
653 None => *EMPTY_HASH,
654 };
655 debug!(target: "blockchain::contractstoreoverlay::update_state_monotree", "New global root: {}", blake3::Hash::from(monotree_root));
656
657 Ok(monotree_root)
658 }
659}
660
661struct ContractMonotreeUpdates {
663 monotree_pointer: [u8; 32],
664 inserts: Vec<(blake3::Hash, blake3::Hash)>,
665 removals: Vec<blake3::Hash>,
666}
667
668impl ContractMonotreeUpdates {
669 fn new(monotree_pointer: [u8; 32]) -> Self {
670 Self { monotree_pointer, inserts: vec![], removals: vec![] }
671 }
672}