Skip to main content

fuel_core/database/
database_description.rs

1use core::fmt::Debug;
2use fuel_core_storage::kv_store::StorageColumn;
3use fuel_core_types::{
4    blockchain::primitives::DaBlockHeight,
5    fuel_types::BlockHeight,
6};
7use std::collections::HashSet;
8use strum::IntoEnumIterator;
9
10pub mod compression;
11pub mod gas_price;
12pub mod off_chain;
13pub mod on_chain;
14pub mod relayer;
15
16#[cfg(feature = "rpc")]
17pub mod block_aggregator;
18
19pub trait DatabaseHeight: PartialEq + Default + Debug + Copy + Send + Sync {
20    fn as_u64(&self) -> u64;
21
22    fn advance_height(&self) -> Option<Self>;
23
24    fn rollback_height(&self) -> Option<Self>;
25}
26
27impl DatabaseHeight for BlockHeight {
28    fn as_u64(&self) -> u64 {
29        let height: u32 = (*self).into();
30        height as u64
31    }
32
33    fn advance_height(&self) -> Option<Self> {
34        self.succ()
35    }
36
37    fn rollback_height(&self) -> Option<Self> {
38        self.pred()
39    }
40}
41
42impl DatabaseHeight for DaBlockHeight {
43    fn as_u64(&self) -> u64 {
44        self.0
45    }
46
47    fn advance_height(&self) -> Option<Self> {
48        self.0.checked_add(1).map(Into::into)
49    }
50
51    fn rollback_height(&self) -> Option<Self> {
52        self.0.checked_sub(1).map(Into::into)
53    }
54}
55
56/// The description of the database that makes it unique.
57pub trait DatabaseDescription: 'static + Copy + Debug + Send + Sync {
58    /// The type of the column used by the database.
59    type Column: StorageColumn + strum::EnumCount + enum_iterator::Sequence;
60    /// The type of the height of the database used to track commits.
61    type Height: DatabaseHeight;
62
63    /// Returns the expected version of the database.
64    fn version() -> u32;
65
66    /// Returns the name of the database.
67    fn name() -> String;
68
69    /// Returns the column used to store the metadata.
70    fn metadata_column() -> Self::Column;
71
72    /// Returns the prefix for the column.
73    fn prefix(column: &Self::Column) -> Option<usize>;
74}
75
76#[derive(
77    Copy,
78    Clone,
79    Debug,
80    serde::Serialize,
81    serde::Deserialize,
82    Eq,
83    PartialEq,
84    Hash,
85    strum::EnumIter,
86)]
87pub enum IndexationKind {
88    Balances,
89    CoinsToSpend,
90    AssetMetadata,
91}
92
93impl IndexationKind {
94    pub fn all() -> impl Iterator<Item = Self> {
95        Self::iter()
96    }
97}
98
99/// The metadata of the database contains information about the version and its height.
100#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
101pub enum DatabaseMetadata<Height> {
102    V1 {
103        version: u32,
104        height: Height,
105    },
106    V2 {
107        version: u32,
108        height: Height,
109        indexation_availability: HashSet<IndexationKind>,
110    },
111}
112
113impl<Height> DatabaseMetadata<Height> {
114    /// Returns the version of the database.
115    pub fn version(&self) -> u32 {
116        match self {
117            Self::V1 { version, .. } => *version,
118            Self::V2 { version, .. } => *version,
119        }
120    }
121
122    /// Returns the height of the database.
123    pub fn height(&self) -> &Height {
124        match self {
125            Self::V1 { height, .. } => height,
126            Self::V2 { height, .. } => height,
127        }
128    }
129
130    /// Returns true if the given indexation kind is available.
131    pub fn indexation_available(&self, kind: IndexationKind) -> bool {
132        match self {
133            Self::V1 { .. } => false,
134            Self::V2 {
135                indexation_availability,
136                ..
137            } => indexation_availability.contains(&kind),
138        }
139    }
140}
141
142/// Gets the indexation availability from the metadata.
143pub fn indexation_availability<D>(
144    metadata: Option<DatabaseMetadata<D::Height>>,
145) -> HashSet<IndexationKind>
146where
147    D: DatabaseDescription,
148{
149    match metadata {
150        Some(DatabaseMetadata::V1 { .. }) => HashSet::new(),
151        Some(DatabaseMetadata::V2 {
152            indexation_availability,
153            ..
154        }) => indexation_availability.clone(),
155        // If the metadata doesn't exist, it is a new database,
156        // and we should set all indexation kinds to available.
157        None => IndexationKind::all().collect(),
158    }
159}