use fuel_storage::{MerkleRootStorage, StorageAsRef, StorageInspect, StorageMutate};
use fuel_tx::{Contract, StorageSlot};
use fuel_types::{Address, AssetId, Bytes32, ContractId, Salt, Word};
use crate::storage::{ContractsAssets, ContractsInfo, ContractsRawCode, ContractsState};
use std::borrow::Cow;
use std::error::Error as StdError;
use std::io;
use std::ops::{Deref, DerefMut};
pub trait InterpreterStorage:
StorageMutate<ContractsRawCode, Error = Self::DataError>
+ StorageMutate<ContractsInfo, Error = Self::DataError>
+ MerkleRootStorage<ContractId, ContractsAssets, Error = Self::DataError>
+ MerkleRootStorage<ContractId, ContractsState, Error = Self::DataError>
{
type DataError: StdError + Into<io::Error>;
fn block_height(&self) -> Result<u32, Self::DataError>;
fn timestamp(&self, height: u32) -> Result<Word, Self::DataError>;
fn block_hash(&self, block_height: u32) -> Result<Bytes32, Self::DataError>;
fn coinbase(&self) -> Result<Address, Self::DataError>;
fn deploy_contract(
&mut self,
salt: &Salt,
slots: &[StorageSlot],
contract: &Contract,
) -> Result<(), Self::DataError> {
let storage_root = Contract::initial_state_root(slots.iter());
let root = contract.root();
let id = contract.id(salt, &root, &storage_root);
self.deploy_contract_with_id(salt, slots, contract, &root, &id)
}
fn deploy_contract_with_id(
&mut self,
salt: &Salt,
slots: &[StorageSlot],
contract: &Contract,
root: &Bytes32,
id: &ContractId,
) -> Result<(), Self::DataError> {
self.storage_contract_insert(id, contract)?;
self.storage_contract_root_insert(id, salt, root)?;
slots
.iter()
.try_for_each(|s| self.merkle_contract_state_insert(id, s.key(), s.value()).map(|_| ()))
}
fn storage_contract(&self, id: &ContractId) -> Result<Option<Cow<'_, Contract>>, Self::DataError> {
StorageInspect::<ContractsRawCode>::get(self, id)
}
fn storage_contract_insert(
&mut self,
id: &ContractId,
contract: &Contract,
) -> Result<Option<Contract>, Self::DataError> {
StorageMutate::<ContractsRawCode>::insert(self, id, contract.as_ref())
}
fn storage_contract_exists(&self, id: &ContractId) -> Result<bool, Self::DataError> {
self.storage::<ContractsRawCode>().contains_key(id)
}
fn storage_contract_root(&self, id: &ContractId) -> Result<Option<Cow<'_, (Salt, Bytes32)>>, Self::DataError> {
StorageInspect::<ContractsInfo>::get(self, id)
}
fn storage_contract_root_insert(
&mut self,
id: &ContractId,
salt: &Salt,
root: &Bytes32,
) -> Result<Option<(Salt, Bytes32)>, Self::DataError> {
StorageMutate::<ContractsInfo>::insert(self, id, &(*salt, *root))
}
fn merkle_contract_state(
&self,
id: &ContractId,
key: &Bytes32,
) -> Result<Option<Cow<'_, Bytes32>>, Self::DataError> {
StorageInspect::<ContractsState>::get(self, &(id, key).into())
}
fn merkle_contract_state_insert(
&mut self,
contract: &ContractId,
key: &Bytes32,
value: &Bytes32,
) -> Result<Option<Bytes32>, Self::DataError> {
StorageMutate::<ContractsState>::insert(self, &(contract, key).into(), value)
}
fn merkle_contract_state_remove(
&mut self,
contract: &ContractId,
key: &Bytes32,
) -> Result<Option<Bytes32>, Self::DataError> {
StorageMutate::<ContractsState>::remove(self, &(contract, key).into())
}
fn merkle_contract_state_range(
&self,
id: &ContractId,
start_key: &Bytes32,
range: Word,
) -> Result<Vec<Option<Cow<Bytes32>>>, Self::DataError>;
fn merkle_contract_state_insert_range(
&mut self,
contract: &ContractId,
start_key: &Bytes32,
values: &[Bytes32],
) -> Result<Option<()>, Self::DataError>;
fn merkle_contract_state_remove_range(
&mut self,
contract: &ContractId,
start_key: &Bytes32,
range: Word,
) -> Result<Option<()>, Self::DataError>;
fn merkle_contract_asset_id_balance(
&self,
id: &ContractId,
asset_id: &AssetId,
) -> Result<Option<Word>, Self::DataError> {
let balance = self
.storage::<ContractsAssets>()
.get(&(id, asset_id).into())?
.map(Cow::into_owned);
Ok(balance)
}
fn merkle_contract_asset_id_balance_insert(
&mut self,
contract: &ContractId,
asset_id: &AssetId,
value: Word,
) -> Result<Option<Word>, Self::DataError> {
StorageMutate::<ContractsAssets>::insert(self, &(contract, asset_id).into(), &value)
}
}
impl<S> InterpreterStorage for &mut S
where
S: InterpreterStorage,
{
type DataError = S::DataError;
fn block_height(&self) -> Result<u32, Self::DataError> {
<S as InterpreterStorage>::block_height(self.deref())
}
fn timestamp(&self, height: u32) -> Result<Word, Self::DataError> {
<S as InterpreterStorage>::timestamp(self.deref(), height)
}
fn block_hash(&self, block_height: u32) -> Result<Bytes32, Self::DataError> {
<S as InterpreterStorage>::block_hash(self.deref(), block_height)
}
fn coinbase(&self) -> Result<Address, Self::DataError> {
<S as InterpreterStorage>::coinbase(self.deref())
}
fn merkle_contract_state_range(
&self,
id: &ContractId,
start_key: &Bytes32,
range: Word,
) -> Result<Vec<Option<Cow<Bytes32>>>, Self::DataError> {
<S as InterpreterStorage>::merkle_contract_state_range(self.deref(), id, start_key, range)
}
fn merkle_contract_state_insert_range(
&mut self,
contract: &ContractId,
start_key: &Bytes32,
values: &[Bytes32],
) -> Result<Option<()>, Self::DataError> {
<S as InterpreterStorage>::merkle_contract_state_insert_range(self.deref_mut(), contract, start_key, values)
}
fn merkle_contract_state_remove_range(
&mut self,
contract: &ContractId,
start_key: &Bytes32,
range: Word,
) -> Result<Option<()>, Self::DataError> {
<S as InterpreterStorage>::merkle_contract_state_remove_range(self.deref_mut(), contract, start_key, range)
}
}