use crate::database::{
Column,
Database,
};
use fuel_core_storage::{
Error as StorageError,
Mappable,
Result as StorageResult,
StorageInspect,
StorageMutate,
};
use fuel_core_types::{
blockchain::primitives::{
BlockHeight,
BlockId,
},
fuel_merkle::binary,
fuel_tx::TxId,
fuel_types::{
Bytes32,
ContractId,
MessageId,
},
};
use serde::{
de::DeserializeOwned,
Serialize,
};
use std::borrow::Cow;
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct DenseMerkleMetadata {
pub root: Bytes32,
pub version: u64,
}
impl Default for DenseMerkleMetadata {
fn default() -> Self {
let empty_merkle_tree = binary::in_memory::MerkleTree::new();
Self {
root: empty_merkle_tree.root().into(),
version: 0,
}
}
}
pub struct FuelBlockSecondaryKeyBlockHeights;
impl Mappable for FuelBlockSecondaryKeyBlockHeights {
type Key = BlockHeight;
type OwnedKey = Self::Key;
type Value = BlockId;
type OwnedValue = Self::Value;
}
pub struct FuelBlockMerkleData;
impl Mappable for FuelBlockMerkleData {
type Key = u64;
type OwnedKey = Self::Key;
type Value = binary::Primitive;
type OwnedValue = Self::Value;
}
pub struct FuelBlockMerkleMetadata;
impl Mappable for FuelBlockMerkleMetadata {
type Key = BlockHeight;
type OwnedKey = Self::Key;
type Value = DenseMerkleMetadata;
type OwnedValue = Self::Value;
}
pub trait DatabaseColumn {
fn column() -> Column;
}
impl DatabaseColumn for FuelBlockSecondaryKeyBlockHeights {
fn column() -> Column {
Column::FuelBlockSecondaryKeyBlockHeights
}
}
impl DatabaseColumn for FuelBlockMerkleData {
fn column() -> Column {
Column::FuelBlockMerkleData
}
}
impl DatabaseColumn for FuelBlockMerkleMetadata {
fn column() -> Column {
Column::FuelBlockMerkleMetadata
}
}
impl<T> StorageInspect<T> for Database
where
T: Mappable + DatabaseColumn,
T::Key: ToDatabaseKey,
T::OwnedValue: DeserializeOwned,
{
type Error = StorageError;
fn get(&self, key: &T::Key) -> StorageResult<Option<Cow<T::OwnedValue>>> {
self.get(key.database_key().as_ref(), T::column())
.map_err(Into::into)
}
fn contains_key(&self, key: &T::Key) -> StorageResult<bool> {
self.contains_key(key.database_key().as_ref(), T::column())
.map_err(Into::into)
}
}
impl<T> StorageMutate<T> for Database
where
T: Mappable + DatabaseColumn,
T::Key: ToDatabaseKey,
T::Value: Serialize,
T::OwnedValue: DeserializeOwned,
{
fn insert(
&mut self,
key: &T::Key,
value: &T::Value,
) -> StorageResult<Option<T::OwnedValue>> {
Database::insert(self, key.database_key().as_ref(), T::column(), &value)
.map_err(Into::into)
}
fn remove(&mut self, key: &T::Key) -> StorageResult<Option<T::OwnedValue>> {
Database::remove(self, key.database_key().as_ref(), T::column())
.map_err(Into::into)
}
}
pub trait ToDatabaseKey {
type Type<'a>: AsRef<[u8]>
where
Self: 'a;
fn database_key(&self) -> Self::Type<'_>;
}
impl ToDatabaseKey for BlockHeight {
type Type<'a> = [u8; 4];
fn database_key(&self) -> Self::Type<'_> {
self.to_bytes()
}
}
impl ToDatabaseKey for u64 {
type Type<'a> = [u8; 8];
fn database_key(&self) -> Self::Type<'_> {
self.to_be_bytes()
}
}
impl ToDatabaseKey for ContractId {
type Type<'a> = &'a [u8];
fn database_key(&self) -> Self::Type<'_> {
self.as_ref()
}
}
impl ToDatabaseKey for MessageId {
type Type<'a> = &'a [u8];
fn database_key(&self) -> Self::Type<'_> {
self.as_ref()
}
}
impl ToDatabaseKey for BlockId {
type Type<'a> = &'a [u8];
fn database_key(&self) -> Self::Type<'_> {
self.as_slice()
}
}
impl ToDatabaseKey for TxId {
type Type<'a> = &'a [u8];
fn database_key(&self) -> Self::Type<'_> {
self.as_ref()
}
}
impl ToDatabaseKey for () {
type Type<'a> = &'a [u8];
fn database_key(&self) -> Self::Type<'_> {
&[]
}
}