From 310a6dca20b0e83f2514d5fdc95e4618ddc62008 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Sat, 6 Apr 2024 15:35:28 +0200 Subject: [PATCH 01/14] Fetch consensus parameters from the provider --- Cargo.lock | 3 +- bin/fuel-core/src/cli/run.rs | 8 +- crates/chain-config/src/config/consensus.rs | 2 +- crates/fuel-core/src/graphql_api.rs | 7 -- .../fuel-core/src/graphql_api/api_service.rs | 5 + crates/fuel-core/src/graphql_api/ports.rs | 6 ++ crates/fuel-core/src/schema/balance.rs | 10 +- crates/fuel-core/src/schema/chain.rs | 87 +++++++++------- crates/fuel-core/src/schema/coins.rs | 15 ++- crates/fuel-core/src/schema/dap.rs | 73 ++++++++------ crates/fuel-core/src/schema/tx.rs | 38 ++++--- crates/fuel-core/src/schema/tx/types.rs | 12 ++- crates/fuel-core/src/service.rs | 10 +- crates/fuel-core/src/service/adapters.rs | 31 ++++-- .../src/service/adapters/block_importer.rs | 8 +- .../src/service/adapters/consensus_module.rs | 5 +- .../src/service/adapters/graphql_api.rs | 9 ++ .../src/service/adapters/producer.rs | 13 ++- .../fuel-core/src/service/adapters/txpool.rs | 15 ++- crates/fuel-core/src/service/config.rs | 21 +--- crates/fuel-core/src/service/genesis.rs | 5 + crates/fuel-core/src/service/sub_services.rs | 32 +++--- .../consensus_module/poa/src/config.rs | 3 - .../service_test/manually_produce_tests.rs | 4 +- .../poa/src/service_test/trigger_tests.rs | 4 +- .../consensus_module/src/block_verifier.rs | 2 +- .../src/block_verifier/config.rs | 10 +- crates/services/importer/Cargo.toml | 1 - crates/services/importer/src/config.rs | 14 +-- crates/services/importer/src/importer.rs | 21 +++- crates/services/importer/src/importer/test.rs | 18 ++-- crates/services/producer/Cargo.toml | 3 +- .../services/producer/src/block_producer.rs | 37 ++++--- .../producer/src/block_producer/gas_price.rs | 10 ++ .../producer/src/block_producer/tests.rs | 75 ++++++++------ crates/services/producer/src/config.rs | 2 - crates/services/txpool/Cargo.toml | 5 +- crates/services/txpool/src/config.rs | 6 -- crates/services/txpool/src/ports.rs | 27 ++++- crates/services/txpool/src/service.rs | 98 ++++++++++++------- .../txpool/src/service/test_helpers.rs | 27 ++++- crates/services/txpool/src/txpool.rs | 50 +++------- crates/services/txpool/src/txpool/tests.rs | 44 +++++---- crates/types/src/services/txpool.rs | 2 - tests/test-helpers/src/builder.rs | 5 +- 45 files changed, 511 insertions(+), 372 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5eeb87df42..58f9e51f82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3094,7 +3094,6 @@ version = "0.24.2" dependencies = [ "anyhow", "derive_more", - "fuel-core-chain-config", "fuel-core-metrics", "fuel-core-storage", "fuel-core-trace", @@ -3209,6 +3208,7 @@ dependencies = [ "fuel-core-storage", "fuel-core-trace", "fuel-core-types", + "mockall", "rand", "tokio", "tokio-rayon", @@ -3354,7 +3354,6 @@ version = "0.24.2" dependencies = [ "anyhow", "async-trait", - "fuel-core-chain-config", "fuel-core-metrics", "fuel-core-services", "fuel-core-storage", diff --git a/bin/fuel-core/src/cli/run.rs b/bin/fuel-core/src/cli/run.rs index b130bb9991..4dc0ea9b64 100644 --- a/bin/fuel-core/src/cli/run.rs +++ b/bin/fuel-core/src/cli/run.rs @@ -244,7 +244,7 @@ impl Command { SnapshotReader::open(metadata)? } }; - let chain_config = snapshot_reader.chain_config().clone(); + let chain_config = snapshot_reader.chain_config(); #[cfg(feature = "relayer")] let relayer_cfg = relayer_args.into_config(); @@ -298,7 +298,7 @@ impl Command { }; let block_importer = - fuel_core::service::config::fuel_core_importer::Config::new(&chain_config); + fuel_core::service::config::fuel_core_importer::Config::new(); let TxPoolArgs { tx_pool_ttl, @@ -317,7 +317,6 @@ impl Command { tx_blacklist_messages, tx_blacklist_contracts, ); - let block_gas_limit = chain_config.consensus_parameters.block_gas_limit(); let config = Config { addr, @@ -333,7 +332,6 @@ impl Command { txpool: TxPoolConfig::new( tx_max_number, tx_max_depth, - chain_config, utxo_validation, metrics, tx_pool_ttl.into(), @@ -341,10 +339,8 @@ impl Command { blacklist, ), block_producer: ProducerConfig { - utxo_validation, coinbase_recipient, metrics, - block_gas_limit, }, static_gas_price: min_gas_price, block_importer, diff --git a/crates/chain-config/src/config/consensus.rs b/crates/chain-config/src/config/consensus.rs index ae3f8161ef..05cb389329 100644 --- a/crates/chain-config/src/config/consensus.rs +++ b/crates/chain-config/src/config/consensus.rs @@ -10,7 +10,7 @@ use serde::{ use crate as fuel_core_chain_config; use fuel_core_chain_config::default_consensus_dev_key; -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq)] pub enum ConsensusConfig { PoA { signing_key: Address }, } diff --git a/crates/fuel-core/src/graphql_api.rs b/crates/fuel-core/src/graphql_api.rs index 119016ca58..bd1b050664 100644 --- a/crates/fuel-core/src/graphql_api.rs +++ b/crates/fuel-core/src/graphql_api.rs @@ -2,11 +2,6 @@ use fuel_core_storage::{ Error as StorageError, IsNotFound, }; -use fuel_core_types::{ - blockchain::primitives::SecretKeyWrapper, - fuel_tx::ConsensusParameters, - secrecy::Secret, -}; use std::net::SocketAddr; pub mod api_service; @@ -26,8 +21,6 @@ pub struct Config { pub max_tx: usize, pub max_depth: usize, pub chain_name: String, - pub consensus_parameters: ConsensusParameters, - pub consensus_key: Option>, } pub trait IntoApiResult { diff --git a/crates/fuel-core/src/graphql_api/api_service.rs b/crates/fuel-core/src/graphql_api/api_service.rs index 222508af86..1d18bfd504 100644 --- a/crates/fuel-core/src/graphql_api/api_service.rs +++ b/crates/fuel-core/src/graphql_api/api_service.rs @@ -4,6 +4,7 @@ use crate::{ ports::{ BlockProducerPort, ConsensusModulePort, + ConsensusProvider as ConsensusProviderTrait, GasPriceEstimate, OffChainDatabase, OnChainDatabase, @@ -91,6 +92,8 @@ pub type P2pService = Box; pub type GasPriceProvider = Box; +pub type ConsensusProvider = Box; + #[derive(Clone)] pub struct SharedState { pub bound_address: SocketAddr, @@ -177,6 +180,7 @@ pub fn new_service( consensus_module: ConsensusModule, p2p_service: P2pService, gas_price_provider: GasPriceProvider, + consensus_parameters_provider: ConsensusProvider, log_threshold_ms: Duration, request_timeout: Duration, ) -> anyhow::Result @@ -197,6 +201,7 @@ where .data(consensus_module) .data(p2p_service) .data(gas_price_provider) + .data(consensus_parameters_provider) .extension(async_graphql::extensions::Tracing) .extension(MetricsExtension::new(log_threshold_ms)) .extension(ViewExtension::new()) diff --git a/crates/fuel-core/src/graphql_api/ports.rs b/crates/fuel-core/src/graphql_api/ports.rs index 453e2835ae..e13349fe09 100644 --- a/crates/fuel-core/src/graphql_api/ports.rs +++ b/crates/fuel-core/src/graphql_api/ports.rs @@ -32,6 +32,7 @@ use fuel_core_types::{ Message, }, fuel_tx::{ + ConsensusParameters, Salt, Transaction, TxId, @@ -285,3 +286,8 @@ pub mod worker { ); } } + +pub trait ConsensusProvider: Send + Sync { + /// Returns latest consensus parameters. + fn latest_consensus_params(&self) -> Arc; +} diff --git a/crates/fuel-core/src/schema/balance.rs b/crates/fuel-core/src/schema/balance.rs index da5a72ada5..eb2e05eb81 100644 --- a/crates/fuel-core/src/schema/balance.rs +++ b/crates/fuel-core/src/schema/balance.rs @@ -1,7 +1,7 @@ use crate::{ fuel_core_graphql_api::{ + api_service::ConsensusProvider, database::ReadView, - Config, }, query::BalanceQueryData, schema::scalars::{ @@ -58,8 +58,8 @@ impl BalanceQuery { ) -> async_graphql::Result { let query: &ReadView = ctx.data_unchecked(); let base_asset_id = *ctx - .data_unchecked::() - .consensus_parameters + .data_unchecked::() + .latest_consensus_params() .base_asset_id(); let balance = query.balance(owner.0, asset_id.0, base_asset_id)?.into(); Ok(balance) @@ -86,8 +86,8 @@ impl BalanceQuery { crate::schema::query_pagination(after, before, first, last, |_, direction| { let owner = filter.owner.into(); let base_asset_id = *ctx - .data_unchecked::() - .consensus_parameters + .data_unchecked::() + .latest_consensus_params() .base_asset_id(); Ok(query .balances(owner, direction, base_asset_id) diff --git a/crates/fuel-core/src/schema/chain.rs b/crates/fuel-core/src/schema/chain.rs index 97e9b23ffc..e57ff21d1a 100644 --- a/crates/fuel-core/src/schema/chain.rs +++ b/crates/fuel-core/src/schema/chain.rs @@ -1,7 +1,7 @@ use crate::{ fuel_core_graphql_api::{ + api_service::ConsensusProvider, database::ReadView, - Config as GraphQLConfig, }, graphql_api::Config, query::{ @@ -29,10 +29,13 @@ use fuel_core_types::{ fuel_tx, fuel_tx::GasCostsValues, }; -use std::ops::Deref; +use std::{ + ops::Deref, + sync::Arc, +}; pub struct ChainInfo; -pub struct ConsensusParameters(fuel_tx::ConsensusParameters); +pub struct ConsensusParameters(Arc); pub struct TxParameters(fuel_tx::TxParameters); pub struct PredicateParameters(fuel_tx::PredicateParameters); pub struct ScriptParameters(fuel_tx::ScriptParameters); @@ -121,7 +124,7 @@ impl Version { #[Object] impl ConsensusParameters { async fn version(&self) -> ConsensusParametersVersion { - match self.0 { + match self.0.as_ref() { fuel_tx::ConsensusParameters::V1(_) => { ConsensusParametersVersion::V1(Version(1)) } @@ -129,67 +132,71 @@ impl ConsensusParameters { } async fn tx_params(&self, ctx: &Context<'_>) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(TxParameters( - config.consensus_parameters.tx_params().to_owned(), - )) + Ok(TxParameters(params.tx_params().to_owned())) } async fn predicate_params( &self, ctx: &Context<'_>, ) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(PredicateParameters( - config.consensus_parameters.predicate_params().to_owned(), - )) + Ok(PredicateParameters(params.predicate_params().to_owned())) } async fn script_params( &self, ctx: &Context<'_>, ) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(ScriptParameters( - config.consensus_parameters.script_params().to_owned(), - )) + Ok(ScriptParameters(params.script_params().to_owned())) } async fn contract_params( &self, ctx: &Context<'_>, ) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(ContractParameters( - config.consensus_parameters.contract_params().to_owned(), - )) + Ok(ContractParameters(params.contract_params().to_owned())) } async fn fee_params( &self, ctx: &Context<'_>, ) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(FeeParameters( - config.consensus_parameters.fee_params().to_owned(), - )) + Ok(FeeParameters(params.fee_params().to_owned())) } async fn base_asset_id(&self, ctx: &Context<'_>) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(AssetId(*config.consensus_parameters.base_asset_id())) + Ok(AssetId(*params.base_asset_id())) } async fn block_gas_limit(&self, ctx: &Context<'_>) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(config.consensus_parameters.block_gas_limit().into()) + Ok(params.block_gas_limit().into()) } async fn chain_id(&self) -> U64 { @@ -197,18 +204,22 @@ impl ConsensusParameters { } async fn gas_costs(&self, ctx: &Context<'_>) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(GasCosts(config.consensus_parameters.gas_costs().clone())) + Ok(GasCosts(params.gas_costs().clone())) } async fn privileged_address( &self, ctx: &Context<'_>, ) -> async_graphql::Result
{ - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(Address(*config.consensus_parameters.privileged_address())) + Ok(Address(*params.privileged_address())) } } @@ -822,15 +833,19 @@ impl ChainInfo { &self, ctx: &Context<'_>, ) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(ConsensusParameters(config.consensus_parameters.clone())) + Ok(ConsensusParameters(params)) } async fn gas_costs(&self, ctx: &Context<'_>) -> async_graphql::Result { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - Ok(GasCosts(config.consensus_parameters.gas_costs().clone())) + Ok(GasCosts(params.gas_costs().clone())) } } diff --git a/crates/fuel-core/src/schema/coins.rs b/crates/fuel-core/src/schema/coins.rs index 6df3adcd66..3c75b0c4ab 100644 --- a/crates/fuel-core/src/schema/coins.rs +++ b/crates/fuel-core/src/schema/coins.rs @@ -5,9 +5,9 @@ use crate::{ }, fuel_core_graphql_api::{ database::ReadView, - Config as GraphQLConfig, IntoApiResult, }, + graphql_api::api_service::ConsensusProvider, query::{ asset_query::AssetSpendTarget, CoinQueryData, @@ -93,8 +93,11 @@ impl MessageCoin { } async fn asset_id(&self, ctx: &Context<'_>) -> AssetId { - let config = ctx.data_unchecked::(); - let base_asset_id = *config.consensus_parameters.base_asset_id(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); + + let base_asset_id = *params.base_asset_id(); base_asset_id.into() } @@ -208,7 +211,9 @@ impl CoinQuery { ExcludeInput, >, ) -> async_graphql::Result>> { - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); let owner: fuel_tx::Address = owner.0; let query_per_asset = query_per_asset @@ -233,7 +238,7 @@ impl CoinQuery { utxos.chain(messages).collect() }); - let base_asset_id = config.consensus_parameters.base_asset_id(); + let base_asset_id = params.base_asset_id(); let spend_query = SpendQuery::new(owner, &query_per_asset, excluded_ids, *base_asset_id)?; diff --git a/crates/fuel-core/src/schema/dap.rs b/crates/fuel-core/src/schema/dap.rs index b8f24a91fc..d8d8c34881 100644 --- a/crates/fuel-core/src/schema/dap.rs +++ b/crates/fuel-core/src/schema/dap.rs @@ -3,6 +3,7 @@ use crate::{ database_description::on_chain::OnChain, Database, }, + fuel_core_graphql_api::api_service::ConsensusProvider, schema::scalars::{ U32, U64, @@ -59,6 +60,7 @@ use std::{ collections::HashMap, io, sync, + sync::Arc, }; use tracing::{ debug, @@ -73,11 +75,10 @@ pub struct Config { type FrozenDatabase = VmStorage>>; -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct ConcreteStorage { vm: HashMap>, tx: HashMap>, - params: ConsensusParameters, } /// The gas price used for transactions in the debugger. It is set to 0 because @@ -86,12 +87,8 @@ pub struct ConcreteStorage { const GAS_PRICE: u64 = 0; impl ConcreteStorage { - pub fn new(params: ConsensusParameters) -> Self { - Self { - vm: Default::default(), - tx: Default::default(), - params, - } + pub fn new() -> Self { + Self::default() } pub fn register(&self, id: &ID, register: RegisterId) -> Option { @@ -112,15 +109,16 @@ impl ConcreteStorage { pub fn init( &mut self, txs: &[Script], + params: Arc, storage: Database, ) -> anyhow::Result { let id = Uuid::new_v4(); let id = ID::from(id); let vm_database = Self::vm_database(storage)?; - let tx = Self::dummy_tx(self.params.tx_params().max_gas_per_tx() / 2); + let tx = Self::dummy_tx(params.tx_params().max_gas_per_tx() / 2); let checked_tx = tx - .into_checked_basic(vm_database.block_height()?, &self.params) + .into_checked_basic(vm_database.block_height()?, ¶ms) .map_err(|e| anyhow::anyhow!("{:?}", e))?; self.tx .get_mut(&id) @@ -129,8 +127,8 @@ impl ConcreteStorage { self.tx.insert(id.clone(), txs.to_owned()); }); - let gas_costs = self.params.gas_costs(); - let fee_params = self.params.fee_params(); + let gas_costs = params.gas_costs(); + let fee_params = params.fee_params(); let ready_tx = checked_tx .into_ready(GAS_PRICE, gas_costs, fee_params) @@ -138,7 +136,7 @@ impl ConcreteStorage { anyhow!("Failed to apply dynamic values to checked tx: {:?}", e) })?; - let interpreter_params = InterpreterParams::new(GAS_PRICE, &self.params); + let interpreter_params = InterpreterParams::new(GAS_PRICE, params.as_ref()); let mut vm = Interpreter::with_storage(vm_database, interpreter_params); vm.transact(ready_tx).map_err(|e| anyhow::anyhow!(e))?; self.vm.insert(id.clone(), vm); @@ -151,21 +149,26 @@ impl ConcreteStorage { self.vm.remove(id).is_some() } - pub fn reset(&mut self, id: &ID, storage: Database) -> anyhow::Result<()> { + pub fn reset( + &mut self, + id: &ID, + params: Arc, + storage: Database, + ) -> anyhow::Result<()> { let vm_database = Self::vm_database(storage)?; let tx = self .tx .get(id) .and_then(|tx| tx.first()) .cloned() - .unwrap_or(Self::dummy_tx(self.params.tx_params().max_gas_per_tx() / 2)); + .unwrap_or(Self::dummy_tx(params.tx_params().max_gas_per_tx() / 2)); let checked_tx = tx - .into_checked_basic(vm_database.block_height()?, &self.params) + .into_checked_basic(vm_database.block_height()?, ¶ms) .map_err(|e| anyhow::anyhow!("{:?}", e))?; - let gas_costs = self.params.gas_costs(); - let fee_params = self.params.fee_params(); + let gas_costs = params.gas_costs(); + let fee_params = params.fee_params(); let ready_tx = checked_tx .into_ready(GAS_PRICE, gas_costs, fee_params) @@ -173,7 +176,7 @@ impl ConcreteStorage { anyhow!("Failed to apply dynamic values to checked tx: {:?}", e) })?; - let interpreter_params = InterpreterParams::new(GAS_PRICE, &self.params); + let interpreter_params = InterpreterParams::new(GAS_PRICE, params.as_ref()); let mut vm = Interpreter::with_storage(vm_database, interpreter_params); vm.transact(ready_tx).map_err(|e| anyhow::anyhow!(e))?; self.vm.insert(id.clone(), vm).ok_or_else(|| { @@ -234,11 +237,10 @@ pub struct DapMutation; pub fn init( schema: SchemaBuilder, - params: ConsensusParameters, debug_enabled: bool, ) -> SchemaBuilder { schema - .data(GraphStorage::new(Mutex::new(ConcreteStorage::new(params)))) + .data(GraphStorage::new(Mutex::new(ConcreteStorage::new()))) .data(Config { debug_enabled }) } @@ -299,12 +301,15 @@ impl DapMutation { trace!("Initializing new interpreter"); let db = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - let id = ctx - .data_unchecked::() - .lock() - .await - .init(&[], db.clone())?; + let id = ctx.data_unchecked::().lock().await.init( + &[], + params, + db.clone(), + )?; debug!("Session {:?} initialized", id); @@ -329,11 +334,15 @@ impl DapMutation { async fn reset(&self, ctx: &Context<'_>, id: ID) -> async_graphql::Result { require_debug(ctx)?; let db = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); - ctx.data_unchecked::() - .lock() - .await - .reset(&id, db.clone())?; + ctx.data_unchecked::().lock().await.reset( + &id, + params, + db.clone(), + )?; debug!("Session {:?} was reset", id); @@ -417,7 +426,9 @@ impl DapMutation { .map_err(|_| async_graphql::Error::new("Invalid transaction JSON"))?; let mut locked = ctx.data_unchecked::().lock().await; - let params = locked.params.clone(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); let vm = locked .vm diff --git a/crates/fuel-core/src/schema/tx.rs b/crates/fuel-core/src/schema/tx.rs index b1de0a5c9b..522945cda4 100644 --- a/crates/fuel-core/src/schema/tx.rs +++ b/crates/fuel-core/src/schema/tx.rs @@ -2,11 +2,11 @@ use crate::{ fuel_core_graphql_api::{ api_service::{ BlockProducer, + ConsensusProvider, TxPool, }, database::ReadView, ports::OffChainDatabase, - Config, IntoApiResult, }, query::{ @@ -174,7 +174,9 @@ impl TxQuery { ) -> async_graphql::Result> { let query: &ReadView = ctx.data_unchecked(); - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); let owner = fuel_types::Address::from(owner); crate::schema::query_pagination( @@ -189,8 +191,7 @@ impl TxQuery { .owned_transactions(owner, start, direction) .map(|result| { result.map(|(cursor, tx)| { - let tx_id = - tx.id(&config.consensus_parameters.chain_id()); + let tx_id = tx.id(¶ms.chain_id()); (cursor.into(), Transaction::from_tx(tx_id, tx)) }) }); @@ -208,18 +209,17 @@ impl TxQuery { ) -> async_graphql::Result { let mut tx = FuelTx::from_bytes(&tx.0)?; - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); tx.estimate_predicates_async::(&CheckPredicateParams::from( - &config.consensus_parameters, + params.as_ref(), )) .await .map_err(|err| anyhow::anyhow!("{:?}", err))?; - Ok(Transaction::from_tx( - tx.id(&config.consensus_parameters.chain_id()), - tx, - )) + Ok(Transaction::from_tx(tx.id(¶ms.chain_id()), tx)) } #[cfg(feature = "test-helpers")] @@ -248,14 +248,16 @@ impl TxMutation { utxo_validation: Option, ) -> async_graphql::Result> { let block_producer = ctx.data_unchecked::(); - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); let mut transactions = txs .iter() .map(|tx| FuelTx::from_bytes(&tx.0)) .collect::, _>>()?; for transaction in &mut transactions { - transaction.precompute(&config.consensus_parameters.chain_id())?; + transaction.precompute(¶ms.chain_id())?; } let tx_statuses = block_producer @@ -278,7 +280,9 @@ impl TxMutation { tx: HexString, ) -> async_graphql::Result { let txpool = ctx.data_unchecked::(); - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); let tx = FuelTx::from_bytes(&tx.0)?; let _: Vec<_> = txpool @@ -286,7 +290,7 @@ impl TxMutation { .await .into_iter() .try_collect()?; - let id = tx.id(&config.consensus_parameters.chain_id()); + let id = tx.id(¶ms.chain_id()); let tx = Transaction(tx, id); Ok(tx) @@ -343,9 +347,11 @@ impl TxStatusSubscription { impl Stream> + 'a, > { let txpool = ctx.data_unchecked::(); - let config = ctx.data_unchecked::(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); let tx = FuelTx::from_bytes(&tx.0)?; - let tx_id = tx.id(&config.consensus_parameters.chain_id()); + let tx_id = tx.id(¶ms.chain_id()); let subscription = txpool.tx_update_subscribe(tx_id)?; let _: Vec<_> = txpool diff --git a/crates/fuel-core/src/schema/tx/types.rs b/crates/fuel-core/src/schema/tx/types.rs index c65884cf48..a7d3a86dbb 100644 --- a/crates/fuel-core/src/schema/tx/types.rs +++ b/crates/fuel-core/src/schema/tx/types.rs @@ -5,9 +5,11 @@ use super::{ }; use crate::{ fuel_core_graphql_api::{ - api_service::TxPool, + api_service::{ + ConsensusProvider, + TxPool, + }, database::ReadView, - Config, IntoApiResult, }, query::{ @@ -342,8 +344,10 @@ impl Transaction { } async fn input_asset_ids(&self, ctx: &Context<'_>) -> Option> { - let config = ctx.data_unchecked::(); - let base_asset_id = config.consensus_parameters.base_asset_id(); + let params = ctx + .data_unchecked::() + .latest_consensus_params(); + let base_asset_id = params.base_asset_id(); match &self.0 { fuel_tx::Transaction::Script(script) => Some( script diff --git a/crates/fuel-core/src/service.rs b/crates/fuel-core/src/service.rs index 581c448d21..de5d67f508 100644 --- a/crates/fuel-core/src/service.rs +++ b/crates/fuel-core/src/service.rs @@ -2,10 +2,7 @@ use self::adapters::BlockImporterAdapter; use crate::{ combined_database::CombinedDatabase, database::Database, - service::adapters::{ - P2PAdapter, - PoAAdapter, - }, + service::adapters::PoAAdapter, }; use fuel_core_poa::ports::BlockImporter; use fuel_core_services::{ @@ -18,7 +15,7 @@ use fuel_core_services::{ use fuel_core_storage::IsNotFound; use std::net::SocketAddr; -use crate::service::adapters::StaticGasPrice; +use crate::service::sub_services::TxPoolSharedState; pub use config::{ Config, DbType, @@ -39,8 +36,7 @@ pub struct SharedState { /// The PoA adaptor around the shared state of the consensus module. pub poa_adapter: PoAAdapter, /// The transaction pool shared state. - pub txpool_shared_state: - fuel_core_txpool::service::SharedState, + pub txpool_shared_state: TxPoolSharedState, /// The P2P network shared state. #[cfg(feature = "p2p")] pub network: Option, diff --git a/crates/fuel-core/src/service/adapters.rs b/crates/fuel-core/src/service/adapters.rs index 0aadd0e05c..6e06444204 100644 --- a/crates/fuel-core/src/service/adapters.rs +++ b/crates/fuel-core/src/service/adapters.rs @@ -3,17 +3,20 @@ use crate::{ database_description::relayer::Relayer, Database, }, - service::sub_services::BlockProducerService, + service::sub_services::{ + BlockProducerService, + TxPoolSharedState, + }, }; use fuel_core_consensus_module::{ block_verifier::Verifier, RelayerConsensusConfig, }; use fuel_core_services::stream::BoxStream; -use fuel_core_txpool::service::SharedState as TxPoolSharedState; #[cfg(feature = "p2p")] use fuel_core_types::services::p2p::peer_reputation::AppScore; use fuel_core_types::{ + fuel_tx::ConsensusParameters, fuel_types::BlockHeight, services::block_importer::SharedImportResult, }; @@ -33,6 +36,19 @@ pub mod relayer; pub mod sync; pub mod txpool; +#[derive(Debug, Clone)] +pub struct ConsensusParametersProvider { + consensus_parameters: Arc, +} + +impl ConsensusParametersProvider { + pub fn new(consensus_parameters: ConsensusParameters) -> Self { + Self { + consensus_parameters: Arc::new(consensus_parameters), + } + } +} + #[derive(Debug, Clone)] pub struct StaticGasPrice { pub gas_price: u64, @@ -51,26 +67,23 @@ pub struct PoAAdapter { #[derive(Clone)] pub struct TxPoolAdapter { - service: TxPoolSharedState, + service: TxPoolSharedState, } impl TxPoolAdapter { - pub fn new(service: TxPoolSharedState) -> Self { + pub fn new(service: TxPoolSharedState) -> Self { Self { service } } } #[derive(Clone)] pub struct TransactionsSource { - txpool: TxPoolSharedState, + txpool: TxPoolSharedState, _block_height: BlockHeight, } impl TransactionsSource { - pub fn new( - txpool: TxPoolSharedState, - block_height: BlockHeight, - ) -> Self { + pub fn new(txpool: TxPoolSharedState, block_height: BlockHeight) -> Self { Self { txpool, _block_height: block_height, diff --git a/crates/fuel-core/src/service/adapters/block_importer.rs b/crates/fuel-core/src/service/adapters/block_importer.rs index 3b50758a9e..424d476afe 100644 --- a/crates/fuel-core/src/service/adapters/block_importer.rs +++ b/crates/fuel-core/src/service/adapters/block_importer.rs @@ -39,7 +39,10 @@ use fuel_core_types::{ consensus::Consensus, SealedBlock, }, - fuel_types::BlockHeight, + fuel_types::{ + BlockHeight, + ChainId, + }, services::executor::{ ExecutionTypes, Result as ExecutorResult, @@ -50,12 +53,13 @@ use std::sync::Arc; impl BlockImporterAdapter { pub fn new( + chain_id: ChainId, config: Config, database: Database, executor: ExecutorAdapter, verifier: VerifierAdapter, ) -> Self { - let importer = Importer::new(config, database, executor, verifier); + let importer = Importer::new(chain_id, config, database, executor, verifier); importer.init_metrics(); Self { block_importer: Arc::new(importer), diff --git a/crates/fuel-core/src/service/adapters/consensus_module.rs b/crates/fuel-core/src/service/adapters/consensus_module.rs index edb6ca6b3a..5901841857 100644 --- a/crates/fuel-core/src/service/adapters/consensus_module.rs +++ b/crates/fuel-core/src/service/adapters/consensus_module.rs @@ -35,9 +35,8 @@ impl VerifierAdapter { pub fn new(config: &Config, database: Database) -> Self { let block_height = config.snapshot_reader.block_height(); let da_block_height = config.snapshot_reader.da_block_height(); - let chain_config = config.snapshot_reader.chain_config(); - let config = - VerifierConfig::new(chain_config.clone(), block_height, da_block_height); + let consensus = config.snapshot_reader.chain_config().consensus; + let config = VerifierConfig::new(consensus, block_height, da_block_height); Self { block_verifier: Arc::new(Verifier::new(config, database)), } diff --git a/crates/fuel-core/src/service/adapters/graphql_api.rs b/crates/fuel-core/src/service/adapters/graphql_api.rs index ee00e2f4eb..5c02c16e18 100644 --- a/crates/fuel-core/src/service/adapters/graphql_api.rs +++ b/crates/fuel-core/src/service/adapters/graphql_api.rs @@ -1,6 +1,7 @@ use super::{ BlockImporterAdapter, BlockProducerAdapter, + ConsensusParametersProvider, StaticGasPrice, }; use crate::{ @@ -8,6 +9,7 @@ use crate::{ fuel_core_graphql_api::ports::{ worker, BlockProducerPort, + ConsensusProvider, DatabaseMessageProof, GasPriceEstimate, P2pPort, @@ -29,6 +31,7 @@ use fuel_core_types::{ entities::relayer::message::MerkleProof, fuel_tx::{ Bytes32, + ConsensusParameters, Transaction, }, fuel_types::BlockHeight, @@ -170,3 +173,9 @@ impl GasPriceEstimate for StaticGasPrice { self.gas_price } } + +impl ConsensusProvider for ConsensusParametersProvider { + fn latest_consensus_params(&self) -> Arc { + self.consensus_parameters.clone() + } +} diff --git a/crates/fuel-core/src/service/adapters/producer.rs b/crates/fuel-core/src/service/adapters/producer.rs index 4b66456f10..34eb502fab 100644 --- a/crates/fuel-core/src/service/adapters/producer.rs +++ b/crates/fuel-core/src/service/adapters/producer.rs @@ -3,6 +3,7 @@ use crate::{ service::{ adapters::{ BlockProducerAdapter, + ConsensusParametersProvider, ExecutorAdapter, MaybeRelayerAdapter, StaticGasPrice, @@ -15,6 +16,7 @@ use crate::{ use fuel_core_executor::executor::OnceTransactionsSource; use fuel_core_producer::{ block_producer::gas_price::{ + ConsensusParametersProvider as ConsensusParametersProviderTrait, GasPriceParams, GasPriceProvider, }, @@ -45,7 +47,10 @@ use fuel_core_types::{ primitives::DaBlockHeight, }, fuel_tx, - fuel_tx::Transaction, + fuel_tx::{ + ConsensusParameters, + Transaction, + }, fuel_types::{ BlockHeight, Bytes32, @@ -226,3 +231,9 @@ impl GasPriceProvider for StaticGasPrice { Some(self.gas_price) } } + +impl ConsensusParametersProviderTrait for ConsensusParametersProvider { + fn latest_consensus_params(&self) -> Arc { + self.consensus_parameters.clone() + } +} diff --git a/crates/fuel-core/src/service/adapters/txpool.rs b/crates/fuel-core/src/service/adapters/txpool.rs index 8f2aa4c6a0..129cecbcb7 100644 --- a/crates/fuel-core/src/service/adapters/txpool.rs +++ b/crates/fuel-core/src/service/adapters/txpool.rs @@ -2,6 +2,7 @@ use crate::{ database::Database, service::adapters::{ BlockImporterAdapter, + ConsensusParametersProvider, P2PAdapter, StaticGasPrice, }, @@ -17,9 +18,10 @@ use fuel_core_storage::{ Result as StorageResult, StorageAsRef, }; -use fuel_core_txpool::{ - ports::BlockImporter, - txpool::GasPriceProvider, +use fuel_core_txpool::ports::{ + BlockImporter, + ConsensusParametersProvider as ConsensusParametersProviderTrait, + GasPriceProvider, }; use fuel_core_types::{ entities::{ @@ -27,6 +29,7 @@ use fuel_core_types::{ relayer::message::Message, }, fuel_tx::{ + ConsensusParameters, Transaction, UtxoId, }, @@ -143,3 +146,9 @@ impl GasPriceProvider for StaticGasPrice { Some(self.gas_price) } } + +impl ConsensusParametersProviderTrait for ConsensusParametersProvider { + fn latest_consensus_parameters(&self) -> Arc { + self.consensus_parameters.clone() + } +} diff --git a/crates/fuel-core/src/service/config.rs b/crates/fuel-core/src/service/config.rs index 3fe3a91676..c1e2c0ad72 100644 --- a/crates/fuel-core/src/service/config.rs +++ b/crates/fuel-core/src/service/config.rs @@ -69,8 +69,7 @@ impl Config { #[cfg(feature = "test-helpers")] pub fn local_node() -> Self { let snapshot_reader = SnapshotReader::local_testnet(); - let chain_config = snapshot_reader.chain_config().clone(); - let block_importer = fuel_core_importer::Config::new(&chain_config); + let block_importer = fuel_core_importer::Config::new(); let utxo_validation = false; let min_gas_price = 0; @@ -95,7 +94,6 @@ impl Config { vm: Default::default(), utxo_validation, txpool: fuel_core_txpool::Config { - chain_config, utxo_validation, transaction_ttl: Duration::from_secs(60 * 100000000), ..fuel_core_txpool::Config::default() @@ -131,25 +129,10 @@ impl Config { self.utxo_validation = true; } - let chain_config = self.snapshot_reader.chain_config(); - if self.txpool.chain_config != *chain_config { - tracing::warn!("The `ChainConfig` of `TxPool` was inconsistent"); - self.txpool.chain_config = chain_config.clone(); - } - - if self.block_importer.chain_id != chain_config.consensus_parameters.chain_id() { - tracing::warn!("The `ChainConfig` of `BlockImporter` was inconsistent"); - self.block_importer.chain_id = chain_config.consensus_parameters.chain_id() - } - if self.txpool.utxo_validation != self.utxo_validation { tracing::warn!("The `utxo_validation` of `TxPool` was inconsistent"); self.txpool.utxo_validation = self.utxo_validation; } - if self.block_producer.utxo_validation != self.utxo_validation { - tracing::warn!("The `utxo_validation` of `BlockProducer` was inconsistent"); - self.block_producer.utxo_validation = self.utxo_validation; - } self } @@ -157,12 +140,10 @@ impl Config { impl From<&Config> for fuel_core_poa::Config { fn from(config: &Config) -> Self { - let chain_config = config.snapshot_reader.chain_config(); fuel_core_poa::Config { trigger: config.block_production, signing_key: config.consensus_key.clone(), metrics: false, - consensus_params: chain_config.consensus_parameters.clone(), min_connected_reserved_peers: config.min_connected_reserved_peers, time_until_synced: config.time_until_synced, } diff --git a/crates/fuel-core/src/service/genesis.rs b/crates/fuel-core/src/service/genesis.rs index 5c1a9c2068..c3f718a473 100644 --- a/crates/fuel-core/src/service/genesis.rs +++ b/crates/fuel-core/src/service/genesis.rs @@ -137,6 +137,11 @@ pub async fn execute_and_commit_genesis_block( ) -> anyhow::Result<()> { let result = execute_genesis_block(config, db).await?; let importer = fuel_core_importer::Importer::new( + config + .snapshot_reader + .chain_config() + .consensus_parameters + .chain_id(), config.block_importer.clone(), db.on_chain().clone(), (), diff --git a/crates/fuel-core/src/service/sub_services.rs b/crates/fuel-core/src/service/sub_services.rs index 32531c5d18..58e0bf813c 100644 --- a/crates/fuel-core/src/service/sub_services.rs +++ b/crates/fuel-core/src/service/sub_services.rs @@ -13,9 +13,11 @@ use crate::{ adapters::{ BlockImporterAdapter, BlockProducerAdapter, + ConsensusParametersProvider, ExecutorAdapter, MaybeRelayerAdapter, PoAAdapter, + StaticGasPrice, TxPoolAdapter, VerifierAdapter, }, @@ -30,7 +32,6 @@ use tokio::sync::Mutex; #[cfg(feature = "relayer")] use crate::relayer::Config as RelayerConfig; -use crate::service::StaticGasPrice; #[cfg(feature = "relayer")] use fuel_core_types::blockchain::primitives::DaBlockHeight; @@ -38,12 +39,18 @@ pub type PoAService = fuel_core_poa::Service; #[cfg(feature = "p2p")] pub type P2PService = fuel_core_p2p::service::Service; -pub type TxPoolService = fuel_core_txpool::Service; +pub type TxPoolSharedState = fuel_core_txpool::service::SharedState< + P2PAdapter, + Database, + StaticGasPrice, + ConsensusParametersProvider, +>; pub type BlockProducerService = fuel_core_producer::block_producer::Producer< Database, TxPoolAdapter, ExecutorAdapter, StaticGasPrice, + ConsensusParametersProvider, >; pub type GraphQL = fuel_core_graphql_api::api_service::Service; @@ -60,6 +67,7 @@ pub fn init_sub_services( block.header().clone() }); let last_height = *last_block_header.height(); + let chain_config = config.snapshot_reader.chain_config(); let executor = ExecutorAdapter::new( database.on_chain().clone(), @@ -73,6 +81,7 @@ pub fn init_sub_services( let verifier = VerifierAdapter::new(config, database.on_chain().clone()); let importer_adapter = BlockImporterAdapter::new( + chain_config.consensus_parameters.chain_id(), config.block_importer.clone(), database.on_chain().clone(), executor.clone(), @@ -101,7 +110,6 @@ pub fn init_sub_services( #[cfg(feature = "p2p")] let mut network = config.p2p.clone().map(|p2p_config| { - let chain_config = config.snapshot_reader.chain_config(); fuel_core_p2p::service::new_service( chain_config.consensus_parameters.chain_id(), p2p_config, @@ -133,6 +141,8 @@ pub fn init_sub_services( let p2p_adapter = P2PAdapter::new(); let gas_price_provider = StaticGasPrice::new(config.static_gas_price); + let consensus_parameters_provider = + ConsensusParametersProvider::new(chain_config.consensus_parameters.clone()); let txpool = fuel_core_txpool::new_service( config.txpool.clone(), database.on_chain().clone(), @@ -140,6 +150,7 @@ pub fn init_sub_services( p2p_adapter.clone(), last_height, gas_price_provider.clone(), + consensus_parameters_provider.clone(), ); let tx_pool_adapter = TxPoolAdapter::new(txpool.shared.clone()); @@ -151,6 +162,7 @@ pub fn init_sub_services( relayer: Box::new(relayer_adapter.clone()), lock: Mutex::new(()), gas_price_provider: gas_price_provider.clone(), + consensus_parameters_provider: consensus_parameters_provider.clone(), }; let producer_adapter = BlockProducerAdapter::new(block_producer); @@ -187,14 +199,8 @@ pub fn init_sub_services( config.sync, )?; - // TODO: Figure out on how to move it into `fuel-core-graphql-api`. - let chain_config = config.snapshot_reader.chain_config(); - let schema = crate::schema::dap::init( - build_schema(), - chain_config.consensus_parameters.clone(), - config.debug, - ) - .data(database.on_chain().clone()); + let schema = crate::schema::dap::init(build_schema(), config.debug) + .data(database.on_chain().clone()); let graphql_worker = fuel_core_graphql_api::worker_service::new_service( tx_pool_adapter.clone(), @@ -203,7 +209,6 @@ pub fn init_sub_services( chain_config.consensus_parameters.chain_id(), ); - let chain_config = config.snapshot_reader.chain_config(); let graphql_config = GraphQLConfig { addr: config.addr, utxo_validation: config.utxo_validation, @@ -212,8 +217,6 @@ pub fn init_sub_services( max_tx: config.txpool.max_tx, max_depth: config.txpool.max_depth, chain_name: chain_config.chain_name.clone(), - consensus_parameters: chain_config.consensus_parameters.clone(), - consensus_key: config.consensus_key.clone(), }; let graph_ql = fuel_core_graphql_api::api_service::new_service( @@ -226,6 +229,7 @@ pub fn init_sub_services( Box::new(poa_adapter.clone()), Box::new(p2p_adapter), Box::new(gas_price_provider), + Box::new(consensus_parameters_provider), config.query_log_threshold_time, config.api_request_timeout, )?; diff --git a/crates/services/consensus_module/poa/src/config.rs b/crates/services/consensus_module/poa/src/config.rs index 07bbc818e2..83f8596b23 100644 --- a/crates/services/consensus_module/poa/src/config.rs +++ b/crates/services/consensus_module/poa/src/config.rs @@ -1,6 +1,5 @@ use fuel_core_types::{ blockchain::primitives::SecretKeyWrapper, - fuel_tx::ConsensusParameters, secrecy::Secret, }; use tokio::time::Duration; @@ -10,7 +9,6 @@ pub struct Config { pub trigger: Trigger, pub signing_key: Option>, pub metrics: bool, - pub consensus_params: ConsensusParameters, pub min_connected_reserved_peers: usize, pub time_until_synced: Duration, } @@ -22,7 +20,6 @@ impl Default for Config { trigger: Trigger::default(), signing_key: None, metrics: false, - consensus_params: ConsensusParameters::default(), min_connected_reserved_peers: 0, time_until_synced: Duration::ZERO, } diff --git a/crates/services/consensus_module/poa/src/service_test/manually_produce_tests.rs b/crates/services/consensus_module/poa/src/service_test/manually_produce_tests.rs index 1acbe0f5fa..836324272d 100644 --- a/crates/services/consensus_module/poa/src/service_test/manually_produce_tests.rs +++ b/crates/services/consensus_module/poa/src/service_test/manually_produce_tests.rs @@ -50,12 +50,10 @@ async fn can_manually_produce_block( ) { let mut rng = StdRng::seed_from_u64(1234u64); let mut ctx_builder = TestContextBuilder::new(); - let consensus_params = ConsensusParameters::default(); ctx_builder.with_config(Config { trigger, signing_key: Some(test_signing_key()), metrics: false, - consensus_params: consensus_params.clone(), ..Default::default() }); @@ -106,7 +104,7 @@ async fn can_manually_produce_block( .await .unwrap(); for tx in txs { - status_sender.send_replace(Some(tx.id(&consensus_params.chain_id()))); + status_sender.send_replace(Some(tx.id(&ChainId::default()))); } for t in times.into_iter() { diff --git a/crates/services/consensus_module/poa/src/service_test/trigger_tests.rs b/crates/services/consensus_module/poa/src/service_test/trigger_tests.rs index dd42ecf94f..f6460b4fd9 100644 --- a/crates/services/consensus_module/poa/src/service_test/trigger_tests.rs +++ b/crates/services/consensus_module/poa/src/service_test/trigger_tests.rs @@ -29,12 +29,10 @@ async fn never_trigger_never_produces_blocks() { const TX_COUNT: usize = 10; let mut rng = StdRng::seed_from_u64(1234u64); let mut ctx_builder = TestContextBuilder::new(); - let consensus_params = ConsensusParameters::default(); ctx_builder.with_config(Config { trigger: Trigger::Never, signing_key: Some(test_signing_key()), metrics: false, - consensus_params: consensus_params.clone(), ..Default::default() }); @@ -57,7 +55,7 @@ async fn never_trigger_never_produces_blocks() { ctx_builder.with_importer(importer); let ctx = ctx_builder.build(); for tx in txs { - status_sender.send_replace(Some(tx.id(&consensus_params.chain_id()))); + status_sender.send_replace(Some(tx.id(&ChainId::default()))); } // Make sure enough time passes for the block to be produced diff --git a/crates/services/consensus_module/src/block_verifier.rs b/crates/services/consensus_module/src/block_verifier.rs index d64ba82531..e7c931383e 100644 --- a/crates/services/consensus_module/src/block_verifier.rs +++ b/crates/services/consensus_module/src/block_verifier.rs @@ -81,7 +81,7 @@ where match consensus { Consensus::Genesis(_) => true, Consensus::PoA(consensus) => fuel_core_poa::verifier::verify_consensus( - &self.config.chain_config.consensus, + &self.config.consensus, header, consensus, ), diff --git a/crates/services/consensus_module/src/block_verifier/config.rs b/crates/services/consensus_module/src/block_verifier/config.rs index 24e9464ed9..64601f41f5 100644 --- a/crates/services/consensus_module/src/block_verifier/config.rs +++ b/crates/services/consensus_module/src/block_verifier/config.rs @@ -1,6 +1,6 @@ //! The config of the block verifier. -use fuel_core_chain_config::ChainConfig; +use fuel_core_chain_config::ConsensusConfig; use fuel_core_types::{ blockchain::primitives::DaBlockHeight, fuel_types::BlockHeight, @@ -8,8 +8,8 @@ use fuel_core_types::{ /// The config of the block verifier. pub struct Config { - /// The chain configuration. - pub chain_config: ChainConfig, + /// The consensus config. + pub consensus: ConsensusConfig, /// The block height of the genesis block. pub block_height: BlockHeight, /// The DA block height at genesis block. @@ -19,12 +19,12 @@ pub struct Config { impl Config { /// Creates the verifier config for all possible consensuses. pub fn new( - chain_config: ChainConfig, + consensus: ConsensusConfig, block_height: BlockHeight, da_block_height: DaBlockHeight, ) -> Self { Self { - chain_config, + consensus, block_height, da_block_height, } diff --git a/crates/services/importer/Cargo.toml b/crates/services/importer/Cargo.toml index 6b47a8272f..a5a56c2766 100644 --- a/crates/services/importer/Cargo.toml +++ b/crates/services/importer/Cargo.toml @@ -12,7 +12,6 @@ description = "Fuel Block Importer" [dependencies] anyhow = { workspace = true } derive_more = { workspace = true } -fuel-core-chain-config = { workspace = true } fuel-core-metrics = { workspace = true } fuel-core-storage = { workspace = true } fuel-core-types = { workspace = true } diff --git a/crates/services/importer/src/config.rs b/crates/services/importer/src/config.rs index 20250a4dc2..e8347ae2ef 100644 --- a/crates/services/importer/src/config.rs +++ b/crates/services/importer/src/config.rs @@ -1,30 +1,20 @@ -use fuel_core_chain_config::ChainConfig; -use fuel_core_types::fuel_types::ChainId; - #[derive(Debug, Clone)] pub struct Config { pub max_block_notify_buffer: usize, pub metrics: bool, - pub chain_id: ChainId, } impl Config { - pub fn new(chain_config: &ChainConfig) -> Self { + pub fn new() -> Self { Self { max_block_notify_buffer: 1 << 10, metrics: false, - chain_id: chain_config.consensus_parameters.chain_id(), } } } -#[cfg(test)] impl Default for Config { fn default() -> Self { - Self { - max_block_notify_buffer: 1, - metrics: false, - chain_id: ChainId::default(), - } + Self::new() } } diff --git a/crates/services/importer/src/importer.rs b/crates/services/importer/src/importer.rs index 638d36f4ff..dbd524ae7a 100644 --- a/crates/services/importer/src/importer.rs +++ b/crates/services/importer/src/importer.rs @@ -127,20 +127,37 @@ pub struct Importer { } impl Importer { - pub fn new(config: Config, database: D, executor: E, verifier: V) -> Self { + pub fn new( + chain_id: ChainId, + config: Config, + database: D, + executor: E, + verifier: V, + ) -> Self { let (broadcast, _) = broadcast::channel(config.max_block_notify_buffer); Self { database: Mutex::new(database), executor: Arc::new(executor), verifier: Arc::new(verifier), - chain_id: config.chain_id, + chain_id, broadcast, prev_block_process_result: Default::default(), guard: tokio::sync::Semaphore::new(1), } } + #[cfg(test)] + pub fn default_config(database: D, executor: E, verifier: V) -> Self { + Self::new( + Default::default(), + Default::default(), + database, + executor, + verifier, + ) + } + pub fn subscribe(&self) -> broadcast::Receiver { self.broadcast.subscribe() } diff --git a/crates/services/importer/src/importer/test.rs b/crates/services/importer/src/importer/test.rs index b52a077265..d0b2a0e989 100644 --- a/crates/services/importer/src/importer/test.rs +++ b/crates/services/importer/src/importer/test.rs @@ -358,7 +358,7 @@ async fn commit_result_assert( .expect_storage_transaction() .return_once(|_| db_transaction); let expected_to_broadcast = sealed_block.clone(); - let importer = Importer::new(Default::default(), underlying_db, (), ()); + let importer = Importer::default_config(underlying_db, (), ()); let uncommitted_result = UncommittedResult::new( ImportResult::new_from_local(sealed_block, vec![], vec![]), Default::default(), @@ -387,7 +387,7 @@ async fn execute_and_commit_assert( verifier: MockBlockVerifier, ) -> Result<(), Error> { let expected_to_broadcast = sealed_block.clone(); - let importer = Importer::new(Default::default(), underlying_db, executor, verifier); + let importer = Importer::default_config(underlying_db, executor, verifier); let mut imported_blocks = importer.subscribe(); let result = importer.execute_and_commit(sealed_block).await; @@ -408,7 +408,7 @@ async fn execute_and_commit_assert( #[tokio::test] async fn commit_result_fail_when_locked() { - let importer = Importer::new(Default::default(), MockDatabase::default(), (), ()); + let importer = Importer::default_config(MockDatabase::default(), (), ()); let uncommitted_result = UncommittedResult::new(ImportResult::default(), Default::default()); @@ -421,8 +421,7 @@ async fn commit_result_fail_when_locked() { #[tokio::test] async fn execute_and_commit_fail_when_locked() { - let importer = Importer::new( - Default::default(), + let importer = Importer::default_config( MockDatabase::default(), MockExecutor::default(), MockBlockVerifier::default(), @@ -437,8 +436,7 @@ async fn execute_and_commit_fail_when_locked() { #[test] fn one_lock_at_the_same_time() { - let importer = Importer::new( - Default::default(), + let importer = Importer::default_config( MockDatabase::default(), MockExecutor::default(), MockBlockVerifier::default(), @@ -534,8 +532,7 @@ where P: Fn() -> ExecutorResult + Send + 'static, V: Fn() -> anyhow::Result<()> + Send + 'static, { - let importer = Importer::new( - Default::default(), + let importer = Importer::default_config( MockDatabase::default(), executor(block_after_execution), verifier(verifier_result), @@ -546,8 +543,7 @@ where #[test] fn verify_and_execute_allowed_when_locked() { - let importer = Importer::new( - Default::default(), + let importer = Importer::default_config( MockDatabase::default(), executor(ok(ex_result(13, 0))), verifier(ok(())), diff --git a/crates/services/producer/Cargo.toml b/crates/services/producer/Cargo.toml index fee135e14b..51c7b3aee5 100644 --- a/crates/services/producer/Cargo.toml +++ b/crates/services/producer/Cargo.toml @@ -15,6 +15,7 @@ async-trait = { workspace = true } derive_more = { workspace = true } fuel-core-storage = { workspace = true } fuel-core-types = { workspace = true } +mockall = { workspace = true, optional = true } tokio = { workspace = true, features = ["full"] } tokio-rayon = { workspace = true } tracing = { workspace = true } @@ -26,4 +27,4 @@ fuel-core-types = { path = "../../types", features = ["test-helpers"] } rand = { workspace = true } [features] -test-helpers = ["fuel-core-types/test-helpers"] +test-helpers = ["dep:mockall", "fuel-core-types/test-helpers"] diff --git a/crates/services/producer/src/block_producer.rs b/crates/services/producer/src/block_producer.rs index ca01d35b65..d60b3a939a 100644 --- a/crates/services/producer/src/block_producer.rs +++ b/crates/services/producer/src/block_producer.rs @@ -1,5 +1,8 @@ use crate::{ - block_producer::gas_price::GasPriceProvider as GasPriceProviderConstraint, + block_producer::gas_price::{ + ConsensusParametersProvider, + GasPriceProvider as GasPriceProviderConstraint, + }, ports, ports::BlockProducerDatabase, Config, @@ -72,7 +75,7 @@ impl From for anyhow::Error { } } -pub struct Producer { +pub struct Producer { pub config: Config, pub view_provider: ViewProvider, pub txpool: TxPool, @@ -82,14 +85,16 @@ pub struct Producer { // execution has completed (which may take a while). pub lock: Mutex<()>, pub gas_price_provider: GasPriceProvider, + pub consensus_parameters_provider: ConsensusProvider, } -impl - Producer +impl + Producer where ViewProvider: AtomicView + 'static, ViewProvider::View: BlockProducerDatabase, GasPriceProvider: GasPriceProviderConstraint, + ConsensusProvider: ConsensusParametersProvider, { /// Produces and execute block for the specified height. async fn produce_and_execute( @@ -142,14 +147,15 @@ where } } -impl - Producer +impl + Producer where ViewProvider: AtomicView + 'static, ViewProvider::View: BlockProducerDatabase, TxPool: ports::TxPool + 'static, Executor: ports::Executor + 'static, GasPriceProvider: GasPriceProviderConstraint, + ConsensusProvider: ConsensusParametersProvider, { /// Produces and execute block for the specified height with transactions from the `TxPool`. pub async fn produce_and_execute_block_txpool( @@ -164,13 +170,14 @@ where } } -impl - Producer +impl + Producer where ViewProvider: AtomicView + 'static, ViewProvider::View: BlockProducerDatabase, Executor: ports::Executor> + 'static, GasPriceProvider: GasPriceProviderConstraint, + ConsensusProvider: ConsensusParametersProvider, { /// Produces and execute block for the specified height with `transactions`. pub async fn produce_and_execute_block_transactions( @@ -184,13 +191,14 @@ where } } -impl - Producer +impl + Producer where ViewProvider: AtomicView + 'static, ViewProvider::View: BlockProducerDatabase, Executor: ports::DryRunner + 'static, GasPriceProvider: GasPriceProviderConstraint, + ConsensusProvider: ConsensusParametersProvider, { // TODO: Support custom `block_time` for `dry_run`. /// Simulates multiple transactions without altering any state. Does not acquire the production lock. @@ -254,10 +262,12 @@ where pub const NO_NEW_DA_HEIGHT_FOUND: &str = "No new da_height found"; -impl Producer +impl + Producer where ViewProvider: AtomicView + 'static, ViewProvider::View: BlockProducerDatabase, + ConsensusProvider: ConsensusParametersProvider, { /// Create the header for a new block at the provided height async fn new_header( @@ -278,7 +288,10 @@ where &self, previous_da_height: DaBlockHeight, ) -> anyhow::Result { - let gas_limit = self.config.block_gas_limit; + let gas_limit = self + .consensus_parameters_provider + .latest_consensus_params() + .block_gas_limit(); let mut new_best = previous_da_height; let mut total_cost: u64 = 0; let highest = self diff --git a/crates/services/producer/src/block_producer/gas_price.rs b/crates/services/producer/src/block_producer/gas_price.rs index c5d186481c..18e47ea613 100644 --- a/crates/services/producer/src/block_producer/gas_price.rs +++ b/crates/services/producer/src/block_producer/gas_price.rs @@ -1,4 +1,5 @@ use fuel_core_types::fuel_types::BlockHeight; +use std::sync::Arc; /// The parameters required to retrieve the gas price for a block pub struct GasPriceParams { @@ -27,3 +28,12 @@ pub trait GasPriceProvider { /// The gas price for all transactions in the block. fn gas_price(&self, params: GasPriceParams) -> Option; } + +/// Interface for retrieving the latest consensus parameters. +#[cfg_attr(feature = "test-helpers", mockall::automock)] +pub trait ConsensusParametersProvider { + /// Retrieve the latest consensus parameters. + fn latest_consensus_params( + &self, + ) -> Arc; +} diff --git a/crates/services/producer/src/block_producer/tests.rs b/crates/services/producer/src/block_producer/tests.rs index 6d8e14296a..849b3394f6 100644 --- a/crates/services/producer/src/block_producer/tests.rs +++ b/crates/services/producer/src/block_producer/tests.rs @@ -5,6 +5,7 @@ use crate::{ gas_price::{ GasPriceParams, GasPriceProvider, + MockConsensusParametersProvider, }, Error, }, @@ -33,6 +34,7 @@ use fuel_core_types::{ }, primitives::DaBlockHeight, }, + fuel_tx::ConsensusParameters, fuel_types::BlockHeight, services::executor::Error as ExecutorError, tai64::Tai64, @@ -55,14 +57,8 @@ pub struct MockProducerGasPrice { } impl MockProducerGasPrice { - pub fn new(gas_price: u64) -> Self { - Self { - gas_price: Some(gas_price), - } - } - - pub fn new_none() -> Self { - Self { gas_price: None } + pub fn new(gas_price: Option) -> Self { + Self { gas_price } } } @@ -496,11 +492,10 @@ mod produce_and_execute_block_txpool { async fn produce_and_execute_block_txpool__executor_receives_gas_price_provided() { // given let gas_price = 1_000; - let gas_price_provider = MockProducerGasPrice::new(gas_price); let executor = MockExecutorWithCapture::default(); let ctx = TestContext::default_from_executor(executor.clone()); - let producer = ctx.producer_with_gas_price_provider(gas_price_provider); + let producer = ctx.producer_with_gas_price(Some(gas_price)); // when let _ = producer @@ -522,9 +517,8 @@ mod produce_and_execute_block_txpool { async fn produce_and_execute_block_txpool__missing_gas_price_causes_block_production_to_fail( ) { // given - let gas_price_provider = MockProducerGasPrice::new_none(); let ctx = TestContext::default(); - let producer = ctx.producer_with_gas_price_provider(gas_price_provider); + let producer = ctx.producer_with_gas_price(None); // when let result = producer @@ -542,7 +536,8 @@ struct TestContext { relayer: MockRelayer, executor: Arc, txpool: MockTxPool, - gas_price: u64, + gas_price: Option, + block_gas_limit: u64, } impl TestContext { @@ -578,7 +573,7 @@ impl TestContext { let txpool = MockTxPool::default(); let relayer = MockRelayer::default(); let config = Config::default(); - let gas_price = 0; + let gas_price = Some(0); Self { config, db, @@ -586,24 +581,32 @@ impl TestContext { executor: Arc::new(executor), txpool, gas_price, + block_gas_limit: 0, } } pub fn producer( self, - ) -> Producer { + ) -> Producer< + MockDb, + MockTxPool, + Executor, + MockProducerGasPrice, + MockConsensusParametersProvider, + > { let gas_price = self.gas_price; let static_gas_price = MockProducerGasPrice::new(gas_price); - self.producer_with_gas_price_provider(static_gas_price) - } - pub fn producer_with_gas_price_provider( - self, - gas_price_provider: GasPrice, - ) -> Producer - where - GasPrice: GasPriceProvider, - { + let mut consensus_params = ConsensusParameters::default(); + consensus_params.set_block_gas_limit(self.block_gas_limit); + let consensus_params = Arc::new(consensus_params); + + let mut consensus_parameters_provider = + MockConsensusParametersProvider::default(); + consensus_parameters_provider + .expect_latest_consensus_params() + .returning(move || consensus_params.clone()); + Producer { config: self.config, view_provider: self.db, @@ -611,9 +614,24 @@ impl TestContext { executor: self.executor, relayer: Box::new(self.relayer), lock: Default::default(), - gas_price_provider, + gas_price_provider: static_gas_price, + consensus_parameters_provider, } } + + pub fn producer_with_gas_price( + mut self, + gas_price: Option, + ) -> Producer< + MockDb, + MockTxPool, + Executor, + MockProducerGasPrice, + MockConsensusParametersProvider, + > { + self.gas_price = gas_price; + self.producer() + } } struct TestContextBuilder { @@ -698,14 +716,9 @@ impl TestContextBuilder { ..Default::default() }; - let config = Config { - block_gas_limit: self.block_gas_limit.unwrap_or_default(), - ..Default::default() - }; - TestContext { - config, relayer: mock_relayer, + block_gas_limit: self.block_gas_limit.unwrap_or_default(), ..TestContext::default_from_db(db) } } diff --git a/crates/services/producer/src/config.rs b/crates/services/producer/src/config.rs index 8f5257e719..f702e8ec56 100644 --- a/crates/services/producer/src/config.rs +++ b/crates/services/producer/src/config.rs @@ -2,8 +2,6 @@ use fuel_core_types::fuel_types::ContractId; #[derive(Clone, Debug, Default)] pub struct Config { - pub utxo_validation: bool, pub coinbase_recipient: Option, pub metrics: bool, - pub block_gas_limit: u64, } diff --git a/crates/services/txpool/Cargo.toml b/crates/services/txpool/Cargo.toml index 8fa684e9a1..465b333d80 100644 --- a/crates/services/txpool/Cargo.toml +++ b/crates/services/txpool/Cargo.toml @@ -13,12 +13,12 @@ description = "Transaction pool" [dependencies] anyhow = { workspace = true } async-trait = { workspace = true } -fuel-core-chain-config = { workspace = true } fuel-core-metrics = { workspace = true } fuel-core-services = { workspace = true } fuel-core-storage = { workspace = true } fuel-core-types = { workspace = true } futures = { workspace = true } +mockall = { workspace = true, optional = true } parking_lot = { workspace = true } tokio = { workspace = true, default-features = false, features = ["sync"] } tokio-rayon = { workspace = true } @@ -30,7 +30,6 @@ fuel-core-trace = { path = "./../../trace" } fuel-core-txpool = { path = "", features = ["test-helpers"] } fuel-core-types = { path = "../../types", features = ["test-helpers"] } itertools = { workspace = true } -mockall = { workspace = true } proptest = { workspace = true } rstest = "0.15" test-strategy = { workspace = true } @@ -38,7 +37,7 @@ tokio = { workspace = true, features = ["sync", "test-util"] } [features] test-helpers = [ + "dep:mockall", "fuel-core-types/test-helpers", "fuel-core-storage/test-helpers", - "fuel-core-chain-config/test-helpers", ] diff --git a/crates/services/txpool/src/config.rs b/crates/services/txpool/src/config.rs index 6f92be657d..c74cde4aca 100644 --- a/crates/services/txpool/src/config.rs +++ b/crates/services/txpool/src/config.rs @@ -1,5 +1,4 @@ use crate::types::ContractId; -use fuel_core_chain_config::ChainConfig; use fuel_core_types::{ fuel_tx::{ Address, @@ -64,8 +63,6 @@ pub struct Config { pub max_depth: usize, /// Flag to disable utxo existence and signature checks pub utxo_validation: bool, - /// chain config - pub chain_config: ChainConfig, /// Enables prometheus metrics for this fuel-service pub metrics: bool, /// Transaction TTL @@ -89,7 +86,6 @@ impl Default for Config { Self::new( max_tx, max_depth, - ChainConfig::default(), utxo_validation, metrics, transaction_ttl, @@ -104,7 +100,6 @@ impl Config { pub fn new( max_tx: usize, max_depth: usize, - chain_config: ChainConfig, utxo_validation: bool, metrics: bool, transaction_ttl: Duration, @@ -117,7 +112,6 @@ impl Config { max_tx, max_depth, utxo_validation, - chain_config, metrics, transaction_ttl, number_of_active_subscription, diff --git a/crates/services/txpool/src/ports.rs b/crates/services/txpool/src/ports.rs index bcc9bbec35..c24e4c9eb7 100644 --- a/crates/services/txpool/src/ports.rs +++ b/crates/services/txpool/src/ports.rs @@ -1,3 +1,4 @@ +use crate::types::GasPrice; use fuel_core_services::stream::BoxStream; use fuel_core_storage::Result as StorageResult; use fuel_core_types::{ @@ -6,10 +7,12 @@ use fuel_core_types::{ relayer::message::Message, }, fuel_tx::{ + ConsensusParameters, Transaction, UtxoId, }, fuel_types::{ + BlockHeight, ContractId, Nonce, }, @@ -22,7 +25,10 @@ use fuel_core_types::{ }, }, }; -use std::sync::Arc; +use std::{ + ops::Deref, + sync::Arc, +}; pub trait PeerToPeer: Send + Sync { type GossipedTransaction: NetworkData; @@ -55,3 +61,22 @@ pub trait TxPoolDb: Send + Sync { fn is_message_spent(&self, message_id: &Nonce) -> StorageResult; } + +/// Trait for getting gas price for the Tx Pool code to look up the gas price for a given block height +pub trait GasPriceProvider { + /// Get gas price for specific block height if it is known + fn gas_price(&self, block_height: BlockHeight) -> Option; +} + +/// Trait for getting the latest consensus parameters. +#[cfg_attr(feature = "test-helpers", mockall::automock)] +pub trait ConsensusParametersProvider { + /// Get latest consensus parameters. + fn latest_consensus_parameters(&self) -> Arc; +} + +impl GasPriceProvider for Arc { + fn gas_price(&self, block_height: BlockHeight) -> Option { + self.deref().gas_price(block_height) + } +} diff --git a/crates/services/txpool/src/service.rs b/crates/services/txpool/src/service.rs index cd5053bc76..b30649b27e 100644 --- a/crates/services/txpool/src/service.rs +++ b/crates/services/txpool/src/service.rs @@ -1,6 +1,8 @@ use crate::{ ports::{ BlockImporter, + ConsensusParametersProvider, + GasPriceProvider as GasPriceProviderConstraint, PeerToPeer, TxPoolDb, }, @@ -8,14 +10,13 @@ use crate::{ txpool::{ check_single_tx, check_transactions, - GasPriceProvider as GasPriceProviderConstraint, }, Config, Error as TxPoolError, TxInfo, TxPool, }; - +use anyhow::anyhow; use fuel_core_services::{ stream::BoxStream, RunnableService, @@ -23,9 +24,9 @@ use fuel_core_services::{ ServiceRunner, StateWatcher, }; +use fuel_core_storage::transactional::AtomicView; use fuel_core_types::{ fuel_tx::{ - ConsensusParameters, Transaction, TxId, UniqueIdentifier, @@ -33,8 +34,10 @@ use fuel_core_types::{ fuel_types::{ BlockHeight, Bytes32, + ChainId, }, services::{ + block_importer::SharedImportResult, p2p::{ GossipData, GossipsubMessageAcceptance, @@ -50,10 +53,6 @@ use fuel_core_types::{ }, tai64::Tai64, }; - -use anyhow::anyhow; -use fuel_core_storage::transactional::AtomicView; -use fuel_core_types::services::block_importer::SharedImportResult; use parking_lot::Mutex as ParkingMutex; use std::{ sync::Arc, @@ -73,7 +72,7 @@ use self::update_sender::{ mod update_sender; -pub type Service = ServiceRunner>; +pub type Service = ServiceRunner>; #[derive(Clone)] pub struct TxStatusChange { @@ -121,52 +120,56 @@ impl TxStatusChange { } } -pub struct SharedState { +pub struct SharedState { tx_status_sender: TxStatusChange, txpool: Arc>>, p2p: Arc, - consensus_params: ConsensusParameters, + chain_id: ChainId, + utxo_validation: bool, current_height: Arc>, - config: Config, + consensus_parameters_provider: Arc, gas_price_provider: Arc, } -impl Clone - for SharedState +impl Clone + for SharedState { fn clone(&self) -> Self { Self { tx_status_sender: self.tx_status_sender.clone(), txpool: self.txpool.clone(), p2p: self.p2p.clone(), - consensus_params: self.consensus_params.clone(), + chain_id: self.chain_id, + utxo_validation: self.utxo_validation, current_height: self.current_height.clone(), - config: self.config.clone(), + consensus_parameters_provider: self.consensus_parameters_provider.clone(), gas_price_provider: self.gas_price_provider.clone(), } } } -pub struct Task { +pub struct Task { gossiped_tx_stream: BoxStream, committed_block_stream: BoxStream, - tx_pool_shared_state: SharedState, + tx_pool_shared_state: + SharedState, ttl_timer: tokio::time::Interval, } #[async_trait::async_trait] -impl RunnableService - for Task +impl RunnableService + for Task where P2P: PeerToPeer, ViewProvider: AtomicView, View: TxPoolDb, - GasPriceProvider: GasPriceProviderConstraint + Send + Sync + Clone, + GasPriceProvider: GasPriceProviderConstraint + Send + Sync, + ConsensusProvider: ConsensusParametersProvider + Send + Sync, { const NAME: &'static str = "TxPool"; - type SharedData = SharedState; - type Task = Task; + type SharedData = SharedState; + type Task = Task; type TaskParams = (); fn shared_data(&self) -> Self::SharedData { @@ -184,13 +187,14 @@ where } #[async_trait::async_trait] -impl RunnableTask - for Task +impl RunnableTask + for Task where P2P: PeerToPeer, ViewProvider: AtomicView, View: TxPoolDb, GasPriceProvider: GasPriceProviderConstraint + Send + Sync, + ConsensusProvider: ConsensusParametersProvider + Send + Sync, { async fn run(&mut self, watcher: &mut StateWatcher) -> anyhow::Result { let should_continue; @@ -232,11 +236,21 @@ where new_transaction = self.gossiped_tx_stream.next() => { if let Some(GossipData { data: Some(tx), message_id, peer_id }) = new_transaction { - let id = tx.id(&self.tx_pool_shared_state.consensus_params.chain_id()); + let id = tx.id(&self.tx_pool_shared_state.chain_id); let current_height = *self.tx_pool_shared_state.current_height.lock(); + let params = self + .tx_pool_shared_state + .consensus_parameters_provider + .latest_consensus_parameters(); // verify tx - let checked_tx = check_single_tx(tx, current_height, &self.tx_pool_shared_state.config, &self.tx_pool_shared_state.gas_price_provider).await; + let checked_tx = check_single_tx( + tx, + current_height, + self.tx_pool_shared_state.utxo_validation, + params.as_ref(), + &self.tx_pool_shared_state.gas_price_provider + ).await; let acceptance = match checked_tx { Ok(tx) => { @@ -298,8 +312,8 @@ where // Instead, `fuel-core` can create a `DatabaseWithTxPool` that aggregates `TxPool` and // storage `Database` together. GraphQL will retrieve data from this `DatabaseWithTxPool` via // `StorageInspect` trait. -impl - SharedState +impl + SharedState { pub fn pending_number(&self) -> usize { self.txpool.lock().pending_number() @@ -365,13 +379,14 @@ impl } } -impl - SharedState +impl + SharedState where P2P: PeerToPeer, ViewProvider: AtomicView, View: TxPoolDb, GasPriceProvider: GasPriceProviderConstraint, + ConsensusProvider: ConsensusParametersProvider, { #[tracing::instrument(name = "insert_submitted_txn", skip_all)] pub async fn insert( @@ -380,11 +395,15 @@ where ) -> Vec> { // verify txs let current_height = *self.current_height.lock(); + let params = self + .consensus_parameters_provider + .latest_consensus_parameters(); let checked_txs = check_transactions( &txs, current_height, - &self.config, + self.utxo_validation, + params.as_ref(), &self.gas_price_provider, ) .await; @@ -463,27 +482,31 @@ pub enum TxStatusMessage { FailedStatus, } -pub fn new_service( +pub fn new_service( config: Config, provider: ViewProvider, importer: Importer, p2p: P2P, current_height: BlockHeight, gas_price_provider: GasPriceProvider, -) -> Service + consensus_parameters_provider: ConsensusProvider, +) -> Service where Importer: BlockImporter, P2P: PeerToPeer + 'static, ViewProvider: AtomicView, ViewProvider::View: TxPoolDb, - GasPriceProvider: GasPriceProviderConstraint + Send + Sync + Clone, + GasPriceProvider: GasPriceProviderConstraint + Send + Sync, + ConsensusProvider: ConsensusParametersProvider + Send + Sync, { let p2p = Arc::new(p2p); let gossiped_tx_stream = p2p.gossiped_transaction_events(); let committed_block_stream = importer.block_events(); let mut ttl_timer = tokio::time::interval(config.transaction_ttl); ttl_timer.set_missed_tick_behavior(MissedTickBehavior::Skip); - let consensus_params = config.chain_config.consensus_parameters.clone(); + let chain_id = consensus_parameters_provider + .latest_consensus_parameters() + .chain_id(); let number_of_active_subscription = config.number_of_active_subscription; let txpool = Arc::new(ParkingMutex::new(TxPool::new(config.clone(), provider))); let task = Task { @@ -500,9 +523,10 @@ where ), txpool, p2p, - consensus_params, + chain_id, + utxo_validation: config.utxo_validation, current_height: Arc::new(ParkingMutex::new(current_height)), - config, + consensus_parameters_provider: Arc::new(consensus_parameters_provider), gas_price_provider: Arc::new(gas_price_provider), }, ttl_timer, diff --git a/crates/services/txpool/src/service/test_helpers.rs b/crates/services/txpool/src/service/test_helpers.rs index 63e2459ba1..6ba7653767 100644 --- a/crates/services/txpool/src/service/test_helpers.rs +++ b/crates/services/txpool/src/service/test_helpers.rs @@ -1,7 +1,10 @@ use super::*; use crate::{ mock_db::MockDBProvider, - ports::BlockImporter, + ports::{ + BlockImporter, + MockConsensusParametersProvider, + }, MockDb, }; use fuel_core_services::{ @@ -33,7 +36,12 @@ use std::cell::RefCell; type GossipedTransaction = GossipData; pub struct TestContext { - pub(crate) service: Service, + pub(crate) service: Service< + MockP2P, + MockDBProvider, + MockTxPoolGasPrice, + MockConsensusParametersProvider, + >, mock_db: MockDb, rng: RefCell, } @@ -66,7 +74,14 @@ impl TestContext { TestContextBuilder::new().build_and_start().await } - pub fn service(&self) -> &Service { + pub fn service( + &self, + ) -> &Service< + MockP2P, + MockDBProvider, + MockTxPoolGasPrice, + MockConsensusParametersProvider, + > { &self.service } @@ -228,6 +243,11 @@ impl TestContextBuilder { .importer .unwrap_or_else(|| MockImporter::with_blocks(vec![])); let gas_price_provider = MockTxPoolGasPrice::new(gas_price); + let mut consensus_parameters_provider = + MockConsensusParametersProvider::default(); + consensus_parameters_provider + .expect_latest_consensus_parameters() + .returning(|| Arc::new(Default::default())); let service = new_service( config, @@ -236,6 +256,7 @@ impl TestContextBuilder { p2p, Default::default(), gas_price_provider, + consensus_parameters_provider, ); TestContext { diff --git a/crates/services/txpool/src/txpool.rs b/crates/services/txpool/src/txpool.rs index 8dfe422405..33111774fd 100644 --- a/crates/services/txpool/src/txpool.rs +++ b/crates/services/txpool/src/txpool.rs @@ -32,6 +32,7 @@ use fuel_core_types::{ tai64::Tai64, }; +use crate::ports::GasPriceProvider; use fuel_core_metrics::txpool_metrics::txpool_metrics; use fuel_core_storage::transactional::AtomicView; use fuel_core_types::{ @@ -48,6 +49,7 @@ use fuel_core_types::{ MessageDataSigned, }, }, + ConsensusParameters, Input, }, fuel_vm::checked_transaction::CheckPredicateParams, @@ -76,18 +78,6 @@ pub struct TxPool { database: ViewProvider, } -/// Trait for getting gas price for the Tx Pool code to look up the gas price for a given block height -pub trait GasPriceProvider { - /// Get gas price for specific block height if it is known - fn gas_price(&self, block_height: BlockHeight) -> Option; -} - -impl GasPriceProvider for Arc { - fn gas_price(&self, block_height: BlockHeight) -> Option { - self.deref().gas_price(block_height) - } -} - impl TxPool { pub fn new(config: Config, database: ViewProvider) -> Self { let max_depth = config.max_depth; @@ -371,19 +361,6 @@ where return Err(Error::NoMetadata) } - // verify max gas is less than block limit - let block_gas_limit = self - .config - .chain_config - .consensus_parameters - .block_gas_limit(); - if tx.max_gas() > block_gas_limit { - return Err(Error::NotInsertedMaxGasLimit { - tx_gas: tx.max_gas(), - block_limit: block_gas_limit, - }) - } - if self.by_hash.contains_key(&tx.id()) { return Err(Error::NotInsertedTxKnown) } @@ -483,7 +460,8 @@ where pub async fn check_transactions( txs: &[Arc], current_height: BlockHeight, - config: &Config, + utxp_validation: bool, + consensus_params: &ConsensusParameters, gas_price_provider: &Provider, ) -> Vec, Error>> where @@ -496,7 +474,8 @@ where check_single_tx( tx.deref().clone(), current_height, - config, + utxp_validation, + consensus_params, gas_price_provider, ) .await, @@ -509,16 +488,15 @@ where pub async fn check_single_tx( tx: Transaction, current_height: BlockHeight, - config: &Config, + utxo_validation: bool, + consensus_params: &ConsensusParameters, gas_price_provider: &GasPrice, ) -> Result, Error> { if tx.is_mint() { return Err(Error::NotSupportedTransactionType) } - let tx: Checked = if config.utxo_validation { - let consensus_params = &config.chain_config.consensus_parameters; - + let tx: Checked = if utxo_validation { let tx = tx .into_checked_basic(current_height, consensus_params)? .check_signatures(&consensus_params.chain_id())?; @@ -533,26 +511,26 @@ pub async fn check_single_tx( tx } else { - tx.into_checked_basic(current_height, &config.chain_config.consensus_parameters)? + tx.into_checked_basic(current_height, consensus_params)? }; let gas_price = gas_price_provider .gas_price(current_height) .ok_or(Error::GasPriceNotFound(current_height))?; - let tx = verify_tx_min_gas_price(tx, config, gas_price)?; + let tx = verify_tx_min_gas_price(tx, consensus_params, gas_price)?; Ok(tx) } fn verify_tx_min_gas_price( tx: Checked, - config: &Config, + consensus_params: &ConsensusParameters, gas_price: GasPrice, ) -> Result, Error> { let tx: CheckedTransaction = tx.into(); - let gas_costs = config.chain_config.consensus_parameters.gas_costs(); - let fee_parameters = config.chain_config.consensus_parameters.fee_params(); + let gas_costs = consensus_params.gas_costs(); + let fee_parameters = consensus_params.fee_params(); let read = match tx { CheckedTransaction::Script(script) => { let ready = script.into_ready(gas_price, gas_costs, fee_parameters)?; diff --git a/crates/services/txpool/src/txpool/tests.rs b/crates/services/txpool/src/txpool/tests.rs index 2ea3640129..d3d23c64cb 100644 --- a/crates/services/txpool/src/txpool/tests.rs +++ b/crates/services/txpool/src/txpool/tests.rs @@ -11,6 +11,7 @@ use crate::{ create_contract_output, create_message_predicate_from_message, }, + types::GasPrice, Config, Error, }; @@ -24,11 +25,15 @@ use fuel_core_types::{ input::coin::CoinPredicate, Address, AssetId, + ConsensusParameters, Contract, + Finalizable, Input, Output, + PredicateParameters, Transaction, TransactionBuilder, + TxParameters, UniqueIdentifier, UtxoId, }, @@ -38,15 +43,6 @@ use fuel_core_types::{ Checked, }, }; - -use crate::types::GasPrice; -use fuel_core_chain_config::ChainConfig; -use fuel_core_types::fuel_tx::{ - ConsensusParameters, - Finalizable, - PredicateParameters, - TxParameters, -}; use std::{ cmp::Reverse, collections::HashMap, @@ -68,9 +64,15 @@ async fn check_unwrap_tx_with_gas_price( gas_price: GasPrice, ) -> Checked { let gas_price_provider = MockTxPoolGasPrice::new(gas_price); - check_single_tx(tx, Default::default(), config, &gas_price_provider) - .await - .expect("Transaction should be checked") + check_single_tx( + tx, + Default::default(), + config.utxo_validation, + &ConsensusParameters::default(), + &gas_price_provider, + ) + .await + .expect("Transaction should be checked") } async fn check_tx( @@ -87,7 +89,14 @@ async fn check_tx_with_gas_price( gas_price: GasPrice, ) -> Result, Error> { let gas_price_provider = MockTxPoolGasPrice::new(gas_price); - check_single_tx(tx, Default::default(), config, &gas_price_provider).await + check_single_tx( + tx, + Default::default(), + config.utxo_validation, + &ConsensusParameters::default(), + &gas_price_provider, + ) + .await } #[tokio::test] @@ -1195,13 +1204,6 @@ async fn predicate_without_enough_gas_returns_out_of_gas() { consensus_parameters.set_predicate_params( PredicateParameters::default().with_max_gas_per_predicate(gas_limit), ); - let config = Config { - chain_config: ChainConfig { - consensus_parameters, - ..Default::default() - }, - ..Default::default() - }; let coin = context .custom_predicate( @@ -1211,7 +1213,7 @@ async fn predicate_without_enough_gas_returns_out_of_gas() { vec![op::jmp(RegId::ZERO)].into_iter().collect(), None, ) - .into_estimated(&config.chain_config.consensus_parameters); + .into_estimated(&consensus_parameters); let tx = TransactionBuilder::script(vec![], vec![]) .script_gas_limit(GAS_LIMIT) diff --git a/crates/types/src/services/txpool.rs b/crates/types/src/services/txpool.rs index 573a44967d..069b7e0a72 100644 --- a/crates/types/src/services/txpool.rs +++ b/crates/types/src/services/txpool.rs @@ -301,8 +301,6 @@ pub enum Error { NotInsertedIoContractOutput, #[error("Transaction is not inserted. Maximum depth of dependent transaction chain reached")] NotInsertedMaxDepth, - #[error("Transaction exceeds the max gas per block limit. Tx gas: {tx_gas}, block limit {block_limit}")] - NotInsertedMaxGasLimit { tx_gas: Word, block_limit: Word }, // small todo for now it can pass but in future we should include better messages #[error("Transaction removed.")] Removed, diff --git a/tests/test-helpers/src/builder.rs b/tests/test-helpers/src/builder.rs index f955a1c8f2..f87611f284 100644 --- a/tests/test-helpers/src/builder.rs +++ b/tests/test-helpers/src/builder.rs @@ -198,10 +198,7 @@ impl TestSetupBuilder { let config = Config { utxo_validation: self.utxo_validation, - txpool: fuel_core_txpool::Config { - chain_config: chain_conf.clone(), - ..fuel_core_txpool::Config::default() - }, + txpool: fuel_core_txpool::Config::default(), snapshot_reader: SnapshotReader::new_in_memory(chain_conf, state), block_production: self.trigger, static_gas_price: self.min_gas_price, From d8ee45940d02647af6828209660c81038491edd9 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Sat, 6 Apr 2024 15:51:19 +0200 Subject: [PATCH 02/14] Self review Updated CHANGELOG.md --- CHANGELOG.md | 3 +++ .../src/service/adapters/consensus_module.rs | 18 ++++++++---------- .../fuel-core/src/service/adapters/producer.rs | 5 ++++- crates/fuel-core/src/service/sub_services.rs | 3 ++- crates/services/producer/src/block_producer.rs | 13 ++++++++----- .../producer/src/block_producer/gas_price.rs | 12 ++++++++---- .../producer/src/block_producer/tests.rs | 4 ++-- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5ae08afee..35d9d82ac7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Description of the upcoming release here. +### Changed +- [#1808](https://github.com/FuelLabs/fuel-core/pull/1808): Fetch consensus parameters from the database. + ## [Version 0.24.2] ### Changed diff --git a/crates/fuel-core/src/service/adapters/consensus_module.rs b/crates/fuel-core/src/service/adapters/consensus_module.rs index 5901841857..6a810c2cb0 100644 --- a/crates/fuel-core/src/service/adapters/consensus_module.rs +++ b/crates/fuel-core/src/service/adapters/consensus_module.rs @@ -1,13 +1,11 @@ use crate::{ database::Database, - service::{ - adapters::{ - MaybeRelayerAdapter, - VerifierAdapter, - }, - Config, + service::adapters::{ + MaybeRelayerAdapter, + VerifierAdapter, }, }; +use fuel_core_chain_config::SnapshotReader; use fuel_core_consensus_module::block_verifier::{ config::Config as VerifierConfig, Verifier, @@ -32,10 +30,10 @@ use std::sync::Arc; pub mod poa; impl VerifierAdapter { - pub fn new(config: &Config, database: Database) -> Self { - let block_height = config.snapshot_reader.block_height(); - let da_block_height = config.snapshot_reader.da_block_height(); - let consensus = config.snapshot_reader.chain_config().consensus; + pub fn new(snapshot_reader: &SnapshotReader, database: Database) -> Self { + let block_height = snapshot_reader.block_height(); + let da_block_height = snapshot_reader.da_block_height(); + let consensus = snapshot_reader.chain_config().consensus; let config = VerifierConfig::new(consensus, block_height, da_block_height); Self { block_verifier: Arc::new(Verifier::new(config, database)), diff --git a/crates/fuel-core/src/service/adapters/producer.rs b/crates/fuel-core/src/service/adapters/producer.rs index 34eb502fab..66393abb96 100644 --- a/crates/fuel-core/src/service/adapters/producer.rs +++ b/crates/fuel-core/src/service/adapters/producer.rs @@ -233,7 +233,10 @@ impl GasPriceProvider for StaticGasPrice { } impl ConsensusParametersProviderTrait for ConsensusParametersProvider { - fn latest_consensus_params(&self) -> Arc { + fn consensus_params_at_version( + &self, + _: &ConsensusParametersVersion, + ) -> Arc { self.consensus_parameters.clone() } } diff --git a/crates/fuel-core/src/service/sub_services.rs b/crates/fuel-core/src/service/sub_services.rs index 58e0bf813c..6069dd0c8b 100644 --- a/crates/fuel-core/src/service/sub_services.rs +++ b/crates/fuel-core/src/service/sub_services.rs @@ -78,7 +78,8 @@ pub fn init_sub_services( }, ); - let verifier = VerifierAdapter::new(config, database.on_chain().clone()); + let verifier = + VerifierAdapter::new(&config.snapshot_reader, database.on_chain().clone()); let importer_adapter = BlockImporterAdapter::new( chain_config.consensus_parameters.chain_id(), diff --git a/crates/services/producer/src/block_producer.rs b/crates/services/producer/src/block_producer.rs index d60b3a939a..3b97ea9802 100644 --- a/crates/services/producer/src/block_producer.rs +++ b/crates/services/producer/src/block_producer.rs @@ -277,7 +277,13 @@ where ) -> anyhow::Result { let mut block_header = self._new_header(height, block_time)?; let previous_da_height = block_header.da_height; - let new_da_height = self.select_new_da_height(previous_da_height).await?; + let gas_limit = self + .consensus_parameters_provider + .consensus_params_at_version(&block_header.consensus_parameters_version) + .block_gas_limit(); + let new_da_height = self + .select_new_da_height(gas_limit, previous_da_height) + .await?; block_header.application.da_height = new_da_height; @@ -286,12 +292,9 @@ where async fn select_new_da_height( &self, + gas_limit: u64, previous_da_height: DaBlockHeight, ) -> anyhow::Result { - let gas_limit = self - .consensus_parameters_provider - .latest_consensus_params() - .block_gas_limit(); let mut new_best = previous_da_height; let mut total_cost: u64 = 0; let highest = self diff --git a/crates/services/producer/src/block_producer/gas_price.rs b/crates/services/producer/src/block_producer/gas_price.rs index 18e47ea613..2643f7db93 100644 --- a/crates/services/producer/src/block_producer/gas_price.rs +++ b/crates/services/producer/src/block_producer/gas_price.rs @@ -1,4 +1,7 @@ -use fuel_core_types::fuel_types::BlockHeight; +use fuel_core_types::{ + blockchain::header::ConsensusParametersVersion, + fuel_types::BlockHeight, +}; use std::sync::Arc; /// The parameters required to retrieve the gas price for a block @@ -29,11 +32,12 @@ pub trait GasPriceProvider { fn gas_price(&self, params: GasPriceParams) -> Option; } -/// Interface for retrieving the latest consensus parameters. +/// Interface for retrieving the consensus parameters. #[cfg_attr(feature = "test-helpers", mockall::automock)] pub trait ConsensusParametersProvider { - /// Retrieve the latest consensus parameters. - fn latest_consensus_params( + /// Retrieve the consensus parameters for the `version`. + fn consensus_params_at_version( &self, + version: &ConsensusParametersVersion, ) -> Arc; } diff --git a/crates/services/producer/src/block_producer/tests.rs b/crates/services/producer/src/block_producer/tests.rs index 849b3394f6..3c565c7a43 100644 --- a/crates/services/producer/src/block_producer/tests.rs +++ b/crates/services/producer/src/block_producer/tests.rs @@ -604,8 +604,8 @@ impl TestContext { let mut consensus_parameters_provider = MockConsensusParametersProvider::default(); consensus_parameters_provider - .expect_latest_consensus_params() - .returning(move || consensus_params.clone()); + .expect_consensus_params_at_version() + .returning(move |_| consensus_params.clone()); Producer { config: self.config, From 14ca7c88eeb3148c8bb81b66f001100e60569198 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Sat, 6 Apr 2024 18:20:12 +0200 Subject: [PATCH 03/14] Fetch `ConsensusParameters` from the database --- crates/fuel-core/src/service.rs | 2 +- crates/fuel-core/src/service/adapters.rs | 10 +- .../adapters/consensus_parameters_provider.rs | 179 ++++++++++++++++++ .../src/service/adapters/graphql_api.rs | 2 +- .../src/service/adapters/producer.rs | 6 +- .../fuel-core/src/service/adapters/txpool.rs | 2 +- crates/fuel-core/src/service/sub_services.rs | 23 ++- .../services/producer/src/block_producer.rs | 2 +- .../producer/src/block_producer/gas_price.rs | 2 +- .../producer/src/block_producer/tests.rs | 2 +- crates/services/src/service.rs | 2 +- crates/services/txpool/src/service.rs | 9 +- 12 files changed, 211 insertions(+), 30 deletions(-) create mode 100644 crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs diff --git a/crates/fuel-core/src/service.rs b/crates/fuel-core/src/service.rs index de5d67f508..de280a6dbf 100644 --- a/crates/fuel-core/src/service.rs +++ b/crates/fuel-core/src/service.rs @@ -319,7 +319,7 @@ mod tests { // current services: graphql, graphql worker, txpool, PoA #[allow(unused_mut)] - let mut expected_services = 4; + let mut expected_services = 5; // Relayer service is disabled with `Config::local_node`. // #[cfg(feature = "relayer")] diff --git a/crates/fuel-core/src/service/adapters.rs b/crates/fuel-core/src/service/adapters.rs index 6e06444204..bfe9db100f 100644 --- a/crates/fuel-core/src/service/adapters.rs +++ b/crates/fuel-core/src/service/adapters.rs @@ -16,7 +16,6 @@ use fuel_core_services::stream::BoxStream; #[cfg(feature = "p2p")] use fuel_core_types::services::p2p::peer_reputation::AppScore; use fuel_core_types::{ - fuel_tx::ConsensusParameters, fuel_types::BlockHeight, services::block_importer::SharedImportResult, }; @@ -25,6 +24,7 @@ use std::sync::Arc; pub mod block_importer; pub mod consensus_module; +pub mod consensus_parameters_provider; pub mod executor; pub mod graphql_api; #[cfg(feature = "p2p")] @@ -38,14 +38,12 @@ pub mod txpool; #[derive(Debug, Clone)] pub struct ConsensusParametersProvider { - consensus_parameters: Arc, + shared_state: consensus_parameters_provider::SharedState, } impl ConsensusParametersProvider { - pub fn new(consensus_parameters: ConsensusParameters) -> Self { - Self { - consensus_parameters: Arc::new(consensus_parameters), - } + pub fn new(shared_state: consensus_parameters_provider::SharedState) -> Self { + Self { shared_state } } } diff --git a/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs b/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs new file mode 100644 index 0000000000..af30c766b7 --- /dev/null +++ b/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs @@ -0,0 +1,179 @@ +use crate::{ + database::Database, + service::adapters::BlockImporterAdapter, +}; +use fuel_core_producer::ports::BlockProducerDatabase; +use fuel_core_services::{ + stream::BoxStream, + RunnableService, + RunnableTask, + ServiceRunner, + SharedMutex, + StateWatcher, +}; +use fuel_core_storage::{ + not_found, + tables::ConsensusParametersVersions, + Result as StorageResult, + StorageAsRef, +}; +use fuel_core_txpool::ports::BlockImporter; +use fuel_core_types::{ + blockchain::header::ConsensusParametersVersion, + fuel_tx::ConsensusParameters, + services::block_importer::SharedImportResult, +}; +use futures::StreamExt; +use std::{ + collections::HashMap, + sync::Arc, +}; + +#[derive(Clone, Debug)] +pub struct SharedState { + latest_consensus_parameters_version: Arc>, + consensus_parameters: + Arc>>>, + database: Database, +} + +pub struct Task { + blocks_events: BoxStream, + shared_state: SharedState, +} + +impl SharedState { + fn new(database: Database) -> StorageResult { + let genesis_version = 0; + let state = Self { + latest_consensus_parameters_version: Arc::new(SharedMutex::new( + genesis_version, + )), + consensus_parameters: Default::default(), + database, + }; + + Ok(state) + } + + fn cache_consensus_parameters( + &self, + version: ConsensusParametersVersion, + ) -> StorageResult> { + let consensus_parameters = self + .database + .storage::() + .get(&version)? + .ok_or(not_found!(ConsensusParametersVersions))? + .into_owned(); + + let consensus_parameters = Arc::new(consensus_parameters); + self.consensus_parameters + .lock() + .insert(version, consensus_parameters.clone()); + Ok(consensus_parameters) + } + + pub fn get_consensus_parameters( + &self, + version: &ConsensusParametersVersion, + ) -> StorageResult> { + { + let consensus_parameters = self.consensus_parameters.lock(); + if let Some(parameters) = consensus_parameters.get(version) { + return Ok(parameters.clone()); + } + } + + self.cache_consensus_parameters(*version) + } + + pub fn latest_consensus_parameters(&self) -> Arc { + let version = *self.latest_consensus_parameters_version.lock(); + self.get_consensus_parameters(&version) + .expect("The latest consensus parameters always are available unless this function was called before regenesis.") + } +} + +#[async_trait::async_trait] +impl RunnableTask for Task { + async fn run(&mut self, watcher: &mut StateWatcher) -> anyhow::Result { + let should_continue; + tokio::select! { + + _ = watcher.while_started() => { + should_continue = false; + } + + Some(event) = self.blocks_events.next() => { + let new_version = event + .sealed_block + .entity + .header() + .application() + .consensus_parameters_version; + + if new_version > *self.shared_state.latest_consensus_parameters_version.lock() { + match self.shared_state.cache_consensus_parameters(new_version) { + Ok(_) => { + *self.shared_state.latest_consensus_parameters_version.lock() = new_version; + } + Err(err) => { + tracing::error!("Failed to cache consensus parameters: {:?}", err); + should_continue = false; + return Ok(should_continue) + } + } + } + should_continue = true; + } + } + + Ok(should_continue) + } + + async fn shutdown(self) -> anyhow::Result<()> { + // We don't have any resources to clean up. + Ok(()) + } +} + +#[async_trait::async_trait] +impl RunnableService for Task { + const NAME: &'static str = "ConsensusParametersProviderTask"; + type SharedData = SharedState; + type Task = Self; + type TaskParams = (); + + fn shared_data(&self) -> Self::SharedData { + self.shared_state.clone() + } + + async fn into_task( + self, + _: &StateWatcher, + _: Self::TaskParams, + ) -> anyhow::Result { + let latest_consensus_parameters_version = self + .shared_state + .database + .latest_consensus_parameters_version()?; + self.shared_state + .cache_consensus_parameters(latest_consensus_parameters_version)?; + *self.shared_state.latest_consensus_parameters_version.lock() = + latest_consensus_parameters_version; + + Ok(self) + } +} + +pub fn new_service( + database: Database, + importer: &BlockImporterAdapter, +) -> StorageResult> { + let blocks_events = importer.block_events(); + Ok(ServiceRunner::new(Task { + blocks_events, + shared_state: SharedState::new(database)?, + })) +} diff --git a/crates/fuel-core/src/service/adapters/graphql_api.rs b/crates/fuel-core/src/service/adapters/graphql_api.rs index 5c02c16e18..871daa9b66 100644 --- a/crates/fuel-core/src/service/adapters/graphql_api.rs +++ b/crates/fuel-core/src/service/adapters/graphql_api.rs @@ -176,6 +176,6 @@ impl GasPriceEstimate for StaticGasPrice { impl ConsensusProvider for ConsensusParametersProvider { fn latest_consensus_params(&self) -> Arc { - self.consensus_parameters.clone() + self.shared_state.latest_consensus_parameters() } } diff --git a/crates/fuel-core/src/service/adapters/producer.rs b/crates/fuel-core/src/service/adapters/producer.rs index 66393abb96..add8752869 100644 --- a/crates/fuel-core/src/service/adapters/producer.rs +++ b/crates/fuel-core/src/service/adapters/producer.rs @@ -235,8 +235,8 @@ impl GasPriceProvider for StaticGasPrice { impl ConsensusParametersProviderTrait for ConsensusParametersProvider { fn consensus_params_at_version( &self, - _: &ConsensusParametersVersion, - ) -> Arc { - self.consensus_parameters.clone() + version: &ConsensusParametersVersion, + ) -> anyhow::Result> { + Ok(self.shared_state.get_consensus_parameters(version)?) } } diff --git a/crates/fuel-core/src/service/adapters/txpool.rs b/crates/fuel-core/src/service/adapters/txpool.rs index 129cecbcb7..ee241fafbf 100644 --- a/crates/fuel-core/src/service/adapters/txpool.rs +++ b/crates/fuel-core/src/service/adapters/txpool.rs @@ -149,6 +149,6 @@ impl GasPriceProvider for StaticGasPrice { impl ConsensusParametersProviderTrait for ConsensusParametersProvider { fn latest_consensus_parameters(&self) -> Arc { - self.consensus_parameters.clone() + self.shared_state.latest_consensus_parameters() } } diff --git a/crates/fuel-core/src/service/sub_services.rs b/crates/fuel-core/src/service/sub_services.rs index 6069dd0c8b..6f4627e085 100644 --- a/crates/fuel-core/src/service/sub_services.rs +++ b/crates/fuel-core/src/service/sub_services.rs @@ -32,6 +32,7 @@ use tokio::sync::Mutex; #[cfg(feature = "relayer")] use crate::relayer::Config as RelayerConfig; +use crate::service::adapters::consensus_parameters_provider; #[cfg(feature = "relayer")] use fuel_core_types::blockchain::primitives::DaBlockHeight; @@ -68,6 +69,8 @@ pub fn init_sub_services( }); let last_height = *last_block_header.height(); let chain_config = config.snapshot_reader.chain_config(); + let chain_id = chain_config.consensus_parameters.chain_id(); + let chain_name = chain_config.chain_name.clone(); let executor = ExecutorAdapter::new( database.on_chain().clone(), @@ -82,13 +85,22 @@ pub fn init_sub_services( VerifierAdapter::new(&config.snapshot_reader, database.on_chain().clone()); let importer_adapter = BlockImporterAdapter::new( - chain_config.consensus_parameters.chain_id(), + chain_id, config.block_importer.clone(), database.on_chain().clone(), executor.clone(), verifier.clone(), ); + let consensus_parameters_provider_service = + consensus_parameters_provider::new_service( + database.on_chain().clone(), + &importer_adapter, + )?; + let consensus_parameters_provider = ConsensusParametersProvider::new( + consensus_parameters_provider_service.shared.clone(), + ); + #[cfg(feature = "relayer")] let relayer_service = if let Some(config) = &config.relayer { Some(fuel_core_relayer::new_service( @@ -112,7 +124,7 @@ pub fn init_sub_services( #[cfg(feature = "p2p")] let mut network = config.p2p.clone().map(|p2p_config| { fuel_core_p2p::service::new_service( - chain_config.consensus_parameters.chain_id(), + chain_id, p2p_config, database.on_chain().clone(), importer_adapter.clone(), @@ -142,8 +154,6 @@ pub fn init_sub_services( let p2p_adapter = P2PAdapter::new(); let gas_price_provider = StaticGasPrice::new(config.static_gas_price); - let consensus_parameters_provider = - ConsensusParametersProvider::new(chain_config.consensus_parameters.clone()); let txpool = fuel_core_txpool::new_service( config.txpool.clone(), database.on_chain().clone(), @@ -207,7 +217,7 @@ pub fn init_sub_services( tx_pool_adapter.clone(), importer_adapter.clone(), database.off_chain().clone(), - chain_config.consensus_parameters.chain_id(), + chain_id, ); let graphql_config = GraphQLConfig { @@ -217,7 +227,7 @@ pub fn init_sub_services( vm_backtrace: config.vm.backtrace, max_tx: config.txpool.max_tx, max_depth: config.txpool.max_depth, - chain_name: chain_config.chain_name.clone(), + chain_name, }; let graph_ql = fuel_core_graphql_api::api_service::new_service( @@ -254,6 +264,7 @@ pub fn init_sub_services( // GraphQL should be shutdown first, so let's start it first. Box::new(graph_ql), Box::new(txpool), + Box::new(consensus_parameters_provider_service), ]; if let Some(poa) = poa { diff --git a/crates/services/producer/src/block_producer.rs b/crates/services/producer/src/block_producer.rs index 3b97ea9802..f438dd157c 100644 --- a/crates/services/producer/src/block_producer.rs +++ b/crates/services/producer/src/block_producer.rs @@ -279,7 +279,7 @@ where let previous_da_height = block_header.da_height; let gas_limit = self .consensus_parameters_provider - .consensus_params_at_version(&block_header.consensus_parameters_version) + .consensus_params_at_version(&block_header.consensus_parameters_version)? .block_gas_limit(); let new_da_height = self .select_new_da_height(gas_limit, previous_da_height) diff --git a/crates/services/producer/src/block_producer/gas_price.rs b/crates/services/producer/src/block_producer/gas_price.rs index 2643f7db93..59245999f9 100644 --- a/crates/services/producer/src/block_producer/gas_price.rs +++ b/crates/services/producer/src/block_producer/gas_price.rs @@ -39,5 +39,5 @@ pub trait ConsensusParametersProvider { fn consensus_params_at_version( &self, version: &ConsensusParametersVersion, - ) -> Arc; + ) -> anyhow::Result>; } diff --git a/crates/services/producer/src/block_producer/tests.rs b/crates/services/producer/src/block_producer/tests.rs index 3c565c7a43..1434865855 100644 --- a/crates/services/producer/src/block_producer/tests.rs +++ b/crates/services/producer/src/block_producer/tests.rs @@ -605,7 +605,7 @@ impl TestContext { MockConsensusParametersProvider::default(); consensus_parameters_provider .expect_consensus_params_at_version() - .returning(move |_| consensus_params.clone()); + .returning(move |_| Ok(consensus_params.clone())); Producer { config: self.config, diff --git a/crates/services/src/service.rs b/crates/services/src/service.rs index 8374c5e448..d2ba048cad 100644 --- a/crates/services/src/service.rs +++ b/crates/services/src/service.rs @@ -20,7 +20,7 @@ use tracing::Instrument; pub type Shared = std::sync::Arc; /// A mutex that can safely be in async contexts and avoids deadlocks. -#[derive(Debug)] +#[derive(Default, Debug)] pub struct SharedMutex(Shared>); impl Clone for SharedMutex { diff --git a/crates/services/txpool/src/service.rs b/crates/services/txpool/src/service.rs index b30649b27e..6e5df0734e 100644 --- a/crates/services/txpool/src/service.rs +++ b/crates/services/txpool/src/service.rs @@ -34,7 +34,6 @@ use fuel_core_types::{ fuel_types::{ BlockHeight, Bytes32, - ChainId, }, services::{ block_importer::SharedImportResult, @@ -124,7 +123,6 @@ pub struct SharedState { tx_status_sender: TxStatusChange, txpool: Arc>>, p2p: Arc, - chain_id: ChainId, utxo_validation: bool, current_height: Arc>, consensus_parameters_provider: Arc, @@ -139,7 +137,6 @@ impl Clone tx_status_sender: self.tx_status_sender.clone(), txpool: self.txpool.clone(), p2p: self.p2p.clone(), - chain_id: self.chain_id, utxo_validation: self.utxo_validation, current_height: self.current_height.clone(), consensus_parameters_provider: self.consensus_parameters_provider.clone(), @@ -236,7 +233,6 @@ where new_transaction = self.gossiped_tx_stream.next() => { if let Some(GossipData { data: Some(tx), message_id, peer_id }) = new_transaction { - let id = tx.id(&self.tx_pool_shared_state.chain_id); let current_height = *self.tx_pool_shared_state.current_height.lock(); let params = self .tx_pool_shared_state @@ -254,6 +250,7 @@ where let acceptance = match checked_tx { Ok(tx) => { + let id = tx.transaction().cached_id().expect("`Checked` tx should have cached id"); let txs = vec![tx]; // insert tx @@ -504,9 +501,6 @@ where let committed_block_stream = importer.block_events(); let mut ttl_timer = tokio::time::interval(config.transaction_ttl); ttl_timer.set_missed_tick_behavior(MissedTickBehavior::Skip); - let chain_id = consensus_parameters_provider - .latest_consensus_parameters() - .chain_id(); let number_of_active_subscription = config.number_of_active_subscription; let txpool = Arc::new(ParkingMutex::new(TxPool::new(config.clone(), provider))); let task = Task { @@ -523,7 +517,6 @@ where ), txpool, p2p, - chain_id, utxo_validation: config.utxo_validation, current_height: Arc::new(ParkingMutex::new(current_height)), consensus_parameters_provider: Arc::new(consensus_parameters_provider), From 28a30458c971b9c288b091828b80f31d34301619 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Sat, 6 Apr 2024 18:28:02 +0200 Subject: [PATCH 04/14] Updated CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35d9d82ac7..df18abf3a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Description of the upcoming release here. ### Changed -- [#1808](https://github.com/FuelLabs/fuel-core/pull/1808): Fetch consensus parameters from the database. +- [#1809](https://github.com/FuelLabs/fuel-core/pull/1809): Fetch `ConsensusParameters` from the database +- [#1808](https://github.com/FuelLabs/fuel-core/pull/1808): Fetch consensus parameters from the provider. ## [Version 0.24.2] From 4e3cf61e80b25d0bacaaa5ce6db87269278c88a2 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Sat, 6 Apr 2024 20:50:27 +0200 Subject: [PATCH 05/14] Removed redundant `Arc` --- .../src/service/adapters/consensus_parameters_provider.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs b/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs index af30c766b7..3f6b40ed5d 100644 --- a/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs +++ b/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs @@ -31,9 +31,9 @@ use std::{ #[derive(Clone, Debug)] pub struct SharedState { - latest_consensus_parameters_version: Arc>, + latest_consensus_parameters_version: SharedMutex, consensus_parameters: - Arc>>>, + SharedMutex>>, database: Database, } @@ -46,9 +46,7 @@ impl SharedState { fn new(database: Database) -> StorageResult { let genesis_version = 0; let state = Self { - latest_consensus_parameters_version: Arc::new(SharedMutex::new( - genesis_version, - )), + latest_consensus_parameters_version: SharedMutex::new(genesis_version), consensus_parameters: Default::default(), database, }; From 1d5dbd84e8ecac33aa0a51843b0140dc4d9c84af Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 10 Apr 2024 03:00:36 +0200 Subject: [PATCH 06/14] Use state transition bytecode from the database --- Cargo.lock | 36 ++ bin/fuel-core/Cargo.toml | 2 +- .../services/upgradable-executor/Cargo.toml | 6 + .../upgradable-executor/src/executor.rs | 542 +++++++++++++++++- crates/storage/src/structured_storage.rs | 2 +- crates/types/src/services/block_producer.rs | 30 +- 6 files changed, 602 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00cc6b5c34..f801f28a06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3400,7 +3400,10 @@ dependencies = [ "fuel-core-storage", "fuel-core-types", "fuel-core-wasm-executor", + "ntest", + "parking_lot", "postcard", + "tracing", "wasmtime", ] @@ -5647,6 +5650,39 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "ntest" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cd16a2e6992865367e7ca50cd6953d09daaed93641421168733a1274afadd6" +dependencies = [ + "ntest_test_cases", + "ntest_timeout", +] + +[[package]] +name = "ntest_test_cases" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197eff6c12b80ff5de6173e438fa3c1340a9e708118c1626e690f65aee1e5332" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ntest_timeout" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef492b5cf80f90c050b287e747228a1fa6517e9d754f364b5a7e0e038e49a25f" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" diff --git a/bin/fuel-core/Cargo.toml b/bin/fuel-core/Cargo.toml index cb32c28c19..10c64171a5 100644 --- a/bin/fuel-core/Cargo.toml +++ b/bin/fuel-core/Cargo.toml @@ -21,7 +21,7 @@ clap = { workspace = true, features = ["derive", "env", "string"] } const_format = { version = "0.2", optional = true } dirs = "4.0" dotenvy = { version = "0.15", optional = true } -fuel-core = { workspace = true } +fuel-core = { workspace = true, features = ["wasm-executor"] } fuel-core-chain-config = { workspace = true } fuel-core-types = { workspace = true } hex = "0.4" diff --git a/crates/services/upgradable-executor/Cargo.toml b/crates/services/upgradable-executor/Cargo.toml index 491d3a3707..4f3c1e3d03 100644 --- a/crates/services/upgradable-executor/Cargo.toml +++ b/crates/services/upgradable-executor/Cargo.toml @@ -16,7 +16,9 @@ fuel-core-executor = { workspace = true } fuel-core-storage = { workspace = true } fuel-core-types = { workspace = true } fuel-core-wasm-executor = { workspace = true, optional = true } +parking_lot = { workspace = true, optional = true } postcard = { workspace = true, optional = true } +tracing = { workspace = true, optional = true } wasmtime = { version = "18.0.1", default-features = false, features = [ "cache", "cranelift", @@ -26,15 +28,19 @@ wasmtime = { version = "18.0.1", default-features = false, features = [ ], optional = true } [dev-dependencies] +anyhow = { workspace = true } fuel-core-storage = { workspace = true, features = ["test-helpers"] } fuel-core-types = { workspace = true, features = ["test-helpers"] } +ntest = "0.9.2" [features] default = ["std"] std = ["fuel-core-executor/std", "fuel-core-storage/std", "fuel-core-types/std"] wasm-executor = [ "dep:anyhow", + "dep:parking_lot", "dep:postcard", + "dep:tracing", "dep:fuel-core-wasm-executor", "dep:wasmtime", ] diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 639342780b..cecdbb958b 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -19,8 +19,6 @@ use fuel_core_storage::{ Modifiable, }, }; -#[cfg(any(test, feature = "test-helpers"))] -use fuel_core_types::services::executor::UncommittedResult; use fuel_core_types::{ blockchain::primitives::DaBlockHeight, fuel_tx::Transaction, @@ -28,6 +26,7 @@ use fuel_core_types::{ services::{ block_producer::Components, executor::{ + Error as ExecutorError, ExecutionResult, ExecutionTypes, Result as ExecutorResult, @@ -38,6 +37,27 @@ use fuel_core_types::{ }; use std::sync::Arc; +#[cfg(feature = "wasm-executor")] +use fuel_core_storage::{ + not_found, + structured_storage::StructuredStorage, + tables::StateTransitionBytecodeVersions, + StorageAsRef, +}; +#[cfg(any(test, feature = "test-helpers"))] +use fuel_core_types::services::executor::UncommittedResult; + +#[cfg(feature = "wasm-executor")] +enum ExecutionStrategy { + /// The executor used when the version matches. + Native, + /// The WASM executor used even when the version matches. + Wasm { + /// The compiled WASM module of the native executor bytecode. + module: wasmtime::Module, + }, +} + /// The upgradable executor supports the WASM version of the state transition function. /// If the block has a version the same as a native executor, we will use it. /// If not, the WASM version of the state transition function will be used @@ -49,7 +69,14 @@ pub struct Executor { #[cfg(feature = "wasm-executor")] engine: wasmtime::Engine, #[cfg(feature = "wasm-executor")] - module: wasmtime::Module, + execution_strategy: ExecutionStrategy, + #[cfg(feature = "wasm-executor")] + cached_modules: parking_lot::Mutex< + std::collections::HashMap< + fuel_core_types::blockchain::header::StateTransitionBytecodeVersion, + wasmtime::Module, + >, + >, } #[cfg(feature = "wasm-executor")] @@ -68,15 +95,68 @@ mod private { pub(crate) static COMPILED_UNDERLYING_EXECUTOR: OnceLock = OnceLock::new(); } +#[cfg(feature = "wasm-executor")] +/// The environment variable that forces the executor to use the WASM +/// version of the state transition function. +pub const FUEL_ALWAYS_USE_WASM: &str = "FUEL_ALWAYS_USE_WASM"; + impl Executor { + /// The current version of the native executor is used to determine whether + /// we need to use a native executor or WASM. If the version is the same as + /// on the block, native execution is used. If the version is not the same + /// as in the block, then the WASM executor is used. + pub const VERSION: u32 = 0; + /// This constant is used along with the `version_check` test. + /// To avoid automatic bumping during release, the constant uses `-` instead of `.`. + #[cfg(test)] + pub const CRATE_VERSION: &'static str = "0-24-2"; + pub fn new( storage_view_provider: S, relayer_view_provider: R, config: Config, ) -> Self { #[cfg(feature = "wasm-executor")] + { + if std::env::var_os(FUEL_ALWAYS_USE_WASM).is_some() { + Self::wasm(storage_view_provider, relayer_view_provider, config) + } else { + Self::native(storage_view_provider, relayer_view_provider, config) + } + } + #[cfg(not(feature = "wasm-executor"))] + { + Self::native(storage_view_provider, relayer_view_provider, config) + } + } + + pub fn native( + storage_view_provider: S, + relayer_view_provider: R, + config: Config, + ) -> Self { + Self { + storage_view_provider, + relayer_view_provider, + config: Arc::new(config), + #[cfg(feature = "wasm-executor")] + engine: private::DEFAULT_ENGINE + .get_or_init(wasmtime::Engine::default) + .clone(), + #[cfg(feature = "wasm-executor")] + execution_strategy: ExecutionStrategy::Native, + #[cfg(feature = "wasm-executor")] + cached_modules: Default::default(), + } + } + + #[cfg(feature = "wasm-executor")] + pub fn wasm( + storage_view_provider: S, + relayer_view_provider: R, + config: Config, + ) -> Self { let engine = private::DEFAULT_ENGINE.get_or_init(wasmtime::Engine::default); - #[cfg(feature = "wasm-executor")] let module = private::COMPILED_UNDERLYING_EXECUTOR.get_or_init(|| { wasmtime::Module::new(engine, crate::WASM_BYTECODE) .expect("Failed to compile the WASM bytecode") @@ -86,10 +166,11 @@ impl Executor { storage_view_provider, relayer_view_provider, config: Arc::new(config), - #[cfg(feature = "wasm-executor")] engine: engine.clone(), - #[cfg(feature = "wasm-executor")] - module: module.clone(), + execution_strategy: ExecutionStrategy::Wasm { + module: module.clone(), + }, + cached_modules: Default::default(), } } } @@ -217,6 +298,7 @@ where Ok(tx_status) } + #[cfg(feature = "wasm-executor")] fn execute_inner( &self, block: ExecutionBlockWithSource, @@ -225,16 +307,48 @@ where where TxSource: TransactionsSource + Send + Sync + 'static, { - #[cfg(feature = "wasm-executor")] - return self.wasm_execute_inner(block, options); + let block_version = block.state_transition_version(); + if block_version == Self::VERSION { + match &self.execution_strategy { + ExecutionStrategy::Native => self.native_execute_inner(block, options), + ExecutionStrategy::Wasm { module } => { + self.wasm_execute_inner(module, block, options) + } + } + } else { + let module = self.get_module(block_version)?; + tracing::warn!( + "The block version({}) is different from the native executor version({}). \ + The WASM executor will be used.", block_version, Self::VERSION + ); + self.wasm_execute_inner(&module, block, options) + } + } - #[cfg(not(feature = "wasm-executor"))] - return self.native_execute_inner(block, options); + #[cfg(not(feature = "wasm-executor"))] + fn execute_inner( + &self, + block: ExecutionBlockWithSource, + options: ExecutionOptions, + ) -> ExecutorResult> + where + TxSource: TransactionsSource + Send + Sync + 'static, + { + let block_version = block.state_transition_version(); + if block_version == Self::VERSION { + self.native_execute_inner(block, options) + } else { + Err(ExecutorError::Other(format!( + "Not supported version `{block_version}`. Expected version is `{}`", + Self::VERSION + ))) + } } #[cfg(feature = "wasm-executor")] fn wasm_execute_inner( &self, + module: &wasmtime::Module, block: ExecutionBlockWithSource, options: ExecutionOptions, ) -> ExecutorResult> @@ -269,10 +383,9 @@ where .add_relayer(relayer)? .add_input_data(block, options)?; - instance.run(&self.module) + instance.run(module) } - #[cfg(not(feature = "wasm-executor"))] fn native_execute_inner( &self, block: ExecutionBlockWithSource, @@ -291,4 +404,407 @@ where }; instance.execute_without_commit(block) } + + /// Returns the compiled WASM module of the state transition function. + /// + /// Note: The method compiles the WASM module if it is not cached. + /// It is a long process to call this method, which can block the thread. + #[cfg(feature = "wasm-executor")] + fn get_module( + &self, + version: fuel_core_types::blockchain::header::StateTransitionBytecodeVersion, + ) -> ExecutorResult { + let guard = self.cached_modules.lock(); + if let Some(module) = guard.get(&version) { + return Ok(module.clone()); + } + drop(guard); + + let view = StructuredStorage::new(self.storage_view_provider.latest_view()); + let bytecode = view + .storage::() + .get(&version)? + .ok_or(not_found!(StateTransitionBytecodeVersions))?; + + // Compiles the module + let module = + wasmtime::Module::new(&self.engine, bytecode.as_ref()).map_err(|e| { + ExecutorError::Other(format!( + "Failed to compile the module for the version `{}` with {e}", + version, + )) + })?; + + self.cached_modules.lock().insert(version, module.clone()); + Ok(module) + } +} + +#[cfg(test)] +mod test { + use super::*; + use fuel_core_storage::{ + kv_store::Value, + structured_storage::test::InMemoryStorage, + tables::ConsensusParametersVersions, + transactional::WriteTransaction, + Result as StorageResult, + StorageAsMut, + }; + use fuel_core_types::{ + blockchain::{ + block::{ + Block, + PartialFuelBlock, + }, + header::{ + ApplicationHeader, + ConsensusHeader, + PartialBlockHeader, + StateTransitionBytecodeVersion, + }, + primitives::Empty, + }, + fuel_tx::{ + AssetId, + Bytes32, + }, + services::relayer::Event, + tai64::Tai64, + }; + + #[derive(Clone, Debug)] + struct Storage(InMemoryStorage); + + impl AtomicView for Storage { + type View = InMemoryStorage; + type Height = BlockHeight; + + fn latest_height(&self) -> Option { + None + } + + fn view_at(&self, _: &Self::Height) -> StorageResult { + unimplemented!() + } + + fn latest_view(&self) -> Self::View { + self.0.clone() + } + } + + impl KeyValueInspect for Storage { + type Column = Column; + + fn get(&self, key: &[u8], column: Self::Column) -> StorageResult> { + self.0.get(key, column) + } + } + + impl Modifiable for Storage { + fn commit_changes(&mut self, changes: Changes) -> StorageResult<()> { + self.0.commit_changes(changes) + } + } + + #[derive(Copy, Clone)] + struct DisabledRelayer; + + impl RelayerPort for DisabledRelayer { + fn enabled(&self) -> bool { + false + } + + fn get_events(&self, _: &DaBlockHeight) -> anyhow::Result> { + unimplemented!() + } + } + + impl AtomicView for DisabledRelayer { + type View = Self; + type Height = DaBlockHeight; + + fn latest_height(&self) -> Option { + None + } + + fn view_at(&self, _: &Self::Height) -> StorageResult { + unimplemented!() + } + + fn latest_view(&self) -> Self::View { + *self + } + } + + #[test] + fn version_check() { + let crate_version = env!("CARGO_PKG_VERSION"); + let executor_cate_version = Executor::::CRATE_VERSION + .to_string() + .replace('-', "."); + assert_eq!( + executor_cate_version, crate_version, + "When this test fails, \ + it is a sign that maybe we need to increase the `Executor::VERSION`. \ + If there are no breaking changes that affect the execution, \ + then you can only increase `Executor::CRATE_VERSION` to pass this test." + ); + } + + const CONSENSUS_PARAMETERS_VERSION: u32 = 0; + + fn storage() -> Storage { + let mut storage = Storage(InMemoryStorage::default()); + let mut tx = storage.write_transaction(); + tx.storage_as_mut::() + .insert(&CONSENSUS_PARAMETERS_VERSION, &Default::default()) + .unwrap(); + tx.commit().unwrap(); + + storage + } + + fn valid_block( + state_transition_bytecode_version: StateTransitionBytecodeVersion, + ) -> Block { + PartialFuelBlock::new( + PartialBlockHeader { + application: ApplicationHeader { + da_height: Default::default(), + consensus_parameters_version: CONSENSUS_PARAMETERS_VERSION, + state_transition_bytecode_version, + generated: Empty, + }, + consensus: ConsensusHeader { + prev_root: Default::default(), + height: Default::default(), + time: Tai64::now(), + generated: Empty, + }, + }, + vec![Transaction::mint( + Default::default(), + Default::default(), + Default::default(), + Default::default(), + AssetId::BASE, + Default::default(), + ) + .into()], + ) + .generate(&[], Bytes32::zeroed()) + } + + #[cfg(not(feature = "wasm-executor"))] + mod native { + use super::*; + use crate::executor::Executor; + + #[test] + fn can_validate_block() { + let storage = storage(); + let executor = Executor::native(storage, DisabledRelayer, Config::default()); + + // Given + let block = valid_block(Executor::::VERSION); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert_eq!(Ok(()), result); + } + + #[test] + fn validation_fails_because_of_versions_mismatch() { + let storage = storage(); + let executor = Executor::native(storage, DisabledRelayer, Config::default()); + + // Given + let wrong_version = Executor::::VERSION + 1; + let block = valid_block(wrong_version); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert!(result.is_err()); + } + } + + #[cfg(feature = "wasm-executor")] + #[allow(non_snake_case)] + mod wasm { + use super::*; + use crate::{ + executor::Executor, + WASM_BYTECODE, + }; + + #[test] + fn can_validate_block__native_strategy() { + let storage = storage(); + + // Given + let executor = Executor::native(storage, DisabledRelayer, Config::default()); + let block = valid_block(Executor::::VERSION); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert_eq!(Ok(()), result); + } + + #[test] + fn can_validate_block__wasm_strategy() { + let storage = storage(); + + // Given + let executor = Executor::wasm(storage, DisabledRelayer, Config::default()); + let block = valid_block(Executor::::VERSION); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert_eq!(Ok(()), result); + } + + #[test] + fn validation_fails_because_of_versions_mismatch__native_strategy() { + let storage = storage(); + + // Given + let executor = Executor::native(storage, DisabledRelayer, Config::default()); + let wrong_version = Executor::::VERSION + 1; + let block = valid_block(wrong_version); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert!(result.is_err()); + } + + #[test] + fn validation_fails_because_of_versions_mismatch__wasm_strategy() { + let storage = storage(); + + // Given + let executor = Executor::wasm(storage, DisabledRelayer, Config::default()); + let wrong_version = Executor::::VERSION + 1; + let block = valid_block(wrong_version); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert!(result.is_err()); + } + + fn storage_with_state_transition( + next_version: StateTransitionBytecodeVersion, + ) -> Storage { + let mut storage = storage(); + let mut tx = storage.write_transaction(); + tx.storage_as_mut::() + .insert(&next_version, WASM_BYTECODE) + .unwrap(); + tx.commit().unwrap(); + + storage + } + + #[test] + fn can_validate_block_with_next_version__native_strategy() { + // Given + let next_version = Executor::::VERSION + 1; + let storage = storage_with_state_transition(next_version); + let executor = Executor::native(storage, DisabledRelayer, Config::default()); + let block = valid_block(next_version); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert_eq!(Ok(()), result); + } + + #[test] + fn can_validate_block_with_next_version__wasm_strategy() { + // Given + let next_version = Executor::::VERSION + 1; + let storage = storage_with_state_transition(next_version); + let executor = Executor::wasm(storage, DisabledRelayer, Config::default()); + let block = valid_block(next_version); + + // When + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block)) + .map(|_| ()); + + // Then + assert_eq!(Ok(()), result); + } + + // The test verifies that `Executor::get_module` method caches the compiled WASM module. + // If it doesn't cache the modules, the test will fail with a timeout. + #[test] + #[ntest::timeout(20_000)] + fn reuse_cached_compiled_module__native_strategy() { + // Given + let next_version = Executor::::VERSION + 1; + let storage = storage_with_state_transition(next_version); + let executor = Executor::native(storage, DisabledRelayer, Config::default()); + let block = valid_block(next_version); + + // When + for _ in 0..1000 { + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block.clone())) + .map(|_| ()); + + // Then + assert_eq!(Ok(()), result); + } + } + + // The test verifies that `Executor::get_module` method caches the compiled WASM module. + // If it doesn't cache the modules, the test will fail with a timeout. + #[test] + #[ntest::timeout(20_000)] + fn reuse_cached_compiled_module__wasm_strategy() { + // Given + let next_version = Executor::::VERSION + 1; + let storage = storage_with_state_transition(next_version); + let executor = Executor::wasm(storage, DisabledRelayer, Config::default()); + let block = valid_block(next_version); + + // When + for _ in 0..1000 { + let result = executor + .execute_without_commit(ExecutionTypes::Validation(block.clone())) + .map(|_| ()); + + // Then + assert_eq!(Ok(()), result); + } + } + } } diff --git a/crates/storage/src/structured_storage.rs b/crates/storage/src/structured_storage.rs index cee9484ea6..11fb9fa986 100644 --- a/crates/storage/src/structured_storage.rs +++ b/crates/storage/src/structured_storage.rs @@ -385,7 +385,7 @@ pub mod test { type Storage = HashMap<(u32, Vec), Value>; /// The in-memory storage for testing purposes. - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] pub struct InMemoryStorage { pub(crate) storage: Storage, _marker: core::marker::PhantomData, diff --git a/crates/types/src/services/block_producer.rs b/crates/types/src/services/block_producer.rs index 429371b22b..aeecb23ade 100644 --- a/crates/types/src/services/block_producer.rs +++ b/crates/types/src/services/block_producer.rs @@ -1,8 +1,15 @@ //! Types related to block producer service. use crate::{ - blockchain::header::PartialBlockHeader, + blockchain::{ + block::Block, + header::{ + PartialBlockHeader, + StateTransitionBytecodeVersion, + }, + }, fuel_tx::ContractId, + services::executor::ExecutionTypes, }; /// The components required to produce a block. @@ -20,3 +27,24 @@ pub struct Components { /// The gas price for all transactions in the block. pub gas_price: u64, } + +impl ExecutionTypes, Block> { + /// Returns the state transition bytecode version of the block. + pub fn state_transition_version(&self) -> StateTransitionBytecodeVersion { + match self { + ExecutionTypes::DryRun(component) => { + component + .header_to_produce + .state_transition_bytecode_version + } + ExecutionTypes::Production(component) => { + component + .header_to_produce + .state_transition_bytecode_version + } + ExecutionTypes::Validation(block) => { + block.header().state_transition_bytecode_version + } + } + } +} From d4164e4a7e026dfe2209af0f99076ed0e9b5e7ce Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 10 Apr 2024 03:06:38 +0200 Subject: [PATCH 07/14] Updated CHANGELOG.md --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c8021eeb9..831f59bf89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,19 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] Description of the upcoming release here. + ### Fixed - [#1814](https://github.com/FuelLabs/fuel-core/pull/1814): Bugfix: the `iter_all_by_prefix` was not working for all tables. The change adds a `Rust` level filtering. -======= + ### Added - [#1799](https://github.com/FuelLabs/fuel-core/pull/1799) Snapshot creation is now concurrent. ### Changed +- [#1816](https://github.com/FuelLabs/fuel-core/pull/1816): Updated the upgradable executor to fetch the state transition bytecode from the database when the version doesn't match a native one. This change enables the WASM executor in the "production" build and requires a `wasm32-unknown-unknown` target. - [#1812](https://github.com/FuelLabs/fuel-core/pull/1812): Follow-up PR to simplify the logic around parallel snapshot creation. - -### Changed - [#1809](https://github.com/FuelLabs/fuel-core/pull/1809): Fetch `ConsensusParameters` from the database - [#1808](https://github.com/FuelLabs/fuel-core/pull/1808): Fetch consensus parameters from the provider. From e12cca6b9eac8dae6b7241f118bfc08df77ed34d Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 10 Apr 2024 03:17:00 +0200 Subject: [PATCH 08/14] Fixed a comment --- crates/services/upgradable-executor/src/executor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index cecdbb958b..b3575deefb 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -49,7 +49,7 @@ use fuel_core_types::services::executor::UncommittedResult; #[cfg(feature = "wasm-executor")] enum ExecutionStrategy { - /// The executor used when the version matches. + /// The native executor used when the version matches. Native, /// The WASM executor used even when the version matches. Wasm { From eaffb17e7b3ee8b0638fb2336a6b8c49204ab96b Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 10 Apr 2024 03:36:05 +0200 Subject: [PATCH 09/14] Increased timeout for the CI. 40 seconds not even closer to real compilation time of 1000 modules --- crates/services/upgradable-executor/src/executor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index b3575deefb..a5a132b1e3 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -766,7 +766,7 @@ mod test { // The test verifies that `Executor::get_module` method caches the compiled WASM module. // If it doesn't cache the modules, the test will fail with a timeout. #[test] - #[ntest::timeout(20_000)] + #[ntest::timeout(40_000)] fn reuse_cached_compiled_module__native_strategy() { // Given let next_version = Executor::::VERSION + 1; @@ -788,7 +788,7 @@ mod test { // The test verifies that `Executor::get_module` method caches the compiled WASM module. // If it doesn't cache the modules, the test will fail with a timeout. #[test] - #[ntest::timeout(20_000)] + #[ntest::timeout(40_000)] fn reuse_cached_compiled_module__wasm_strategy() { // Given let next_version = Executor::::VERSION + 1; From 6ec1a6bdac7bd322fc5284790cd3e7c3bb5b639b Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 10 Apr 2024 12:18:28 +0200 Subject: [PATCH 10/14] Added tests for the service --- .../adapters/consensus_parameters_provider.rs | 200 +++++++++++++++++- crates/fuel-core/src/service/sub_services.rs | 2 +- crates/services/src/state.rs | 11 + 3 files changed, 203 insertions(+), 10 deletions(-) diff --git a/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs b/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs index 3f6b40ed5d..d8552efe30 100644 --- a/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs +++ b/crates/fuel-core/src/service/adapters/consensus_parameters_provider.rs @@ -26,6 +26,7 @@ use fuel_core_types::{ use futures::StreamExt; use std::{ collections::HashMap, + fmt::Debug, sync::Arc, }; @@ -42,16 +43,22 @@ pub struct Task { shared_state: SharedState, } +impl Debug for Task { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Task") + .field("shared_state", &self.shared_state) + .finish() + } +} + impl SharedState { - fn new(database: Database) -> StorageResult { + fn new(database: Database) -> Self { let genesis_version = 0; - let state = Self { + Self { latest_consensus_parameters_version: SharedMutex::new(genesis_version), consensus_parameters: Default::default(), database, - }; - - Ok(state) + } } fn cache_consensus_parameters( @@ -98,6 +105,7 @@ impl RunnableTask for Task { async fn run(&mut self, watcher: &mut StateWatcher) -> anyhow::Result { let should_continue; tokio::select! { + biased; _ = watcher.while_started() => { should_continue = false; @@ -168,10 +176,184 @@ impl RunnableService for Task { pub fn new_service( database: Database, importer: &BlockImporterAdapter, -) -> StorageResult> { +) -> ServiceRunner { let blocks_events = importer.block_events(); - Ok(ServiceRunner::new(Task { + ServiceRunner::new(Task { blocks_events, - shared_state: SharedState::new(database)?, - })) + shared_state: SharedState::new(database), + }) +} + +#[cfg(test)] +mod tests { + use crate::{ + database::Database, + service::adapters::consensus_parameters_provider::{ + SharedState, + Task, + }, + }; + use fuel_core_services::{ + stream::IntoBoxStream, + RunnableService, + RunnableTask, + StateWatcher, + }; + use fuel_core_storage::{ + tables::ConsensusParametersVersions, + transactional::IntoTransaction, + StorageAsMut, + }; + use fuel_core_types::{ + blockchain::{ + block::Block, + header::ConsensusParametersVersion, + SealedBlock, + }, + fuel_tx::ConsensusParameters, + services::block_importer::{ + ImportResult, + SharedImportResult, + }, + }; + use futures::stream; + + fn add_consensus_parameters( + database: Database, + consensus_parameters_version: ConsensusParametersVersion, + consensus_parameters: &ConsensusParameters, + ) -> Database { + let mut database = database.into_transaction(); + database + .storage_as_mut::() + .insert(&consensus_parameters_version, consensus_parameters) + .unwrap(); + database.commit().unwrap() + } + + #[tokio::test] + async fn latest_consensus_parameters_works() { + let version = 0; + let consensus_parameters = Default::default(); + + // Given + let database = + add_consensus_parameters(Database::default(), version, &consensus_parameters); + let state = SharedState::new(database); + + // When + let fetched_parameters = state.latest_consensus_parameters(); + + // Then + assert_eq!(fetched_parameters.as_ref(), &consensus_parameters); + } + + #[tokio::test] + async fn into_task_works_with_non_empty_database() { + let version = 0; + let consensus_parameters = Default::default(); + + // Given + let non_empty_database = + add_consensus_parameters(Database::default(), version, &consensus_parameters); + let task = Task { + blocks_events: stream::empty().into_boxed(), + shared_state: SharedState::new(non_empty_database), + }; + + // When + let result = task.into_task(&Default::default(), ()).await; + + // Then + result.expect("Initialization should succeed because database contains consensus parameters."); + } + + #[tokio::test] + async fn into_task_fails_when_no_parameters() { + // Given + let empty_database = Database::default(); + let task = Task { + blocks_events: stream::empty().into_boxed(), + shared_state: SharedState::new(empty_database), + }; + + // When + let result = task.into_task(&Default::default(), ()).await; + + // Then + result.expect_err( + "Initialization should fails because of lack of consensus parameters", + ); + } + + fn result_with_new_version( + version: ConsensusParametersVersion, + ) -> SharedImportResult { + let mut block = Block::default(); + block + .header_mut() + .application_mut() + .consensus_parameters_version = version; + let sealed_block = SealedBlock { + entity: block, + consensus: Default::default(), + }; + std::sync::Arc::new(ImportResult::new_from_local( + sealed_block, + Default::default(), + Default::default(), + )) + } + + #[tokio::test] + async fn run_updates_the_latest_consensus_parameters_from_imported_block() { + use futures::StreamExt; + + let old_version = 0; + let new_version = 1234; + let old_consensus_parameters = ConsensusParameters::default(); + let mut new_consensus_parameters = ConsensusParameters::default(); + new_consensus_parameters.set_privileged_address([123; 32].into()); + assert_ne!(old_consensus_parameters, new_consensus_parameters); + + let (block_sender, block_receiver) = + tokio::sync::broadcast::channel::(1); + let database_with_old_parameters = add_consensus_parameters( + Database::default(), + old_version, + &old_consensus_parameters, + ); + let mut task = Task { + blocks_events: IntoBoxStream::into_boxed( + tokio_stream::wrappers::BroadcastStream::new(block_receiver) + .filter_map(|r| futures::future::ready(r.ok())), + ), + shared_state: SharedState::new(database_with_old_parameters.clone()), + } + .into_task(&Default::default(), ()) + .await + .unwrap(); + assert_eq!( + task.shared_state.latest_consensus_parameters().as_ref(), + &old_consensus_parameters + ); + + // Given + add_consensus_parameters( + database_with_old_parameters, + new_version, + &new_consensus_parameters, + ); + + // When + let result_with_new_version = result_with_new_version(new_version); + let _ = block_sender.send(result_with_new_version); + task.run(&mut StateWatcher::started()).await.unwrap(); + + // Then + assert_eq!( + task.shared_state.latest_consensus_parameters().as_ref(), + &new_consensus_parameters + ); + } } diff --git a/crates/fuel-core/src/service/sub_services.rs b/crates/fuel-core/src/service/sub_services.rs index 6f4627e085..80194473af 100644 --- a/crates/fuel-core/src/service/sub_services.rs +++ b/crates/fuel-core/src/service/sub_services.rs @@ -96,7 +96,7 @@ pub fn init_sub_services( consensus_parameters_provider::new_service( database.on_chain().clone(), &importer_adapter, - )?; + ); let consensus_parameters_provider = ConsensusParametersProvider::new( consensus_parameters_provider_service.shared.clone(), ); diff --git a/crates/services/src/state.rs b/crates/services/src/state.rs index e060242c50..26559e2c19 100644 --- a/crates/services/src/state.rs +++ b/crates/services/src/state.rs @@ -54,6 +54,17 @@ impl Default for StateWatcher { } } +#[cfg(feature = "test-helpers")] +impl StateWatcher { + /// Create a new `StateWatcher` with the `State::Started` state. + pub fn started() -> Self { + let (sender, receiver) = watch::channel(State::Started); + // This function is used only in tests, so for simplicity of the tests, we want to leak sender. + core::mem::forget(sender); + Self(receiver) + } +} + impl StateWatcher { /// See [`watch::Receiver::borrow`]. pub fn borrow(&self) -> watch::Ref<'_, State> { From 3f06311d1afbbeeeecf4a42e93fc1fbcec48c235 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 10 Apr 2024 13:24:37 +0200 Subject: [PATCH 11/14] Applied comment from PR. Fixed the compilation of the debug image. Use WASM executor in some tests. --- .github/workflows/ci.yml | 1 + ci_checks.sh | 4 ++-- crates/services/upgradable-executor/build.rs | 1 + crates/services/upgradable-executor/src/executor.rs | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db13a359e5..50e99f505a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,7 @@ env: RUSTFLAGS: -D warnings REGISTRY: ghcr.io SEGMENT_DOWNLOAD_TIMEOUT_MINS: 2 + FUEL_ALWAYS_USE_WASM: true jobs: check-changelog: diff --git a/ci_checks.sh b/ci_checks.sh index b154534152..eea4c3e989 100755 --- a/ci_checks.sh +++ b/ci_checks.sh @@ -19,14 +19,14 @@ cargo clippy -p fuel-core-wasm-executor --target wasm32-unknown-unknown --no-def cargo clippy --all-targets --all-features && cargo doc --all-features --workspace --no-deps && cargo make check --locked && -cargo make check --all-features --locked && +FUEL_ALWAYS_USE_WASM=true cargo make check --all-features --locked && cargo check -p fuel-core-types --target wasm32-unknown-unknown --no-default-features && cargo check -p fuel-core-storage --target wasm32-unknown-unknown --no-default-features && cargo check -p fuel-core-client --target wasm32-unknown-unknown --no-default-features && cargo check -p fuel-core-chain-config --target wasm32-unknown-unknown --no-default-features && cargo check -p fuel-core-executor --target wasm32-unknown-unknown --no-default-features && cargo test --workspace && -cargo test --all-features --workspace && +FUEL_ALWAYS_USE_WASM=true cargo test --all-features --workspace && cargo test -p fuel-core --no-default-features && cargo test -p fuel-core-client --no-default-features && cargo test -p fuel-core-chain-config --no-default-features && diff --git a/crates/services/upgradable-executor/build.rs b/crates/services/upgradable-executor/build.rs index 26a9f86a16..7b0f6b5675 100644 --- a/crates/services/upgradable-executor/build.rs +++ b/crates/services/upgradable-executor/build.rs @@ -49,6 +49,7 @@ fn build_wasm() { cargo.env("CARGO_PROFILE_RELEASE_CODEGEN_UNITS", "1"); cargo.env("CARGO_PROFILE_RELEASE_OPT_LEVEL", "3"); cargo.env("CARGO_PROFILE_RELEASE_STRIP", "symbols"); + cargo.env("CARGO_PROFILE_RELEASE_DEBUG", "false"); cargo.current_dir(project_root()).args(args); let output = cargo.output(); diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index a5a132b1e3..c693b19d4e 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -633,7 +633,7 @@ mod test { .map(|_| ()); // Then - assert!(result.is_err()); + result.expect_err("The validation should fail because of versions mismatch"); } } @@ -695,7 +695,7 @@ mod test { .map(|_| ()); // Then - assert!(result.is_err()); + result.expect_err("The validation should fail because of versions mismatch"); } #[test] @@ -713,7 +713,7 @@ mod test { .map(|_| ()); // Then - assert!(result.is_err()); + result.expect_err("The validation should fail because of versions mismatch"); } fn storage_with_state_transition( From 874b1193975d926d474fbfb8041fadc5cfbc3d3f Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 10 Apr 2024 22:24:01 +0200 Subject: [PATCH 12/14] Increase the memory for the docker --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50e99f505a..ec28e42855 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -343,6 +343,10 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 + with: + context: . + memory: 4g + memory-swap: -1 - name: Log in to the ghcr.io registry uses: docker/login-action@v1 From 32177870fdb1ab8a2f2bbd5a691c22c57811210c Mon Sep 17 00:00:00 2001 From: xgreenx Date: Thu, 11 Apr 2024 01:31:59 +0200 Subject: [PATCH 13/14] Increase memory to 48g, if it is possible=D --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec28e42855..bf3e0ab77c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -344,8 +344,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 with: - context: . - memory: 4g + memory: 48g memory-swap: -1 - name: Log in to the ghcr.io registry From a6df71437fb6bf88ff1db31145aa6eb4552ca5b6 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Thu, 11 Apr 2024 02:04:39 +0200 Subject: [PATCH 14/14] Use 64 GB builder --- .github/workflows/ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf3e0ab77c..8dac1cc486 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,7 +318,7 @@ jobs: publish-docker-image-profiling: needs: - verifications-complete - runs-on: buildjet-4vcpu-ubuntu-2204 + runs-on: buildjet-16vcpu-ubuntu-2204 permissions: contents: read packages: write @@ -343,9 +343,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - with: - memory: 48g - memory-swap: -1 - name: Log in to the ghcr.io registry uses: docker/login-action@v1