fuel_core/state/historical_rocksdb/
description.rs

1use crate::database::database_description::DatabaseDescription;
2use fuel_core_storage::kv_store::StorageColumn;
3
4pub const HISTORY_COLUMN_ID: u32 = u32::MAX / 2;
5// Avoid conflicts with HistoricalDuplicateColumn indexes, which are
6// in decreasing order starting from HISTORY_COLUMN_ID - 1.
7pub const HISTORY_V2_COLUMN_ID: u32 = HISTORY_COLUMN_ID + 1;
8
9#[derive(Debug, Copy, Clone, enum_iterator::Sequence)]
10pub enum Column<Description>
11where
12    Description: DatabaseDescription,
13{
14    OriginalColumn(Description::Column),
15    HistoricalDuplicateColumn(Description::Column),
16    /// Original history column
17    HistoryColumn,
18    /// Migrated history column
19    HistoryV2Column,
20}
21
22impl<Description> strum::EnumCount for Column<Description>
23where
24    Description: DatabaseDescription,
25{
26    const COUNT: usize = Description::Column::COUNT /* original columns */
27        + Description::Column::COUNT /* duplicated columns */
28        + 2 /* history column, history V2 column */;
29}
30
31impl<Description> StorageColumn for Column<Description>
32where
33    Description: DatabaseDescription,
34{
35    fn name(&self) -> String {
36        match self {
37            Column::OriginalColumn(c) => c.name(),
38            Column::HistoricalDuplicateColumn(c) => {
39                format!("history_{}", c.name())
40            }
41            Column::HistoryColumn => "modifications_history".to_string(),
42            Column::HistoryV2Column => "modifications_history_v2".to_string(),
43        }
44    }
45
46    fn id(&self) -> u32 {
47        match self {
48            Column::OriginalColumn(c) => c.id(),
49            Column::HistoricalDuplicateColumn(c) => {
50                historical_duplicate_column_id(c.id())
51            }
52            Column::HistoryColumn => HISTORY_COLUMN_ID,
53            Column::HistoryV2Column => HISTORY_V2_COLUMN_ID,
54        }
55    }
56}
57
58pub fn historical_duplicate_column_id(id: u32) -> u32 {
59    HISTORY_COLUMN_ID.saturating_sub(1).saturating_sub(id)
60}
61
62#[derive(Debug, Copy, Clone)]
63pub struct Historical<Description> {
64    _maker: core::marker::PhantomData<Description>,
65}
66
67impl<Description> DatabaseDescription for Historical<Description>
68where
69    Description: DatabaseDescription,
70{
71    type Column = Column<Description>;
72    type Height = Description::Height;
73
74    fn version() -> u32 {
75        Description::version()
76    }
77
78    fn name() -> String {
79        Description::name()
80    }
81
82    fn metadata_column() -> Self::Column {
83        Column::OriginalColumn(Description::metadata_column())
84    }
85
86    fn prefix(column: &Self::Column) -> Option<usize> {
87        match column {
88            Column::OriginalColumn(c) => Description::prefix(c),
89            Column::HistoricalDuplicateColumn(c) => {
90                Some(Description::prefix(c).unwrap_or(0).saturating_add(8)) // `u64::to_be_bytes`
91            }
92            Column::HistoryColumn | Column::HistoryV2Column => Some(8),
93        }
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use crate::database::database_description::{
101        DatabaseDescription,
102        off_chain::OffChain,
103        on_chain::OnChain,
104        relayer::Relayer,
105    };
106    use strum::EnumCount;
107
108    #[test]
109    fn iteration_over_all_columns_on_chain() {
110        let variants = enum_iterator::all::<Column<OnChain>>().collect::<Vec<_>>();
111        let original = <OnChain as DatabaseDescription>::Column::COUNT;
112        let duplicated = <OnChain as DatabaseDescription>::Column::COUNT;
113        let history_modification_versions = 2;
114        let expected_count = original + duplicated + history_modification_versions;
115        assert_eq!(variants.len(), expected_count);
116        assert_eq!(<Column<OnChain> as EnumCount>::COUNT, expected_count);
117    }
118
119    #[test]
120    fn iteration_over_all_columns_off_chain() {
121        let variants = enum_iterator::all::<Column<OffChain>>().collect::<Vec<_>>();
122        let original = <OffChain as DatabaseDescription>::Column::COUNT;
123        let duplicated = <OffChain as DatabaseDescription>::Column::COUNT;
124        let history_modification_versions = 2;
125        let expected_count = original + duplicated + history_modification_versions;
126        assert_eq!(variants.len(), expected_count);
127        assert_eq!(<Column<OffChain> as EnumCount>::COUNT, expected_count);
128    }
129
130    #[test]
131    fn iteration_over_all_columns_relayer() {
132        let variants = enum_iterator::all::<Column<Relayer>>().collect::<Vec<_>>();
133        let original = <Relayer as DatabaseDescription>::Column::COUNT;
134        let duplicated = <Relayer as DatabaseDescription>::Column::COUNT;
135        let history_modification_versions = 2;
136        let expected_count = original + duplicated + history_modification_versions;
137        assert_eq!(variants.len(), expected_count);
138        assert_eq!(<Column<Relayer> as EnumCount>::COUNT, expected_count);
139    }
140}