contractstore.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 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_sdk::crypto::ContractId;
  19. use darkfi_serial::{deserialize, serialize};
  20. use crate::{
  21. Error::{ContractAlreadyInitialized, ContractNotFound, ContractStateNotFound},
  22. Result,
  23. };
  24. #[derive(Clone)]
  25. pub struct ContractStore(sled::Tree);
  26. const SLED_CONTRACTS_TREE: &[u8] = b"_contracts";
  27. // =================
  28. // TODO: Drop tree
  29. // =================
  30. impl ContractStore {
  31. pub fn new(db: &sled::Db) -> Result<Self> {
  32. let tree = db.open_tree(SLED_CONTRACTS_TREE)?;
  33. Ok(Self(tree))
  34. }
  35. /// Database layout:
  36. /// ```plaintext
  37. /// Tree: _contracts
  38. /// key: ContractId
  39. /// value: blake3(ContractId || tree_name)
  40. /// ```
  41. ///
  42. /// `value` when init-ed represents a Contract's state tree:
  43. /// ```plaintext
  44. /// Tree: blake3(ContractId || tree_name)
  45. /// key: &[u8]
  46. /// value: &[u8]
  47. /// ```
  48. pub fn init(
  49. &self,
  50. db: &sled::Db,
  51. contract_id: &ContractId,
  52. tree_name: &str,
  53. ) -> Result<sled::Tree> {
  54. let contract_id_bytes = serialize(contract_id);
  55. let mut state_pointers: Vec<[u8; 32]> = if self.0.contains_key(&contract_id_bytes)? {
  56. let bytes = self.0.get(&contract_id_bytes)?.unwrap();
  57. deserialize(&bytes)?
  58. } else {
  59. vec![]
  60. };
  61. let mut hasher = blake3::Hasher::new();
  62. hasher.update(&contract_id_bytes);
  63. hasher.update(&tree_name.as_bytes());
  64. let ptr = hasher.finalize();
  65. let ptr = ptr.as_bytes();
  66. // If the db was never initialized, it should not be in here.
  67. if state_pointers.contains(ptr) {
  68. return Err(ContractAlreadyInitialized)
  69. }
  70. // Now we add it so it's marked as initialized
  71. state_pointers.push(*ptr);
  72. self.0.insert(&contract_id_bytes, serialize(&state_pointers))?;
  73. // We open the tree and return its handle
  74. let tree = db.open_tree(ptr)?;
  75. Ok(tree)
  76. }
  77. pub fn lookup(
  78. &self,
  79. db: &sled::Db,
  80. contract_id: &ContractId,
  81. tree_name: &str,
  82. ) -> Result<sled::Tree> {
  83. let contract_id_bytes = serialize(contract_id);
  84. // A guard to make sure we went through init()
  85. if !self.0.contains_key(&contract_id_bytes)? {
  86. return Err(ContractNotFound(contract_id.to_string()))
  87. }
  88. let state_pointers = self.0.get(&contract_id_bytes)?.unwrap();
  89. let state_pointers: Vec<[u8; 32]> = deserialize(&state_pointers)?;
  90. let mut hasher = blake3::Hasher::new();
  91. hasher.update(&contract_id_bytes);
  92. hasher.update(&tree_name.as_bytes());
  93. let ptr = hasher.finalize();
  94. let ptr = ptr.as_bytes();
  95. // We assume the tree has been created already, so it should be listed in this array.
  96. // If not, that's an error.
  97. if !state_pointers.contains(ptr) {
  98. return Err(ContractStateNotFound)
  99. }
  100. // We open the tree and return its handle
  101. let tree = db.open_tree(ptr)?;
  102. Ok(tree)
  103. }
  104. }