mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
blockchain: Add WasmStore and rename ContractStore to ContractStateStore.
This commit is contained in:
@@ -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";
|
||||
|
||||
impl ContractStore {
|
||||
/// Opens or creates a `ContractStore`. This main tree holds the links
|
||||
/// of contracts' states,
|
||||
/// 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 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.
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user