Skip to content

Commit

Permalink
Use a separate database for each data domain (#1629)
Browse files Browse the repository at this point in the history
Closes #1568

The change splits the `Database` into 3 databases: 
- `Database<OnChain>` - Stores only data required for normal work of the
blockchain.
- `Database<OffChain>` - Stores only data used by the off-chain services
like GraphQL.
- `Database<Relayer>` - Stores relayer-related data like events(messages
or transactions) from L1.

The `Database<Description>` type has a generic `Description` that
implements the `DatabaseDescription` trait:

```rust
/// The description of the database that makes it unique.
pub trait DatabaseDescription: 'static + Clone + Debug + Send + Sync {
    /// The type of the column used by the database.
    type Column: StorageColumn + strum::EnumCount + enum_iterator::Sequence;
    /// The type of the height of the database used to track commits.
    type Height: Copy;

    /// Returns the expected version of the database.
    fn version() -> u32;

    /// Returns the name of the database.
    fn name() -> &'static str;

    /// Returns the column used to store the metadata.
    fn metadata_column() -> Self::Column;

    /// Returns the prefix for the column.
    fn prefix(column: &Self::Column) -> Option<usize>;
}
```

Each database has its folder, defined by the
`DatabaseDescription::name`, where actual data is stored.

<img width="353" alt="image"
src="https://github.com/FuelLabs/fuel-core/assets/18346821/8b642384-0dd4-4668-a415-0748be3e88f0">


Each database has its own `Column` type that describes all columns,
avoiding overlaps with other tables. The change updates a little bit
`StrucutredStorage` implementation and `TableWithBlueprint` to be more
flexible and use the `Column` defined by the table, instead of hardcoded
`fuel_core_storage::column::Column`.


Other small changes:
- Unified the logic of storing the database's metadata. It will be
useful for #1589 to
implement a unified `commit_chagnes` function.
- The `latest_height` function now uses the height from the metadata
table.
- Removed relayers-related tables and columns from the
`fuel-core-storage` crate.
- Removed part of GraphQL tables and columns from the
`fuel-core-storage`. The last part will be removed during
#1583.
- Moved `tx_count` metrics from `BlockImporter` to GraphQL off-chain
worker. Any statistic that requires a persistent state in the database
may be done outside of the blockchain.
- Remove `chain_name` from the database. The `ConsensusParameters`
already contains this information.
- Removed the `checkpoint` function from the `RocksDB` since it is not
used. Later it will be added again back but with another implementation
during #1589.
- Removed `Column::ForeignColumn`, since each database has its own
`Column` type. Removed the macro rules added to handle `ForeignColumn`.
  • Loading branch information
xgreenx committed Feb 2, 2024
1 parent e0b746a commit 114d450
Show file tree
Hide file tree
Showing 74 changed files with 1,745 additions and 1,086 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ Description of the upcoming release here.

#### Breaking
- [#1639](https://github.com/FuelLabs/fuel-core/pull/1639): Make Merkle metadata, i.e. `SparseMerkleMetadata` and `DenseMerkleMetadata` type version-able enums
- [#16232](https://github.com/FuelLabs/fuel-core/pull/1632): Make `Message` type a version-able enum
- [#1632](https://github.com/FuelLabs/fuel-core/pull/1632): Make `Message` type a version-able enum
- [#1629](https://github.com/FuelLabs/fuel-core/pull/1629): Use a separate database for each data domain. Each database has its own folder where data is stored.
- [#1628](https://github.com/FuelLabs/fuel-core/pull/1628): Make `CompressedCoin` type a version-able enum
- [#1616](https://github.com/FuelLabs/fuel-core/pull/1616): Make `BlockHeader` type a version-able enum
- [#1614](https://github.com/FuelLabs/fuel-core/pull/1614): Use the default consensus key regardless of trigger mode. The change is breaking because it removes the `--dev-keys` argument. If the `debug` flag is set, the default consensus key will be used, regardless of the trigger mode.
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions benches/benches/block_target_gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use criterion::{
use ed25519_dalek::Signer;
use ethnum::U256;
use fuel_core::{
combined_database::CombinedDatabase,
service::{
config::Trigger,
Config,
Expand Down Expand Up @@ -325,8 +326,11 @@ fn service_with_many_contracts(
.unwrap();
}

let service = fuel_core::service::FuelService::new(database, config.clone())
.expect("Unable to start a FuelService");
let service = FuelService::new(
CombinedDatabase::new(database, Default::default(), Default::default()),
config.clone(),
)
.expect("Unable to start a FuelService");
service.start().expect("Unable to start the service");
(service, rt)
}
Expand Down Expand Up @@ -456,6 +460,7 @@ fn replace_contract_in_service(
service
.shared
.database
.on_chain_mut()
.storage_as_mut::<ContractsRawCode>()
.insert(contract_id, &contract_bytecode)
.unwrap();
Expand Down
1 change: 1 addition & 0 deletions benches/benches/transaction_throughput.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ where
let block = srv
.shared
.database
.on_chain()
.get_sealed_block_by_height(&1.into())
.unwrap()
.unwrap();
Expand Down
1 change: 1 addition & 0 deletions crates/fuel-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ rocksdb = { version = "0.21", default-features = false, features = [
"lz4",
"multi-threaded-cf",
], optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["raw_value"] }
strum = { workspace = true }
strum_macros = { workspace = true }
Expand Down
13 changes: 7 additions & 6 deletions crates/fuel-core/src/coins_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ mod tests {
CoinsQueryError,
SpendQuery,
},
database::Database,
combined_database::CombinedDatabase,
fuel_core_graphql_api::api_service::ReadDatabase as ServiceDatabase,
query::asset_query::{
AssetQuery,
Expand Down Expand Up @@ -922,7 +922,7 @@ mod tests {
}

pub struct TestDatabase {
database: Database,
database: CombinedDatabase,
last_coin_index: u64,
last_message_index: u64,
}
Expand All @@ -937,8 +937,9 @@ mod tests {
}

fn service_database(&self) -> ServiceDatabase {
let database = self.database.clone();
ServiceDatabase::new(database.clone(), database)
let on_chain = self.database.on_chain().clone();
let off_chain = self.database.off_chain().clone();
ServiceDatabase::new(on_chain, off_chain)
}
}

Expand All @@ -958,7 +959,7 @@ mod tests {
coin.set_amount(amount);
coin.set_asset_id(asset_id);

let db = &mut self.database;
let db = self.database.on_chain_mut();
StorageMutate::<Coins>::insert(db, &id, &coin).unwrap();

coin.uncompress(id)
Expand All @@ -978,7 +979,7 @@ mod tests {
}
.into();

let db = &mut self.database;
let db = self.database.on_chain_mut();
StorageMutate::<Messages>::insert(db, message.id(), &message).unwrap();

message
Expand Down
92 changes: 92 additions & 0 deletions crates/fuel-core/src/combined_database.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use crate::database::{
database_description::{
off_chain::OffChain,
on_chain::OnChain,
relayer::Relayer,
},
Database,
Result as DatabaseResult,
};
use fuel_core_storage::Result as StorageResult;
use fuel_core_types::{
blockchain::primitives::DaBlockHeight,
fuel_types::BlockHeight,
};

/// A database that combines the on-chain, off-chain and relayer databases into one entity.
#[derive(Default, Clone)]
pub struct CombinedDatabase {
on_chain: Database<OnChain>,
off_chain: Database<OffChain>,
relayer: Database<Relayer>,
}

impl CombinedDatabase {
pub fn new(
on_chain: Database<OnChain>,
off_chain: Database<OffChain>,
relayer: Database<Relayer>,
) -> Self {
Self {
on_chain,
off_chain,
relayer,
}
}

#[cfg(feature = "rocksdb")]
pub fn open(path: &std::path::Path, capacity: usize) -> DatabaseResult<Self> {
// TODO: Use different cache sizes for different databases
let on_chain = Database::open(path, capacity)?;
let off_chain = Database::open(path, capacity)?;
let relayer = Database::open(path, capacity)?;
Ok(Self {
on_chain,
off_chain,
relayer,
})
}

pub fn in_memory() -> Self {
Self::new(
Database::in_memory(),
Database::in_memory(),
Database::in_memory(),
)
}

pub fn init(
&mut self,
block_height: &BlockHeight,
da_block_height: &DaBlockHeight,
) -> StorageResult<()> {
self.on_chain.init(block_height)?;
self.off_chain.init(block_height)?;
self.relayer.init(da_block_height)?;
Ok(())
}

pub fn on_chain(&self) -> &Database<OnChain> {
&self.on_chain
}

#[cfg(any(feature = "test-helpers", test))]
pub fn on_chain_mut(&mut self) -> &mut Database<OnChain> {
&mut self.on_chain
}

pub fn off_chain(&self) -> &Database<OffChain> {
&self.off_chain
}

pub fn relayer(&self) -> &Database<Relayer> {
&self.relayer
}

pub fn flush(self) -> DatabaseResult<()> {
self.on_chain.flush()?;
self.off_chain.flush()?;
self.relayer.flush()?;
Ok(())
}
}

0 comments on commit 114d450

Please sign in to comment.