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,
error::Error as StdError,
io,
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,
)
}
}