use fuel_storage::{MerkleRootStorage, StorageAsRef, StorageInspect, StorageMutate, StorageRead, StorageSize};
use fuel_tx::{Contract, StorageSlot};
use fuel_types::{Address, AssetId, BlockHeight, 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>
+ StorageSize<ContractsRawCode, Error = Self::DataError>
+ StorageRead<ContractsRawCode, Error = Self::DataError>
+ StorageMutate<ContractsInfo, Error = Self::DataError>
+ MerkleRootStorage<ContractId, ContractsState, Error = Self::DataError>
+ ContractsAssetsStorage<Error = Self::DataError>
{
type DataError: StdError + Into<io::Error>;
fn block_height(&self) -> Result<BlockHeight, Self::DataError>;
fn timestamp(&self, height: BlockHeight) -> Result<Word, Self::DataError>;
fn block_hash(&self, block_height: BlockHeight) -> Result<Bytes32, Self::DataError>;
fn coinbase(&self) -> Result<Address, Self::DataError>;
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_size(&self, id: &ContractId) -> Result<Option<usize>, Self::DataError> {
StorageSize::<ContractsRawCode>::size_of_value(self, id)
}
fn read_contract(&self, id: &ContractId, writer: &mut [u8]) -> Result<Option<Word>, Self::DataError> {
Ok(StorageRead::<ContractsRawCode>::read(self, id, writer)?.map(|r| r as Word))
}
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>;
}
pub trait ContractsAssetsStorage: MerkleRootStorage<ContractId, ContractsAssets> {
fn merkle_contract_asset_id_balance(
&self,
id: &ContractId,
asset_id: &AssetId,
) -> Result<Option<Word>, Self::Error> {
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::Error> {
StorageMutate::<ContractsAssets>::insert(self, &(contract, asset_id).into(), &value)
}
}
impl<S> ContractsAssetsStorage for &mut S where S: ContractsAssetsStorage {}
impl<S> InterpreterStorage for &mut S
where
S: InterpreterStorage,
{
type DataError = S::DataError;
fn block_height(&self) -> Result<BlockHeight, Self::DataError> {
<S as InterpreterStorage>::block_height(self.deref())
}
fn timestamp(&self, height: BlockHeight) -> Result<Word, Self::DataError> {
<S as InterpreterStorage>::timestamp(self.deref(), height)
}
fn block_hash(&self, block_height: BlockHeight) -> 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 storage_contract_size(&self, id: &ContractId) -> Result<Option<usize>, Self::DataError> {
<S as InterpreterStorage>::storage_contract_size(self.deref(), id)
}
fn read_contract(&self, id: &ContractId, writer: &mut [u8]) -> Result<Option<Word>, Self::DataError> {
<S as InterpreterStorage>::read_contract(self.deref(), id, writer)
}
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)
}
}