diff --git a/crates/fuel-core/src/combined_database.rs b/crates/fuel-core/src/combined_database.rs index 1cc42680be..a5f527969f 100644 --- a/crates/fuel-core/src/combined_database.rs +++ b/crates/fuel-core/src/combined_database.rs @@ -311,6 +311,21 @@ impl CombinedDatabase { Ok(()) } + + pub fn sync_aux_db_heights(&self, shutdown_listener: &mut S) -> anyhow::Result<()> + where + S: ShutdownListener, + { + if let Some(on_chain_height) = self.on_chain().latest_height_from_metadata()? { + // todo(https://github.com/FuelLabs/fuel-core/issues/2239): This is a temporary fix + let res = self.rollback_to(on_chain_height, shutdown_listener); + if res.is_err() { + tracing::warn!("Failed to rollback auxiliary databases to on-chain database height: {:?}", res); + } + }; + + Ok(()) + } } /// A trait for listening to shutdown signals. diff --git a/crates/fuel-core/src/service.rs b/crates/fuel-core/src/service.rs index 4894a55f69..b0e4bb0459 100644 --- a/crates/fuel-core/src/service.rs +++ b/crates/fuel-core/src/service.rs @@ -134,6 +134,7 @@ impl FuelService { // initialize sub services tracing::info!("Initializing sub services"); + database.sync_aux_db_heights(shutdown_listener)?; let (services, shared) = sub_services::init_sub_services(&config, database)?; let sub_services = Arc::new(services); diff --git a/crates/fuel-core/src/service/adapters/gas_price_adapters.rs b/crates/fuel-core/src/service/adapters/gas_price_adapters.rs index b504335f79..80c426f292 100644 --- a/crates/fuel-core/src/service/adapters/gas_price_adapters.rs +++ b/crates/fuel-core/src/service/adapters/gas_price_adapters.rs @@ -11,9 +11,15 @@ use fuel_core_gas_price_service::{ Error as GasPriceError, Result as GasPriceResult, }, - ports::L2Data, + ports::{ + GasPriceData, + L2Data, + }, +}; +use fuel_core_storage::{ + transactional::HistoricalView, + Result as StorageResult, }; -use fuel_core_storage::Result as StorageResult; use fuel_core_types::{ blockchain::{ block::Block, @@ -23,6 +29,11 @@ use fuel_core_types::{ fuel_types::BlockHeight, }; +use crate::database::{ + database_description::gas_price::GasPriceDatabase, + Database, +}; + #[cfg(test)] mod tests; @@ -39,6 +50,12 @@ impl L2Data for OnChainIterableKeyValueView { } } +impl GasPriceData for Database { + fn latest_height(&self) -> Option { + HistoricalView::latest_height(self) + } +} + impl GasPriceSettingsProvider for ConsensusParametersProvider { fn settings( &self, diff --git a/crates/fuel-core/src/service/sub_services/algorithm_updater.rs b/crates/fuel-core/src/service/sub_services/algorithm_updater.rs index f1d8e7308d..df59d8759a 100644 --- a/crates/fuel-core/src/service/sub_services/algorithm_updater.rs +++ b/crates/fuel-core/src/service/sub_services/algorithm_updater.rs @@ -1,13 +1,6 @@ -use crate::{ - database::{ - database_description::gas_price::GasPriceDatabase, - Database, - RegularStage, - }, - service::{ - adapters::ConsensusParametersProvider, - Config, - }, +use crate::service::{ + adapters::ConsensusParametersProvider, + Config, }; use fuel_core_gas_price_service::{ @@ -19,7 +12,7 @@ use fuel_core_gas_price_service::{ }, fuel_core_storage_adapter::{ get_block_info, - storage::GasPriceMetadata, + storage::GasPriceColumn, FuelL2BlockSource, GasPriceSettings, GasPriceSettingsProvider, @@ -29,11 +22,14 @@ use fuel_core_gas_price_service::{ AlgorithmUpdaterV0, BlockInfo, FuelGasPriceUpdater, - MetadataStorage, UpdaterMetadata, V0Metadata, }, - ports::L2Data, + ports::{ + GasPriceData, + L2Data, + MetadataStorage, + }, GasPriceService, SharedGasPriceAlgo, }; @@ -44,59 +40,58 @@ use fuel_core_services::{ StateWatcher, }; use fuel_core_storage::{ + kv_store::KeyValueInspect, not_found, structured_storage::StructuredStorage, transactional::{ AtomicView, - HistoricalView, + Modifiable, }, - StorageAsRef, }; use fuel_core_types::{ fuel_types::BlockHeight, services::block_importer::SharedImportResult, }; -type Updater = FuelGasPriceUpdater< +type Updater = FuelGasPriceUpdater< FuelL2BlockSource, - MetadataStorageAdapter, + StructuredStorage, DaBlockCostsSharedState, >; -pub struct InitializeTask { +pub struct InitializeTask { pub config: Config, pub genesis_block_height: BlockHeight, pub settings: ConsensusParametersProvider, - pub gas_price_db: Database>, + pub gas_price_db: GasPriceStore, pub on_chain_db: L2DataStoreView, pub block_stream: BoxStream, pub shared_algo: SharedGasPriceAlgo, pub da_block_costs_provider: DaBlockCostsProvider, } -type MetadataStorageAdapter = - StructuredStorage>>; +type Task = GasPriceService>; -type Task = GasPriceService; - -impl InitializeTask +impl + InitializeTask where L2DataStore: L2Data, L2DataStoreView: AtomicView, + GasPriceStore: GasPriceData + Modifiable + KeyValueInspect, { pub fn new( config: Config, genesis_block_height: BlockHeight, settings: ConsensusParametersProvider, block_stream: BoxStream, - gas_price_db: Database>, + mut gas_price_db: GasPriceStore, on_chain_db: L2DataStoreView, ) -> anyhow::Result { let view = on_chain_db.latest_view()?; let latest_block_height = view.latest_height().unwrap_or(genesis_block_height).into(); let default_metadata = get_default_metadata(&config, latest_block_height); - let algo = get_best_algo(&gas_price_db, default_metadata)?; + let algo = get_best_algo(&mut gas_price_db, default_metadata)?; let shared_algo = SharedGasPriceAlgo::new_with_algorithm(algo); // there's no use of this source yet, so we can safely return an error let da_block_costs_source = @@ -128,16 +123,18 @@ fn get_default_metadata(config: &Config, latest_block_height: u32) -> UpdaterMet }) } -fn get_best_algo( - gas_price_db: &Database>, +fn get_best_algo( + gas_price_db: &mut GasPriceStore, default_metadata: UpdaterMetadata, -) -> anyhow::Result { +) -> anyhow::Result +where + GasPriceStore: GasPriceData + Modifiable + KeyValueInspect, +{ let best_metadata: UpdaterMetadata = if let Some(height) = gas_price_db.latest_height() { - gas_price_db - .storage::() - .get(&height)? - .map(|m| m.into_owned()) + let metadata_storage = StructuredStorage::new(gas_price_db); + metadata_storage + .get_metadata(&height)? .unwrap_or(default_metadata) } else { default_metadata @@ -147,14 +144,16 @@ fn get_best_algo( Ok(algo) } #[async_trait::async_trait] -impl RunnableService for InitializeTask +impl RunnableService + for InitializeTask where L2DataStore: L2Data, L2DataStoreView: AtomicView, + GasPriceStore: GasPriceData + Modifiable + KeyValueInspect, { const NAME: &'static str = "GasPriceUpdater"; type SharedData = SharedGasPriceAlgo; - type Task = Task; + type Task = Task; type TaskParams = (); fn shared_data(&self) -> Self::SharedData { @@ -189,18 +188,19 @@ where } } -pub fn get_synced_gas_price_updater( +pub fn get_synced_gas_price_updater( config: Config, genesis_block_height: BlockHeight, settings: ConsensusParametersProvider, - mut gas_price_db: Database>, + gas_price_db: GasPriceStore, on_chain_db: &L2DataStoreView, block_stream: BoxStream, da_block_costs: DaBlockCostsSharedState, -) -> anyhow::Result +) -> anyhow::Result> where L2DataStore: L2Data, L2DataStoreView: AtomicView, + GasPriceStore: GasPriceData + Modifiable + KeyValueInspect, { let mut first_run = false; let latest_block_height: u32 = on_chain_db @@ -210,7 +210,7 @@ where .into(); let maybe_metadata_height = gas_price_db.latest_height(); - let mut metadata_height = if let Some(metadata_height) = maybe_metadata_height { + let metadata_height = if let Some(metadata_height) = maybe_metadata_height { metadata_height.into() } else { first_run = true; @@ -218,20 +218,11 @@ where }; let default_metadata = get_default_metadata(&config, latest_block_height); - if metadata_height > latest_block_height { - revert_gas_price_db_to_height(&mut gas_price_db, latest_block_height.into())?; - metadata_height = gas_price_db - .latest_height() - .ok_or(anyhow::anyhow!( - "Metadata DB height should match the latest block height" - ))? - .into(); - } - - let mut metadata_storage = StructuredStorage::new(gas_price_db); let l2_block_source = FuelL2BlockSource::new(genesis_block_height, settings.clone(), block_stream); + let mut metadata_storage = StructuredStorage::new(gas_price_db); + if BlockHeight::from(latest_block_height) == genesis_block_height || first_run { let updater = FuelGasPriceUpdater::new( default_metadata.into(), @@ -242,7 +233,7 @@ where Ok(updater) } else { if latest_block_height > metadata_height { - sync_metadata_storage_with_on_chain_storage( + sync_gas_price_db_with_on_chain_storage( &settings, &mut metadata_storage, on_chain_db, @@ -264,11 +255,9 @@ where } } -fn sync_metadata_storage_with_on_chain_storage( +fn sync_gas_price_db_with_on_chain_storage( settings: &ConsensusParametersProvider, - metadata_storage: &mut StructuredStorage< - Database>, - >, + metadata_storage: &mut StructuredStorage, on_chain_db: &L2DataStoreView, metadata_height: u32, latest_block_height: u32, @@ -276,6 +265,7 @@ fn sync_metadata_storage_with_on_chain_storage( where L2DataStore: L2Data, L2DataStoreView: AtomicView, + GasPriceStore: GasPriceData + Modifiable + KeyValueInspect, { let metadata = metadata_storage .get_metadata(&metadata_height.into())? @@ -301,19 +291,18 @@ where Ok(()) } -fn sync_v0_metadata( +fn sync_v0_metadata( settings: &ConsensusParametersProvider, on_chain_db: &L2DataStoreView, metadata_height: u32, latest_block_height: u32, updater: &mut AlgorithmUpdaterV0, - metadata_storage: &mut StructuredStorage< - Database>, - >, + metadata_storage: &mut StructuredStorage, ) -> anyhow::Result<()> where L2DataStore: L2Data, L2DataStoreView: AtomicView, + GasPriceStore: GasPriceData + Modifiable + KeyValueInspect, { let first = metadata_height.saturating_add(1); let view = on_chain_db.latest_view()?; @@ -339,23 +328,8 @@ where updater.update_l2_block_data(height, block_gas_used, block_gas_capacity)?; let metadata = AlgorithmUpdater::V0(updater.clone()).into(); - metadata_storage.set_metadata(metadata)?; + metadata_storage.set_metadata(&metadata)?; } Ok(()) } - -fn revert_gas_price_db_to_height( - gas_price_db: &mut Database>, - height: BlockHeight, -) -> anyhow::Result<()> { - if let Some(gas_price_db_height) = gas_price_db.latest_height() { - let gas_price_db_height: u32 = gas_price_db_height.into(); - let height: u32 = height.into(); - let diff = gas_price_db_height.saturating_sub(height); - for _ in 0..diff { - gas_price_db.rollback_last_block()?; - } - } - Ok(()) -} diff --git a/crates/services/gas_price_service/src/fuel_gas_price_updater.rs b/crates/services/gas_price_service/src/fuel_gas_price_updater.rs index 90017c6b9e..8cc7c37e26 100644 --- a/crates/services/gas_price_service/src/fuel_gas_price_updater.rs +++ b/crates/services/gas_price_service/src/fuel_gas_price_updater.rs @@ -1,4 +1,5 @@ use crate::{ + ports::MetadataStorage, GasPriceAlgorithm, UpdateAlgorithm, }; @@ -200,12 +201,6 @@ impl From for UpdaterMetadata { } } -pub trait MetadataStorage: Send + Sync { - fn get_metadata(&self, block_height: &BlockHeight) - -> Result>; - fn set_metadata(&mut self, metadata: UpdaterMetadata) -> Result<()>; -} - impl FuelGasPriceUpdater where Metadata: MetadataStorage, @@ -220,12 +215,13 @@ where exec_gas_price_change_percent: u64, l2_block_fullness_threshold_percent: u64, ) -> Result { - let old_metadata = metadata_storage.get_metadata(&target_block_height)?.ok_or( - Error::CouldNotInitUpdater(anyhow::anyhow!( + let old_metadata = metadata_storage + .get_metadata(&target_block_height) + .map_err(|err| Error::CouldNotInitUpdater(anyhow::anyhow!(err)))? + .ok_or(Error::CouldNotInitUpdater(anyhow::anyhow!( "No metadata found for block height: {:?}", target_block_height - )), - )?; + )))?; let inner = match old_metadata { UpdaterMetadata::V0(old) => { let v0 = AlgorithmUpdaterV0::new( @@ -256,8 +252,9 @@ where } async fn set_metadata(&mut self) -> anyhow::Result<()> { + let metadata = self.inner.clone().into(); self.metadata_storage - .set_metadata(self.inner.clone().into()) + .set_metadata(&metadata) .map_err(|err| anyhow!(err)) } @@ -310,7 +307,7 @@ impl UpdateAlgorithm for FuelGasPriceUpdater where L2: L2BlockSource, - Metadata: MetadataStorage + Send + Sync, + Metadata: MetadataStorage, DaBlockCosts: GetDaBlockCosts, { type Algorithm = Algorithm; diff --git a/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter.rs b/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter.rs index a1e4de8ed8..3b64c17c68 100644 --- a/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter.rs +++ b/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter.rs @@ -1,19 +1,23 @@ use crate::fuel_gas_price_updater::{ - fuel_core_storage_adapter::storage::{ - GasPriceColumn, - GasPriceMetadata, - }, BlockInfo, - Error, Error as GasPriceError, + Error, L2BlockSource, - MetadataStorage, Result, Result as GasPriceResult, UpdaterMetadata, }; use anyhow::anyhow; use fuel_core_services::stream::BoxStream; +use fuel_core_types::fuel_types::BlockHeight; + +use crate::{ + fuel_gas_price_updater::fuel_core_storage_adapter::storage::{ + GasPriceColumn, + GasPriceMetadata, + }, + ports::MetadataStorage, +}; use fuel_core_storage::{ kv_store::KeyValueInspect, structured_storage::StructuredStorage, @@ -24,8 +28,6 @@ use fuel_core_storage::{ StorageAsMut, StorageAsRef, }; -use fuel_core_types::fuel_types::BlockHeight; - use fuel_core_types::{ blockchain::{ block::Block, @@ -69,11 +71,11 @@ where Ok(metadata.map(|inner| inner.into_owned())) } - fn set_metadata(&mut self, metadata: UpdaterMetadata) -> Result<()> { + fn set_metadata(&mut self, metadata: &UpdaterMetadata) -> Result<()> { let block_height = metadata.l2_block_height(); let mut tx = self.write_transaction(); tx.storage_as_mut::() - .insert(&block_height, &metadata) + .insert(&block_height, metadata) .map_err(|err| Error::CouldNotSetMetadata { block_height, source_error: err.into(), diff --git a/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter/metadata_tests.rs b/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter/metadata_tests.rs index 79e6ed748c..070f7087d9 100644 --- a/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter/metadata_tests.rs +++ b/crates/services/gas_price_service/src/fuel_gas_price_updater/fuel_core_storage_adapter/metadata_tests.rs @@ -1,8 +1,10 @@ #![allow(non_snake_case)] +use super::*; use crate::fuel_gas_price_updater::{ fuel_core_storage_adapter::storage::GasPriceColumn, AlgorithmUpdater, + UpdaterMetadata, }; use fuel_core_storage::{ structured_storage::test::InMemoryStorage, @@ -10,12 +12,9 @@ use fuel_core_storage::{ IntoTransaction, StorageTransaction, }, - StorageAsMut, }; use fuel_gas_price_algorithm::v0::AlgorithmUpdaterV0; -use super::*; - fn arb_metadata() -> UpdaterMetadata { let height = 111231u32.into(); arb_metadata_with_l2_height(height) @@ -79,7 +78,7 @@ async fn set_metadata__can_set_metadata() { // when let actual = database.get_metadata(&block_height).unwrap(); assert_eq!(None, actual); - database.set_metadata(metadata.clone()).unwrap(); + database.set_metadata(&metadata).unwrap(); let actual = database.get_metadata(&block_height).unwrap(); // then diff --git a/crates/services/gas_price_service/src/fuel_gas_price_updater/tests.rs b/crates/services/gas_price_service/src/fuel_gas_price_updater/tests.rs index 6a4a669e05..9c4ab7daff 100644 --- a/crates/services/gas_price_service/src/fuel_gas_price_updater/tests.rs +++ b/crates/services/gas_price_service/src/fuel_gas_price_updater/tests.rs @@ -38,15 +38,13 @@ impl FakeMetadata { } impl MetadataStorage for FakeMetadata { - fn get_metadata( - &self, - _block_height: &BlockHeight, - ) -> Result> { - Ok(self.inner.lock().unwrap().clone()) + fn get_metadata(&self, _: &BlockHeight) -> Result> { + let metadata = self.inner.lock().unwrap().clone(); + Ok(metadata) } - fn set_metadata(&mut self, metadata: UpdaterMetadata) -> Result<()> { - let _ = self.inner.lock().unwrap().replace(metadata); + fn set_metadata(&mut self, metadata: &UpdaterMetadata) -> Result<()> { + *self.inner.lock().unwrap() = Some(metadata.clone()); Ok(()) } } diff --git a/crates/services/gas_price_service/src/ports.rs b/crates/services/gas_price_service/src/ports.rs index 7b4169c945..2dd56a8d90 100644 --- a/crates/services/gas_price_service/src/ports.rs +++ b/crates/services/gas_price_service/src/ports.rs @@ -1,3 +1,7 @@ +use crate::fuel_gas_price_updater::{ + Result, + UpdaterMetadata, +}; use fuel_core_storage::Result as StorageResult; use fuel_core_types::{ blockchain::block::Block, @@ -12,3 +16,16 @@ pub trait L2Data: Send + Sync { height: &BlockHeight, ) -> StorageResult>>; } + +pub trait MetadataStorage: Send + Sync { + fn get_metadata(&self, block_height: &BlockHeight) + -> Result>; + fn set_metadata(&mut self, metadata: &UpdaterMetadata) -> Result<()>; +} + +/// Provides the latest block height. +/// This is used to determine the latest block height that has been processed by the gas price service. +/// We need this to fetch the gas price data for the latest block. +pub trait GasPriceData: Send + Sync { + fn latest_height(&self) -> Option; +}