Преглед изворни кода

blockchain: Add WasmStore and rename ContractStore to ContractStateStore.

parazyd пре 3 година
родитељ
комит
337f80361d
3 измењених фајлова са 79 додато и 34 уклоњено
  1. 66 29
      src/blockchain/contractstore.rs
  2. 7 3
      src/blockchain/mod.rs
  3. 6 2
      src/error.rs

+ 66 - 29
src/blockchain/contractstore.rs

@@ -7,7 +7,7 @@
  * published by the Free Software Foundation, either version 3 of the
  * License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
+r* This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Affero General Public License for more details.
@@ -18,28 +18,64 @@
 
 use darkfi_sdk::crypto::ContractId;
 use darkfi_serial::{deserialize, serialize};
-use log::debug;
+use log::{debug, error};
 
-use crate::{
-    Error::{ContractAlreadyInitialized, ContractNotFound, ContractStateNotFound},
-    Result,
-};
-
-/// The `ContractStore` is a `sled` tree that stores pointers to contracts'
-/// databases. See the rustdoc for the impl functions for more info.
-#[derive(Clone)]
-pub struct ContractStore(sled::Tree);
+use crate::{Error, Result};
 
 const SLED_CONTRACTS_TREE: &[u8] = b"_contracts";
+const SLED_BINCODE_TREE: &[u8] = b"_wasm_bincode";
 
 // Logger targets
-const TGT_INIT: &str = "blockchain::contractstore::init";
-const TGT_LKUP: &str = "blockchain::contractstore::lookup";
-const TGT_DROP: &str = "blockchain::contractstore::remove";
+const CS_TGT_INIT: &str = "blockchain::contractstatestore::init";
+const CS_TGT_LKUP: &str = "blockchain::contractstatestore::lookup";
+const CS_TGT_DROP: &str = "blockchain::contractstatestore::remove";
+
+/// The `WasmStore` is a `sled` tree that stores the wasm bincode for deployed
+/// contracts.
+#[derive(Clone)]
+pub struct WasmStore(sled::Tree);
+
+impl WasmStore {
+    /// Opens or creates a `WasmStore`. This tree holds the wasm bincode.
+    /// The layout looks like this:
+    /// ```plaintext
+    ///  tree: "_wasm_bincode"
+    ///   key: ContractId
+    /// value: Vec<u8>
+    pub fn new(db: &sled::Db) -> Result<Self> {
+        let tree = db.open_tree(SLED_BINCODE_TREE)?;
+        Ok(Self(tree))
+    }
+
+    /// Fetches the bincode for a given ContractId
+    /// Returns an error if the bincode is not found.
+    pub fn get(&self, contract_id: ContractId) -> Result<Vec<u8>> {
+        if let Some(bincode) = self.0.get(&serialize(&contract_id))? {
+            return Ok(bincode.to_vec())
+        }
+
+        Err(Error::WasmBincodeNotFound)
+    }
+
+    /// Inserts or replaces the bincode for a given ContractId
+    pub fn insert(&self, contract_id: ContractId, bincode: &[u8]) -> Result<()> {
+        if let Err(e) = self.0.insert(&serialize(&contract_id), bincode) {
+            error!("Failed to insert bincode to WasmStore: {}", e);
+            return Err(e.into())
+        }
+
+        Ok(())
+    }
+}
+
+/// The `ContractStateStore` is a `sled` tree that stores pointers to contracts'
+/// databases. See the rustdoc for the impl functions for more info.
+#[derive(Clone)]
+pub struct ContractStateStore(sled::Tree);
 
-impl ContractStore {
-    /// Opens or creates a `ContractStore`. This main tree holds the links
-    /// of contracts' states,
+impl ContractStateStore {
+    /// Opens or creates a `ContractStateStore`. This main tree holds the links
+    /// of contracts' states.
     /// The layout looks like this:
     /// ```plaintext
     ///  tree: "_contracts"
@@ -54,20 +90,21 @@ impl ContractStore {
 
     /// Try to initialize a new contract state. Contracts can create a number
     /// of trees, separated by `tree_name`, which they can then use from the
-    /// smart contract API. `init()` will look into the main `ContractStore`
+    /// smart contract API. `init()` will look into the main `ContractStateStore`
     /// tree to check if the smart contract was already deployed, and if so
     /// it will fetch a vector of these states that were initialized. If the
     /// state was already found, this function will return an error, because
     /// in this case the handle should be fetched using `lookup()`.
     /// If the tree was not initialized previously, it will be appended to
-    /// the main `ContractStore` tree and a `sled::Tree` handle will be returned.
+    /// the main `ContractStateStore` tree and a `sled::Tree` handle will be
+    /// returned.
     pub fn init(
         &self,
         db: &sled::Db,
         contract_id: &ContractId,
         tree_name: &str,
     ) -> Result<sled::Tree> {
-        debug!(target: TGT_INIT, "Initializing state tree for {}:{}", contract_id, tree_name);
+        debug!(target: CS_TGT_INIT, "Initializing state tree for {}:{}", contract_id, tree_name);
 
         let contract_id_bytes = serialize(contract_id);
         let ptr = contract_id.hash_state_id(tree_name);
@@ -83,7 +120,7 @@ impl ContractStore {
 
         // If the db was never initialized, it should not be in here.
         if state_pointers.contains(&ptr) {
-            return Err(ContractAlreadyInitialized)
+            return Err(Error::ContractAlreadyInitialized)
         }
 
         // Now we add it so it's marked as initialized
@@ -113,14 +150,14 @@ impl ContractStore {
         contract_id: &ContractId,
         tree_name: &str,
     ) -> Result<sled::Tree> {
-        debug!(target: TGT_LKUP, "Looking up state tree for {}:{}", contract_id, tree_name);
+        debug!(target: CS_TGT_LKUP, "Looking up state tree for {}:{}", contract_id, tree_name);
 
         let contract_id_bytes = serialize(contract_id);
         let ptr = contract_id.hash_state_id(tree_name);
 
         // A guard to make sure we went through init()
         if !self.0.contains_key(&contract_id_bytes)? {
-            return Err(ContractNotFound(contract_id.to_string()))
+            return Err(Error::ContractNotFound(contract_id.to_string()))
         }
 
         let state_pointers = self.0.get(&contract_id_bytes)?.unwrap();
@@ -129,7 +166,7 @@ impl ContractStore {
         // We assume the tree has been created already, so it should be listed
         // in this array. If not, that's an error.
         if !state_pointers.contains(&ptr) {
-            return Err(ContractStateNotFound)
+            return Err(Error::ContractStateNotFound)
         }
 
         // We open the tree and return its handle
@@ -140,17 +177,17 @@ impl ContractStore {
     /// Attempt to remove an existing contract state. In order to succeed, the
     /// state must have been previously initialized with `init()`. If the state
     /// has been found, its contents in the tree will be cleared, and the pointer
-    /// will be removed from the main `ContractStore`. If anything is not found
-    /// as initialized, an error is returned.
+    /// will be removed from the main `ContractStateStore`. If anything is not
+    /// found as initialized, an error is returned.
     pub fn remove(&self, db: &sled::Db, contract_id: &ContractId, tree_name: &str) -> Result<()> {
-        debug!(target: TGT_DROP, "Removing state tree for {}:{}", contract_id, tree_name);
+        debug!(target: CS_TGT_DROP, "Removing state tree for {}:{}", contract_id, tree_name);
 
         let contract_id_bytes = serialize(contract_id);
         let ptr = contract_id.hash_state_id(tree_name);
 
         // A guard to make sure we went through init()
         if !self.0.contains_key(&contract_id_bytes)? {
-            return Err(ContractNotFound(contract_id.to_string()))
+            return Err(Error::ContractNotFound(contract_id.to_string()))
         }
 
         let state_pointers = self.0.get(&contract_id_bytes)?.unwrap();
@@ -159,7 +196,7 @@ impl ContractStore {
         // We assume the tree has been created already, so it should be listed
         // in this array. If not, that's an error.
         if !state_pointers.contains(&ptr) {
-            return Err(ContractStateNotFound)
+            return Err(Error::ContractStateNotFound)
         }
 
         // We open the tree and clear it. This is unfortunately not atomic.

+ 7 - 3
src/blockchain/mod.rs

@@ -38,7 +38,7 @@ pub mod txstore;
 pub use txstore::TxStore;
 
 pub mod contractstore;
-pub use contractstore::ContractStore;
+pub use contractstore::{ContractStateStore, WasmStore};
 
 /// Structure holding all sled trees that define the concept of Blockchain.
 #[derive(Clone)]
@@ -58,7 +58,9 @@ pub struct Blockchain {
     /// Merkle roots sled tree
     pub merkle_roots: RootStore,
     /// Contract states
-    pub contracts: ContractStore,
+    pub contracts: ContractStateStore,
+    /// Wasm bincodes
+    pub wasm_bincode: WasmStore,
 }
 
 impl Blockchain {
@@ -70,7 +72,8 @@ impl Blockchain {
         let transactions = TxStore::new(db)?;
         let nullifiers = NullifierStore::new(db)?;
         let merkle_roots = RootStore::new(db)?;
-        let contracts = ContractStore::new(db)?;
+        let contracts = ContractStateStore::new(db)?;
+        let wasm_bincode = WasmStore::new(db)?;
 
         Ok(Self {
             sled_db: db.clone(),
@@ -81,6 +84,7 @@ impl Blockchain {
             nullifiers,
             merkle_roots,
             contracts,
+            wasm_bincode,
         })
     }
 

+ 6 - 2
src/error.rs

@@ -218,7 +218,7 @@ pub enum Error {
     InvalidPublicInputsError,
 
     #[error("Error during leader proof verification")]
-    LeaderProofVerificationError,
+    LeaderProofVerification,
 
     #[error("Signature could not be verified")]
     InvalidSignature,
@@ -227,7 +227,7 @@ pub enum Error {
     StateTransitionError,
 
     #[error("Check if proposal extends any existing fork chains failed")]
-    ExtendedChainIndexNotFoundError,
+    ExtendedChainIndexNotFound,
 
     #[error("Proposal contains missmatched headers")]
     ProposalHeadersMissmatchError,
@@ -311,6 +311,10 @@ pub enum Error {
     #[error("contract initialize error")]
     ContractError(darkfi_sdk::error::ContractError),
 
+    #[cfg(feature = "wasm-runtime")]
+    #[error("contract wasm bincode not found")]
+    WasmBincodeNotFound,
+
     #[cfg(feature = "wasm-runtime")]
     #[error("contract initialize error")]
     ContractInitError(u64),