From c1e0f54c53b76a34019d207d26759268f7d9fc06 Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 17 Apr 2024 12:48:37 -0700 Subject: [PATCH 01/13] Naively remove `Validation` exectution variant --- crates/services/executor/src/executor.rs | 38 +++++++---------- crates/types/src/services/block_producer.rs | 14 ++----- crates/types/src/services/executor.rs | 45 +++++---------------- 3 files changed, 29 insertions(+), 68 deletions(-) diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index 03bab4010d6..2a63f65327d 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -35,10 +35,7 @@ use fuel_core_storage::{ }; use fuel_core_types::{ blockchain::{ - block::{ - Block, - PartialFuelBlock, - }, + block::PartialFuelBlock, header::PartialBlockHeader, primitives::DaBlockHeight, }, @@ -150,7 +147,7 @@ use tracing::{ warn, }; -pub type ExecutionBlockWithSource = ExecutionTypes, Block>; +pub type ExecutionBlockWithSource = ExecutionTypes>; pub struct OnceTransactionsSource { transactions: ParkingMutex>, @@ -295,10 +292,6 @@ where // Compute the block id before execution if there is one. let pre_exec_block_id = block.id(); - // If there is full fuel block for validation then map it into - // a partial header. - let block = block.map_v(PartialFuelBlock::from); - let (block, execution_data) = match block { ExecutionTypes::DryRun(component) => { let mut block = @@ -341,20 +334,19 @@ where block_executor.execute_block(ExecutionType::Production(component))?; (block, execution_data) - } - ExecutionTypes::Validation(mut block) => { - let block_executor = BlockExecutor::new( - self.relayer, - self.database, - self.options, - &block, - )?; - - let component = PartialBlockComponent::from_partial_block(&mut block); - let execution_data = - block_executor.execute_block(ExecutionType::Validation(component))?; - (block, execution_data) - } + } /* ExecutionTypes::Validation(mut block) => { + * let block_executor = BlockExecutor::new( + * self.relayer, + * self.database, + * self.options, + * &block, + * )?; + * + * let component = PartialBlockComponent::from_partial_block(&mut block); + * let execution_data = + * block_executor.execute_block(ExecutionType::Validation(component))?; + * (block, execution_data) + * } */ }; let ExecutionData { diff --git a/crates/types/src/services/block_producer.rs b/crates/types/src/services/block_producer.rs index aeecb23adee..2909b3d201b 100644 --- a/crates/types/src/services/block_producer.rs +++ b/crates/types/src/services/block_producer.rs @@ -1,12 +1,9 @@ //! Types related to block producer service. use crate::{ - blockchain::{ - block::Block, - header::{ - PartialBlockHeader, - StateTransitionBytecodeVersion, - }, + blockchain::header::{ + PartialBlockHeader, + StateTransitionBytecodeVersion, }, fuel_tx::ContractId, services::executor::ExecutionTypes, @@ -28,7 +25,7 @@ pub struct Components { pub gas_price: u64, } -impl ExecutionTypes, Block> { +impl ExecutionTypes> { /// Returns the state transition bytecode version of the block. pub fn state_transition_version(&self) -> StateTransitionBytecodeVersion { match self { @@ -42,9 +39,6 @@ impl ExecutionTypes, Block> { .header_to_produce .state_transition_bytecode_version } - ExecutionTypes::Validation(block) => { - block.header().state_transition_bytecode_version - } } } } diff --git a/crates/types/src/services/executor.rs b/crates/types/src/services/executor.rs index 89dc45d3231..c81bdba4705 100644 --- a/crates/types/src/services/executor.rs +++ b/crates/types/src/services/executor.rs @@ -174,26 +174,23 @@ impl TransactionExecutionResult { /// depend on the type of execution. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum ExecutionTypes { +pub enum ExecutionTypes

{ /// DryRun mode where P is being produced. DryRun(P), /// Production mode where P is being produced. Production(P), - /// Validation mode where V is being checked. - Validation(V), } /// Starting point for executing a block. Production starts with a [`PartialFuelBlock`]. /// Validation starts with a full `FuelBlock`. -pub type ExecutionBlock = ExecutionTypes; +pub type ExecutionBlock = ExecutionTypes; -impl

ExecutionTypes { +impl

ExecutionTypes

{ /// Get the hash of the full `FuelBlock` if validating. pub fn id(&self) -> Option { match self { ExecutionTypes::DryRun(_) => None, ExecutionTypes::Production(_) => None, - ExecutionTypes::Validation(v) => Some(v.id()), } } } @@ -201,48 +198,33 @@ impl

ExecutionTypes { // TODO: Move `ExecutionType` and `ExecutionKind` into `fuel-core-executor` /// Execution wrapper with only a single type. -pub type ExecutionType = ExecutionTypes; +pub type ExecutionType = ExecutionTypes; -impl ExecutionTypes { +impl

ExecutionTypes

{ /// Map the production type if producing. - pub fn map_p(self, f: F) -> ExecutionTypes + pub fn map_p(self, f: F) -> ExecutionTypes where F: FnOnce(P) -> Q, { match self { ExecutionTypes::DryRun(p) => ExecutionTypes::DryRun(f(p)), ExecutionTypes::Production(p) => ExecutionTypes::Production(f(p)), - ExecutionTypes::Validation(v) => ExecutionTypes::Validation(v), - } - } - - /// Map the validation type if validating. - pub fn map_v(self, f: F) -> ExecutionTypes - where - F: FnOnce(V) -> W, - { - match self { - ExecutionTypes::DryRun(p) => ExecutionTypes::DryRun(p), - ExecutionTypes::Production(p) => ExecutionTypes::Production(p), - ExecutionTypes::Validation(v) => ExecutionTypes::Validation(f(v)), } } /// Get a reference version of the inner type. - pub fn as_ref(&self) -> ExecutionTypes<&P, &V> { + pub fn as_ref(&self) -> ExecutionTypes<&P> { match *self { ExecutionTypes::DryRun(ref p) => ExecutionTypes::DryRun(p), ExecutionTypes::Production(ref p) => ExecutionTypes::Production(p), - ExecutionTypes::Validation(ref v) => ExecutionTypes::Validation(v), } } /// Get a mutable reference version of the inner type. - pub fn as_mut(&mut self) -> ExecutionTypes<&mut P, &mut V> { + pub fn as_mut(&mut self) -> ExecutionTypes<&mut P> { match *self { ExecutionTypes::DryRun(ref mut p) => ExecutionTypes::DryRun(p), ExecutionTypes::Production(ref mut p) => ExecutionTypes::Production(p), - ExecutionTypes::Validation(ref mut v) => ExecutionTypes::Validation(v), } } @@ -251,7 +233,6 @@ impl ExecutionTypes { match self { ExecutionTypes::DryRun(_) => ExecutionKind::DryRun, ExecutionTypes::Production(_) => ExecutionKind::Production, - ExecutionTypes::Validation(_) => ExecutionKind::Validation, } } } @@ -265,7 +246,6 @@ impl ExecutionType { match self { ExecutionTypes::DryRun(p) => ExecutionTypes::DryRun(f(p)), ExecutionTypes::Production(p) => ExecutionTypes::Production(f(p)), - ExecutionTypes::Validation(v) => ExecutionTypes::Validation(f(v)), } } @@ -277,16 +257,13 @@ impl ExecutionType { match self { ExecutionTypes::DryRun(p) => f(p).map(ExecutionTypes::DryRun), ExecutionTypes::Production(p) => f(p).map(ExecutionTypes::Production), - ExecutionTypes::Validation(v) => f(v).map(ExecutionTypes::Validation), } } /// Get the inner type. pub fn into_inner(self) -> T { match self { - ExecutionTypes::DryRun(t) - | ExecutionTypes::Production(t) - | ExecutionTypes::Validation(t) => t, + ExecutionTypes::DryRun(t) | ExecutionTypes::Production(t) => t, } } @@ -304,7 +281,6 @@ impl core::ops::Deref for ExecutionType { match self { ExecutionTypes::DryRun(p) => p, ExecutionTypes::Production(p) => p, - ExecutionTypes::Validation(v) => v, } } } @@ -314,7 +290,6 @@ impl core::ops::DerefMut for ExecutionType { match self { ExecutionTypes::DryRun(p) => p, ExecutionTypes::Production(p) => p, - ExecutionTypes::Validation(v) => v, } } } @@ -336,7 +311,7 @@ impl ExecutionKind { match self { ExecutionKind::DryRun => ExecutionTypes::DryRun(t), ExecutionKind::Production => ExecutionTypes::Production(t), - ExecutionKind::Validation => ExecutionTypes::Validation(t), + ExecutionKind::Validation => todo!("remove this variant"), } } } From 5dfb4a32c71411b7025b23fa2ba36e560bfb7ccb Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 17 Apr 2024 14:53:00 -0700 Subject: [PATCH 02/13] Remove all uses of `Validation` execution type in tests, break tests with unimplemented code --- crates/fuel-core/src/executor.rs | 76 +++++++------------ .../src/service/adapters/block_importer.rs | 12 +-- .../src/service/adapters/executor.rs | 12 ++- crates/services/importer/src/importer.rs | 8 +- crates/services/importer/src/ports.rs | 7 +- .../upgradable-executor/src/executor.rs | 63 ++++++++------- 6 files changed, 87 insertions(+), 91 deletions(-) diff --git a/crates/fuel-core/src/executor.rs b/crates/fuel-core/src/executor.rs index 2fa3844c618..ce6004b3410 100644 --- a/crates/fuel-core/src/executor.rs +++ b/crates/fuel-core/src/executor.rs @@ -329,7 +329,7 @@ mod tests { #[test] fn executor_validates_correctly_produced_block() { let mut producer = create_executor(Default::default(), Default::default()); - let mut verifier = create_executor(Default::default(), Default::default()); + let verifier = create_executor(Default::default(), Default::default()); let block = test_block(1u32.into(), 0u64.into(), 10); let ExecutionResult { @@ -340,8 +340,7 @@ mod tests { .execute_and_commit(ExecutionTypes::Production(block.into())) .unwrap(); - let validation_result = - verifier.execute_and_commit(ExecutionTypes::Validation(block)); + let validation_result = verifier.validate(block); assert!(validation_result.is_ok()); assert!(skipped_transactions.is_empty()); } @@ -717,9 +716,7 @@ mod tests { let ExecutionResult { block: validated_block, .. - } = validator - .execute_and_commit(ExecutionBlock::Validation(produced_block)) - .unwrap(); + } = validator.validate_and_commit(produced_block).unwrap(); assert_eq!(validated_block.transactions(), produced_txs); let ContractBalance { asset_id, amount, .. @@ -841,7 +838,7 @@ mod tests { }, ); let validation_err = validator - .execute_and_commit(ExecutionBlock::Validation(block)) + .validate_and_commit(block) .expect_err("Expected error because coinbase if invalid"); assert!(matches!( validation_err, @@ -867,7 +864,7 @@ mod tests { let mut validator = create_executor(Default::default(), Default::default()); let validation_err = validator - .execute_and_commit(ExecutionBlock::Validation(block)) + .validate_and_commit(block) .expect_err("Expected error because coinbase if invalid"); assert!(matches!( validation_err, @@ -881,7 +878,7 @@ mod tests { let mut validator = create_executor(Default::default(), Default::default()); let validation_err = validator - .execute_and_commit(ExecutionBlock::Validation(block)) + .validate_and_commit(block) .expect_err("Expected error because coinbase is missing"); assert!(matches!(validation_err, ExecutorError::MintMissing)); } @@ -903,7 +900,7 @@ mod tests { let mut validator = create_executor(Default::default(), Default::default()); let validation_err = validator - .execute_and_commit(ExecutionBlock::Validation(block)) + .validate_and_commit(block) .expect_err("Expected error because coinbase if invalid"); assert!(matches!( @@ -938,7 +935,7 @@ mod tests { }; let mut validator = create_executor(Default::default(), config); let validation_err = validator - .execute_and_commit(ExecutionBlock::Validation(block)) + .validate_and_commit(block) .expect_err("Expected error because coinbase if invalid"); assert!(matches!( @@ -966,7 +963,7 @@ mod tests { let mut validator = create_executor(Default::default(), Default::default()); let validation_err = validator - .execute_and_commit(ExecutionBlock::Validation(block)) + .validate_and_commit(block) .expect_err("Expected error because coinbase if invalid"); assert!(matches!( validation_err, @@ -1028,15 +1025,14 @@ mod tests { // Produced block is valid let ExecutionResult { mut block, .. } = verifier - .execute_without_commit(ExecutionTypes::Validation(block)) + .validate_without_commit(block) .unwrap() .into_result(); // Invalidate the block with Insufficient tx let len = block.transactions().len(); block.transactions_mut().insert(len - 1, tx); - let verify_result = - verifier.execute_without_commit(ExecutionTypes::Validation(block)); + let verify_result = verifier.validate_without_commit(block); assert!(matches!( verify_result, Err(ExecutorError::InvalidTransaction( @@ -1077,7 +1073,7 @@ mod tests { // Produced block is valid let ExecutionResult { mut block, .. } = verifier - .execute_without_commit(ExecutionTypes::Validation(block)) + .validate_without_commit(block) .unwrap() .into_result(); @@ -1086,8 +1082,7 @@ mod tests { block .transactions_mut() .insert(len - 1, Transaction::default_test_tx()); - let verify_result = - verifier.execute_without_commit(ExecutionTypes::Validation(block)); + let verify_result = verifier.validate_without_commit(block); assert!(matches!( verify_result, Err(ExecutorError::TransactionIdCollision(_)) @@ -1150,15 +1145,14 @@ mod tests { // Produced block is valid let ExecutionResult { mut block, .. } = verifier - .execute_without_commit(ExecutionTypes::Validation(block)) + .validate_without_commit(block) .unwrap() .into_result(); // Invalidate block by adding transaction with not existing coin let len = block.transactions().len(); block.transactions_mut().insert(len - 1, tx); - let verify_result = - verifier.execute_without_commit(ExecutionTypes::Validation(block)); + let verify_result = verifier.validate_without_commit(block); assert!(matches!( verify_result, Err(ExecutorError::TransactionValidity( @@ -1203,8 +1197,7 @@ mod tests { } } - let verify_result = - verifier.execute_and_commit(ExecutionBlock::Validation(block)); + let verify_result = verifier.validate_and_commit(block); assert!(matches!( verify_result, Err(ExecutorError::InvalidTransactionOutcome { transaction_id }) if transaction_id == tx_id @@ -1240,8 +1233,7 @@ mod tests { block.header_mut().set_transaction_root(rng.gen()); block.header_mut().recalculate_metadata(); - let verify_result = - verifier.execute_and_commit(ExecutionBlock::Validation(block)); + let verify_result = verifier.validate_and_commit(block); assert!(matches!(verify_result, Err(ExecutorError::InvalidBlockId))) } @@ -1914,9 +1906,7 @@ mod tests { assert_eq!(tx.inputs()[0].state_root(), state_root); let _ = executor - .execute_without_commit_with_source::( - ExecutionTypes::Validation(block), - ) + .validate(block) .expect("Validation of block should be successful"); } @@ -2110,8 +2100,7 @@ mod tests { assert!(skipped_transactions.is_empty()); let verifier = create_executor(db, Default::default()); - let verify_result = - verifier.execute_without_commit(ExecutionBlock::Validation(second_block)); + let verify_result = verifier.validate_without_commit(second_block); assert!(verify_result.is_ok()); } @@ -2188,8 +2177,7 @@ mod tests { } let verifier = create_executor(db, Default::default()); - let verify_result = - verifier.execute_without_commit(ExecutionBlock::Validation(second_block)); + let verify_result = verifier.validate_without_commit(second_block); assert!(matches!( verify_result, @@ -2343,7 +2331,7 @@ mod tests { .expect("block execution failed unexpectedly"); make_executor(&[&message]) - .execute_and_commit(ExecutionBlock::Validation(block)) + .validate_and_commit(block) .expect("block validation failed unexpectedly"); } @@ -2468,14 +2456,14 @@ mod tests { // Produced block is valid make_executor(&[]) // No messages in the db - .execute_and_commit(ExecutionBlock::Validation(block.clone())) + .validate_and_commit(block.clone()) .unwrap(); // Invalidate block by returning back `tx` with not existing message let index = block.transactions().len() - 1; block.transactions_mut().insert(index, tx); let res = make_executor(&[]) // No messages in the db - .execute_and_commit(ExecutionBlock::Validation(block)); + .validate_and_commit(block); assert!(matches!( res, Err(ExecutorError::TransactionValidity( @@ -2510,14 +2498,13 @@ mod tests { // Produced block is valid make_executor(&[&message]) - .execute_and_commit(ExecutionBlock::Validation(block.clone())) + .validate_and_commit(block.clone()) .unwrap(); // Invalidate block by return back `tx` with not ready message. let index = block.transactions().len() - 1; block.transactions_mut().insert(index, tx); - let res = make_executor(&[&message]) - .execute_and_commit(ExecutionBlock::Validation(block)); + let res = make_executor(&[&message]).validate_and_commit(block); assert!(matches!( res, Err(ExecutorError::TransactionValidity( @@ -2589,16 +2576,14 @@ mod tests { // Produced block is valid let exec = make_executor(&[&message]); - let ExecutionResult { mut block, .. } = exec - .execute_without_commit(ExecutionTypes::Validation(block)) - .unwrap() - .into_result(); + let ExecutionResult { mut block, .. } = + exec.validate_without_commit(block).unwrap().into_result(); // Invalidate block by return back `tx2` transaction skipped during production. let len = block.transactions().len(); block.transactions_mut().insert(len - 1, tx2); let exec = make_executor(&[&message]); - let res = exec.execute_without_commit(ExecutionTypes::Validation(block)); + let res = exec.validate_without_commit(block); assert!(matches!( res, Err(ExecutorError::TransactionValidity( @@ -2810,10 +2795,7 @@ mod tests { assert!(skipped_transactions.is_empty()); let validator = create_executor(db.clone(), config); - let result = validator - .execute_without_commit_with_source::( - ExecutionTypes::Validation(block), - ); + let result = validator.validate(block); assert!(result.is_ok(), "{result:?}") } diff --git a/crates/fuel-core/src/service/adapters/block_importer.rs b/crates/fuel-core/src/service/adapters/block_importer.rs index 424d476afef..12a2ad57192 100644 --- a/crates/fuel-core/src/service/adapters/block_importer.rs +++ b/crates/fuel-core/src/service/adapters/block_importer.rs @@ -1,4 +1,3 @@ -use super::TransactionsSource; use crate::{ database::Database, service::adapters::{ @@ -10,8 +9,8 @@ use crate::{ use fuel_core_importer::{ ports::{ BlockVerifier, - Executor, ImporterDatabase, + Validator, }, Config, Importer, @@ -44,7 +43,6 @@ use fuel_core_types::{ ChainId, }, services::executor::{ - ExecutionTypes, Result as ExecutorResult, UncommittedResult as UncommittedExecutionResult, }, @@ -102,13 +100,11 @@ impl ImporterDatabase for Database { } } -impl Executor for ExecutorAdapter { - fn execute_without_commit( +impl Validator for ExecutorAdapter { + fn validate( &self, block: Block, ) -> ExecutorResult> { - self._execute_without_commit::(ExecutionTypes::Validation( - block, - )) + self._validate_block(block) } } diff --git a/crates/fuel-core/src/service/adapters/executor.rs b/crates/fuel-core/src/service/adapters/executor.rs index 74949c3c8e2..815325b439c 100644 --- a/crates/fuel-core/src/service/adapters/executor.rs +++ b/crates/fuel-core/src/service/adapters/executor.rs @@ -14,7 +14,10 @@ use fuel_core_executor::{ }; use fuel_core_storage::transactional::Changes; use fuel_core_types::{ - blockchain::primitives::DaBlockHeight, + blockchain::{ + block::Block, + primitives::DaBlockHeight, + }, fuel_tx, services::{ block_producer::Components, @@ -55,6 +58,13 @@ impl ExecutorAdapter { ) -> ExecutorResult> { self.executor.dry_run(block, utxo_validation) } + + pub(crate) fn _validate_block( + &self, + block: Block, + ) -> ExecutorResult> { + self.executor.validate(block) + } } impl fuel_core_executor::ports::RelayerPort for Database { diff --git a/crates/services/importer/src/importer.rs b/crates/services/importer/src/importer.rs index dbd524ae7a1..874649803b9 100644 --- a/crates/services/importer/src/importer.rs +++ b/crates/services/importer/src/importer.rs @@ -2,8 +2,8 @@ use crate::{ ports::{ BlockVerifier, DatabaseTransaction, - Executor, ImporterDatabase, + Validator, }, Config, }; @@ -354,7 +354,7 @@ where impl Importer where - E: Executor, + E: Validator, V: BlockVerifier, { /// Performs all checks required to commit the block, it includes the execution of @@ -410,7 +410,7 @@ where }, changes, ) = executor - .execute_without_commit(block) + .validate(block) .map_err(Error::FailedExecution)? .into(); @@ -440,7 +440,7 @@ where impl Importer where IDatabase: ImporterDatabase + 'static, - E: Executor + 'static, + E: Validator + 'static, V: BlockVerifier + 'static, { /// The method validates the `Block` fields and commits the `SealedBlock`. diff --git a/crates/services/importer/src/ports.rs b/crates/services/importer/src/ports.rs index c4a3c809f43..3795749c2e6 100644 --- a/crates/services/importer/src/ports.rs +++ b/crates/services/importer/src/ports.rs @@ -41,13 +41,10 @@ use fuel_core_types::{ #[cfg_attr(test, mockall::automock(type Database = crate::importer::test::MockDatabase;))] /// The executors port. -pub trait Executor: Send + Sync { +pub trait Validator: Send + Sync { /// Executes the block and returns the result of execution with uncommitted database /// transaction. - fn execute_without_commit( - &self, - block: Block, - ) -> ExecutorResult>; + fn validate(&self, block: Block) -> ExecutorResult>; } /// The trait indicates that the type supports storage transactions. diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 0875790733d..6a237c443bd 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -47,7 +47,10 @@ use fuel_core_storage::{ }, StorageAsRef, }; -use fuel_core_types::blockchain::header::StateTransitionBytecodeVersion; +use fuel_core_types::blockchain::{ + block::Block, + header::StateTransitionBytecodeVersion, +}; #[cfg(any(test, feature = "test-helpers"))] use fuel_core_types::services::executor::UncommittedResult; @@ -201,6 +204,15 @@ where self.storage_view_provider.commit_changes(changes)?; Ok(result) } + + #[cfg(any(test, feature = "test-helpers"))] + /// Executes the block and commits the result of the execution into the inner `Database`. + pub fn validate_and_commit( + &mut self, + _block: Block, + ) -> fuel_core_types::services::executor::Result { + todo!() + } } impl Executor @@ -219,6 +231,15 @@ where self.execute_without_commit_with_coinbase(block, Default::default(), 0) } + #[cfg(any(test, feature = "test-helpers"))] + /// Executes the block and returns the result of the execution with storage changes. + pub fn validate_without_commit( + &self, + _block: Block, + ) -> fuel_core_types::services::executor::Result> { + todo!() + } + #[cfg(any(test, feature = "test-helpers"))] /// The analog of the [`Self::execute_without_commit`] method, /// but with the ability to specify the coinbase recipient and the gas price. @@ -238,7 +259,6 @@ where coinbase_recipient, gas_price, }), - ExecutionTypes::Validation(block) => ExecutionTypes::Validation(block), }; let option = self.config.as_ref().into(); @@ -306,6 +326,13 @@ where Ok(tx_status) } + pub fn validate( + &self, + _block: Block, + ) -> ExecutorResult> { + todo!() + } + #[cfg(feature = "wasm-executor")] fn execute_inner( &self, @@ -635,9 +662,7 @@ mod test { let block = valid_block(Executor::::VERSION); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then assert_eq!(Ok(()), result); @@ -653,9 +678,7 @@ mod test { let block = valid_block(wrong_version); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then result.expect_err("The validation should fail because of versions mismatch"); @@ -682,9 +705,7 @@ mod test { let block = valid_block(Executor::::VERSION); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then assert_eq!(Ok(()), result); @@ -699,9 +720,7 @@ mod test { let block = valid_block(Executor::::VERSION); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then assert_eq!(Ok(()), result); @@ -717,9 +736,7 @@ mod test { let block = valid_block(wrong_version); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then result.expect_err("The validation should fail because of versions mismatch"); @@ -735,9 +752,7 @@ mod test { let block = valid_block(wrong_version); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then result.expect_err("The validation should fail because of versions mismatch"); @@ -776,9 +791,7 @@ mod test { let block = valid_block(next_version); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then assert_eq!(Ok(()), result); @@ -793,9 +806,7 @@ mod test { let block = valid_block(next_version); // When - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block)) - .map(|_| ()); + let result = executor.validate_without_commit(block).map(|_| ()); // Then assert_eq!(Ok(()), result); From 777212d1b07c0bf1e80cae5643563f123e8fda12 Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 17 Apr 2024 17:43:56 -0700 Subject: [PATCH 03/13] WIP getting tests to pass --- .../upgradable-executor/src/executor.rs | 75 +++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 6a237c443bd..33875d125f5 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -211,7 +211,10 @@ where &mut self, _block: Block, ) -> fuel_core_types::services::executor::Result { - todo!() + let (result, changes) = self.validate_without_commit(_block)?.into(); + + self.storage_view_provider.commit_changes(changes)?; + Ok(result) } } @@ -235,9 +238,10 @@ where /// Executes the block and returns the result of the execution with storage changes. pub fn validate_without_commit( &self, - _block: Block, + block: Block, ) -> fuel_core_types::services::executor::Result> { - todo!() + let options = self.config.as_ref().into(); + self.validate_inner(block, options) } #[cfg(any(test, feature = "test-helpers"))] @@ -261,8 +265,8 @@ where }), }; - let option = self.config.as_ref().into(); - self.execute_inner(component, option) + let options = self.config.as_ref().into(); + self.execute_inner(component, options) } } @@ -382,6 +386,49 @@ where } } + #[cfg(feature = "wasm-executor")] + fn validate_inner( + &self, + block: Block, + options: ExecutionOptions, + ) -> ExecutorResult> { + let block_version = block.header().state_transition_bytecode_version; + let native_executor_version = self.native_executor_version(); + if block_version == native_executor_version { + match &self.execution_strategy { + ExecutionStrategy::Native => self.native_validate_inner(block, options), + ExecutionStrategy::Wasm { module } => { + self.wasm_validate_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_validate_inner(&module, block, self.config.as_ref().into()) + } + } + + #[cfg(not(feature = "wasm-executor"))] + fn validate_inner( + &self, + block: Block, + options: ExecutionOptions, + ) -> ExecutorResult> { + let block_version = block.header().state_transition_bytecode_version; + let native_executor_version = self.native_executor_version(); + if block_version == native_executor_version { + self.native_validate_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, @@ -427,6 +474,16 @@ where } } + #[cfg(feature = "wasm-executor")] + fn wasm_validate_inner( + &self, + _module: &wasmtime::Module, + _block: Block, + _options: ExecutionOptions, + ) -> ExecutorResult> { + todo!() + } + fn native_execute_inner( &self, block: ExecutionBlockWithSource, @@ -446,6 +503,14 @@ where instance.execute_without_commit(block) } + fn native_validate_inner( + &self, + _block: Block, + _options: ExecutionOptions, + ) -> ExecutorResult> { + todo!() + } + /// Returns the compiled WASM module of the state transition function. /// /// Note: The method compiles the WASM module if it is not cached. From 4a311e561d72c6f5403e76147a65a9872dbc6aef Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 18 Apr 2024 11:46:19 -0700 Subject: [PATCH 04/13] Implement validate route and get most of tests passing again --- crates/services/executor/src/executor.rs | 213 ++++++++++++++++-- .../upgradable-executor/src/executor.rs | 14 +- 2 files changed, 210 insertions(+), 17 deletions(-) diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index 2a63f65327d..f3eb8029efe 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -35,7 +35,10 @@ use fuel_core_storage::{ }; use fuel_core_types::{ blockchain::{ - block::PartialFuelBlock, + block::{ + Block, + PartialFuelBlock, + }, header::PartialBlockHeader, primitives::DaBlockHeight, }, @@ -222,6 +225,13 @@ where { self.execute_inner(block) } + + pub fn validate_without_commit( + self, + block: Block, + ) -> ExecutorResult> { + self.validate_inner(block) + } } // TODO: Make this module private after moving unit tests from `fuel-core` here. @@ -334,19 +344,7 @@ where block_executor.execute_block(ExecutionType::Production(component))?; (block, execution_data) - } /* ExecutionTypes::Validation(mut block) => { - * let block_executor = BlockExecutor::new( - * self.relayer, - * self.database, - * self.options, - * &block, - * )?; - * - * let component = PartialBlockComponent::from_partial_block(&mut block); - * let execution_data = - * block_executor.execute_block(ExecutionType::Validation(component))?; - * (block, execution_data) - * } */ + } }; let ExecutionData { @@ -392,6 +390,63 @@ where // Get the complete fuel block. Ok(UncommittedResult::new(result, changes)) } + + fn validate_inner(self, block: Block) -> ExecutorResult> { + // Compute the block id before execution if there is one. + let pre_exec_block_id = block.id(); + + let (block, execution_data) = { + let mut partial_block = block.into(); + let block_executor = BlockExecutor::new( + self.relayer, + self.database, + self.options, + &partial_block, + )?; + + let component = PartialBlockComponent::from_partial_block(&mut partial_block); + let execution_data = block_executor.validate_block(component)?; + (partial_block, execution_data) + }; + + let ExecutionData { + coinbase, + used_gas, + message_ids, + tx_status, + skipped_transactions, + events, + changes, + event_inbox_root, + .. + } = execution_data; + + // Now that the transactions have been executed, generate the full header. + + let block = block.generate(&message_ids[..], event_inbox_root); + + let finalized_block_id = block.id(); + + debug!( + "Block {:#x} fees: {} gas: {}", + pre_exec_block_id, coinbase, used_gas + ); + + // check if block id doesn't match proposed block id + if pre_exec_block_id != finalized_block_id { + return Err(ExecutorError::InvalidBlockId) + } + + let result = ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }; + + // Get the complete fuel block. + Ok(UncommittedResult::new(result, changes)) + } } #[derive(Clone, Debug)] @@ -617,7 +672,137 @@ where } data.changes = self.block_st_transaction.into_changes(); + Ok(data) + } + + #[tracing::instrument(skip_all)] + fn validate_block( + mut self, + component: PartialBlockComponent, + ) -> ExecutorResult { + let block_gas_limit = self.consensus_params.block_gas_limit(); + let mut data = ExecutionData { + coinbase: 0, + used_gas: 0, + tx_count: 0, + found_mint: false, + message_ids: Vec::new(), + tx_status: Vec::new(), + events: Vec::new(), + changes: Default::default(), + skipped_transactions: Vec::new(), + event_inbox_root: Default::default(), + }; + let execution_data = &mut data; + + // Split out the execution kind and partial block. + let block = component.empty_block; + let source = component.transactions_source; + let gas_price = component.gas_price; + let coinbase_contract_id = component.coinbase_contract_id; + let block_height = *block.header.height(); + + let forced_transactions = if self.relayer.enabled() { + self.process_da(&block.header, execution_data)? + } else { + Vec::with_capacity(0) + }; + + // The block level storage transaction that also contains data from the relayer. + // Starting from this point, modifications from each thread should be independent + // and shouldn't touch the same data. + let mut block_with_relayer_data_transaction = self.block_st_transaction.read_transaction() + // Enforces independent changes from each thread. + .with_policy(ConflictPolicy::Fail); + + // We execute transactions in a single thread right now, but later, + // we will execute them in parallel with a separate independent storage transaction per thread. + let mut thread_block_transaction = block_with_relayer_data_transaction + .read_transaction() + .with_policy(ConflictPolicy::Overwrite); + + debug_assert!(block.transactions.is_empty()); + + let mut execute_transaction = |execution_data: &mut ExecutionData, + tx: MaybeCheckedTransaction, + gas_price: Word| + -> ExecutorResult<()> { + let tx_count = execution_data.tx_count; + let tx = { + let mut tx_st_transaction = thread_block_transaction + .write_transaction() + .with_policy(ConflictPolicy::Overwrite); + let tx_id = tx.id(&self.consensus_params.chain_id()); + let tx = self.execute_transaction( + tx, + &tx_id, + &block.header, + coinbase_contract_id, + gas_price, + execution_data, + ExecutionKind::Validation, + &mut tx_st_transaction, + )?; + tx_st_transaction.commit()?; + tx + }; + + block.transactions.push(tx); + execution_data.tx_count = tx_count + .checked_add(1) + .ok_or(ExecutorError::TooManyTransactions)?; + + Ok(()) + }; + + let relayed_tx_iter = forced_transactions.into_iter(); + for transaction in relayed_tx_iter { + const RELAYED_GAS_PRICE: Word = 0; + let transaction = MaybeCheckedTransaction::CheckedTransaction(transaction); + let tx_id = transaction.id(&self.consensus_params.chain_id()); + match execute_transaction( + &mut *execution_data, + transaction, + RELAYED_GAS_PRICE, + ) { + Ok(_) => {} + Err(err) => { + let event = ExecutorEvent::ForcedTransactionFailed { + id: tx_id.into(), + block_height, + failure: err.to_string(), + }; + execution_data.events.push(event); + } + } + } + let remaining_gas_limit = block_gas_limit.saturating_sub(execution_data.used_gas); + + // L2 originated transactions should be in the `TxSource`. This will be triggered after + // all relayed transactions are processed. + let mut regular_tx_iter = source.next(remaining_gas_limit).into_iter().peekable(); + while regular_tx_iter.peek().is_some() { + for transaction in regular_tx_iter { + execute_transaction(&mut *execution_data, transaction, gas_price)?; + } + + let new_remaining_gas_limit = + block_gas_limit.saturating_sub(execution_data.used_gas); + + regular_tx_iter = source.next(new_remaining_gas_limit).into_iter().peekable(); + } + + let changes_from_thread = thread_block_transaction.into_changes(); + block_with_relayer_data_transaction.commit_changes(changes_from_thread)?; + self.block_st_transaction + .commit_changes(block_with_relayer_data_transaction.into_changes())?; + + if !data.found_mint { + return Err(ExecutorError::MintMissing) + } + + data.changes = self.block_st_transaction.into_changes(); Ok(data) } diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 33875d125f5..2eec1d4d9b5 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -505,10 +505,18 @@ where fn native_validate_inner( &self, - _block: Block, - _options: ExecutionOptions, + block: Block, + options: ExecutionOptions, ) -> ExecutorResult> { - todo!() + let storage = self.storage_view_provider.latest_view(); + let relayer = self.relayer_view_provider.latest_view(); + + let instance = fuel_core_executor::executor::ExecutionInstance { + relayer, + database: storage, + options, + }; + instance.validate_without_commit(block) } /// Returns the compiled WASM module of the state transition function. From 94bff0498a5227c6e922306102f86e6d7eca07cd Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 18 Apr 2024 11:49:14 -0700 Subject: [PATCH 05/13] Implement `validate` and fix other tests --- crates/services/upgradable-executor/src/executor.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 2eec1d4d9b5..d2e4c2f298d 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -332,9 +332,10 @@ where pub fn validate( &self, - _block: Block, + block: Block, ) -> ExecutorResult> { - todo!() + let options = self.config.as_ref().into(); + self.validate_inner(block, options) } #[cfg(feature = "wasm-executor")] From 74f5e1f8be366b8feca357771314fbc5ad02e0e8 Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 18 Apr 2024 11:53:30 -0700 Subject: [PATCH 06/13] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fee0162125..27d5eb110fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Description of the upcoming release here. ### Changed +- [#1837](https://github.com/FuelLabs/fuel-core/pull/1837): Refactor the executor and separate validation from the other use cases - [#1830](https://github.com/FuelLabs/fuel-core/pull/1830): Use versioning enum for WASM executor input and output. - [#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. From cc78682a782b34984cdb1363fd8d9c3de9bbea3d Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 18 Apr 2024 12:07:58 -0700 Subject: [PATCH 07/13] Fix checks --- crates/fuel-core/src/executor.rs | 2 +- crates/services/importer/src/importer/test.rs | 44 +++++++++---------- .../upgradable-executor/src/executor.rs | 8 +--- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/crates/fuel-core/src/executor.rs b/crates/fuel-core/src/executor.rs index ce6004b3410..10ec28fe5d4 100644 --- a/crates/fuel-core/src/executor.rs +++ b/crates/fuel-core/src/executor.rs @@ -3354,7 +3354,7 @@ mod tests { add_events_to_relayer(&mut verifier_relayer_db, da_height.into(), &events); let verifier = create_relayer_executor(verifyer_db, verifier_relayer_db); let (result, _) = verifier - .execute_without_commit(ExecutionTypes::Validation(produced_block)) + .validate_without_commit(produced_block) .unwrap() .into(); diff --git a/crates/services/importer/src/importer/test.rs b/crates/services/importer/src/importer/test.rs index d0b2a0e9892..0bd59484146 100644 --- a/crates/services/importer/src/importer/test.rs +++ b/crates/services/importer/src/importer/test.rs @@ -4,7 +4,7 @@ use crate::{ ImporterDatabase, MockBlockVerifier, MockDatabaseTransaction, - MockExecutor, + MockValidator, Transactional, }, Importer, @@ -160,28 +160,26 @@ fn execution_failure_error() -> Error { Error::FailedExecution(ExecutorError::InvalidBlockId) } -fn executor(result: R) -> MockExecutor +fn executor(result: R) -> MockValidator where R: Fn() -> ExecutorResult + Send + 'static, { - let mut executor = MockExecutor::default(); - executor - .expect_execute_without_commit() - .return_once(move |_| { - let mock_result = result()?; - let skipped_transactions: Vec<_> = (0..mock_result.skipped_transactions) - .map(|_| (TxId::zeroed(), ExecutorError::InvalidBlockId)) - .collect(); - Ok(Uncommitted::new( - ExecutionResult { - block: mock_result.block.entity, - skipped_transactions, - tx_status: vec![], - events: vec![], - }, - Default::default(), - )) - }); + let mut executor = MockValidator::default(); + executor.expect_validate().return_once(move |_| { + let mock_result = result()?; + let skipped_transactions: Vec<_> = (0..mock_result.skipped_transactions) + .map(|_| (TxId::zeroed(), ExecutorError::InvalidBlockId)) + .collect(); + Ok(Uncommitted::new( + ExecutionResult { + block: mock_result.block.entity, + skipped_transactions, + tx_status: vec![], + events: vec![], + }, + Default::default(), + )) + }); executor } @@ -383,7 +381,7 @@ async fn commit_result_assert( async fn execute_and_commit_assert( sealed_block: SealedBlock, underlying_db: MockDatabase, - executor: MockExecutor, + executor: MockValidator, verifier: MockBlockVerifier, ) -> Result<(), Error> { let expected_to_broadcast = sealed_block.clone(); @@ -423,7 +421,7 @@ async fn commit_result_fail_when_locked() { async fn execute_and_commit_fail_when_locked() { let importer = Importer::default_config( MockDatabase::default(), - MockExecutor::default(), + MockValidator::default(), MockBlockVerifier::default(), ); @@ -438,7 +436,7 @@ async fn execute_and_commit_fail_when_locked() { fn one_lock_at_the_same_time() { let importer = Importer::default_config( MockDatabase::default(), - MockExecutor::default(), + MockValidator::default(), MockBlockVerifier::default(), ); diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index d2e4c2f298d..7a3d12099d7 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -899,9 +899,7 @@ mod test { // When for _ in 0..1000 { - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block.clone())) - .map(|_| ()); + let result = executor.validate_without_commit(block.clone()).map(|_| ()); // Then assert_eq!(Ok(()), result); @@ -921,9 +919,7 @@ mod test { // When for _ in 0..1000 { - let result = executor - .execute_without_commit(ExecutionTypes::Validation(block.clone())) - .map(|_| ()); + let result = executor.validate_without_commit(block.clone()).map(|_| ()); // Then assert_eq!(Ok(()), result); From 70d672b96226212ef7b1dfcda081d632393033cd Mon Sep 17 00:00:00 2001 From: Turner Date: Thu, 18 Apr 2024 15:30:28 -0700 Subject: [PATCH 08/13] Fix most of the Wasm tests --- .../upgradable-executor/src/executor.rs | 23 +++- .../upgradable-executor/src/instance.rs | 60 ++++++++- .../wasm-executor/src/main.rs | 126 +++++++++++++++--- .../wasm-executor/src/utils.rs | 31 +++-- 4 files changed, 199 insertions(+), 41 deletions(-) diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 7a3d12099d7..917d56fd1f4 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -466,7 +466,7 @@ where .add_source(source)? .add_storage(storage)? .add_relayer(relayer)? - .add_input_data(block, options)?; + .add_execution_input_data(block, options)?; let output = instance.run(module)?; @@ -478,11 +478,24 @@ where #[cfg(feature = "wasm-executor")] fn wasm_validate_inner( &self, - _module: &wasmtime::Module, - _block: Block, - _options: ExecutionOptions, + module: &wasmtime::Module, + block: Block, + options: ExecutionOptions, ) -> ExecutorResult> { - todo!() + let storage = self.storage_view_provider.latest_view(); + let relayer = self.relayer_view_provider.latest_view(); + + let instance = crate::instance::Instance::new(&self.engine) + .no_source()? + .add_storage(storage)? + .add_relayer(relayer)? + .add_validation_input_data(block, options)?; + + let output = instance.run(module)?; + + match output { + fuel_core_wasm_executor::utils::ReturnType::V1(result) => result, + } } fn native_execute_inner( diff --git a/crates/services/upgradable-executor/src/instance.rs b/crates/services/upgradable-executor/src/instance.rs index c0a1cc128a9..f4a9c440d34 100644 --- a/crates/services/upgradable-executor/src/instance.rs +++ b/crates/services/upgradable-executor/src/instance.rs @@ -17,7 +17,10 @@ use fuel_core_storage::{ }, }; use fuel_core_types::{ - blockchain::primitives::DaBlockHeight, + blockchain::{ + block::Block, + primitives::DaBlockHeight, + }, fuel_tx::Transaction, fuel_vm::checked_transaction::Checked, services::executor::{ @@ -30,6 +33,7 @@ use fuel_core_wasm_executor::utils::{ unpack_ptr_and_len, InputType, ReturnType, + WasmExecutionBlockTypes, }; use std::{ collections::HashMap, @@ -146,6 +150,20 @@ impl Instance { }) } + pub fn no_source(mut self) -> ExecutorResult> { + let peek_next_txs_size = self.no_source_peek_next_txs_size(); + self.add_method("peek_next_txs_size", peek_next_txs_size)?; + + let consume_next_txs = self.consume_next_txs(); + self.add_method("consume_next_txs", consume_next_txs)?; + + Ok(Instance { + store: self.store, + linker: self.linker, + stage: Source {}, + }) + } + fn peek_next_txs_size(&mut self, source: Option>) -> Func where TxSource: TransactionsSource + Send + Sync + 'static, @@ -195,6 +213,13 @@ impl Instance { Func::wrap(&mut self.store, closure) } + fn no_source_peek_next_txs_size(&mut self) -> Func { + let closure = + move |_: Caller<'_, ExecutionState>, _: u64| -> anyhow::Result { Ok(0) }; + + Func::wrap(&mut self.store, closure) + } + fn consume_next_txs(&mut self) -> Func { let closure = move |mut caller: Caller<'_, ExecutionState>, output_ptr: u32, @@ -429,12 +454,39 @@ pub struct InputData { impl Instance { /// Adds getters for the `block` and `options`. - pub fn add_input_data( - mut self, + pub fn add_execution_input_data( + self, block: ExecutionBlockWithSource<()>, options: ExecutionOptions, ) -> ExecutorResult> { - let input = InputType::V1 { block, options }; + let wasm_block = match block { + ExecutionBlockWithSource::DryRun(inner) => { + WasmExecutionBlockTypes::DryRun(inner) + } + ExecutionBlockWithSource::Production(inner) => { + WasmExecutionBlockTypes::Production(inner) + } + }; + let input = InputType::V1 { + block: wasm_block, + options, + }; + self.add_input_data(input) + } + + pub fn add_validation_input_data( + self, + block: Block, + options: ExecutionOptions, + ) -> ExecutorResult> { + let input = InputType::V1 { + block: WasmExecutionBlockTypes::Validation(block), + options, + }; + self.add_input_data(input) + } + + fn add_input_data(mut self, input: InputType) -> ExecutorResult> { let encoded_input = postcard::to_allocvec(&input).map_err(|e| { ExecutorError::Other(format!( "Failed encoding of the input for `input` function: {}", diff --git a/crates/services/upgradable-executor/wasm-executor/src/main.rs b/crates/services/upgradable-executor/wasm-executor/src/main.rs index f58ca182f85..e7fa0c99ac2 100644 --- a/crates/services/upgradable-executor/wasm-executor/src/main.rs +++ b/crates/services/upgradable-executor/wasm-executor/src/main.rs @@ -14,16 +14,23 @@ #![deny(warnings)] use crate as fuel_core_wasm_executor; -use fuel_core_executor::executor::ExecutionInstance; +use crate::utils::WasmExecutionBlockTypes; +use fuel_core_executor::executor::{ + ExecutionBlockWithSource, + ExecutionInstance, +}; use fuel_core_storage::transactional::Changes; -use fuel_core_types::services::{ - block_producer::Components, - executor::{ - Error as ExecutorError, - ExecutionResult, - Result as ExecutorResult, +use fuel_core_types::{ + blockchain::block::Block, + services::{ + block_producer::Components, + executor::{ + Error as ExecutorError, + ExecutionResult, + Result as ExecutorResult, + }, + Uncommitted, }, - Uncommitted, }; use fuel_core_wasm_executor::{ relayer::WasmRelayer, @@ -62,21 +69,17 @@ pub fn execute_without_commit( let (block, options) = match input { InputType::V1 { block, options } => { - let block = block.map_p(|component| { - let Components { - header_to_produce, - gas_price, - coinbase_recipient, - .. - } = component; - - Components { - header_to_produce, - gas_price, - transactions_source: WasmTxSource::new(), - coinbase_recipient, + let block = match block { + WasmExecutionBlockTypes::DryRun(c) => { + WasmExecutionBlockTypes::DryRun(use_wasm_tx_source(c)) + } + WasmExecutionBlockTypes::Production(c) => { + WasmExecutionBlockTypes::Production(use_wasm_tx_source(c)) + } + WasmExecutionBlockTypes::Validation(c) => { + WasmExecutionBlockTypes::Validation(c) } - }); + }; (block, options) } @@ -88,6 +91,18 @@ pub fn execute_without_commit( options, }; + match block { + WasmExecutionBlockTypes::DryRun(c) => execute_dry_run(instance, c), + WasmExecutionBlockTypes::Production(c) => execute_production(instance, c), + WasmExecutionBlockTypes::Validation(c) => execute_validation(instance, c), + } +} + +fn execute_dry_run( + instance: ExecutionInstance, + block: Components, +) -> ExecutorResult> { + let block = ExecutionBlockWithSource::DryRun(block); let ( ExecutionResult { block, @@ -109,5 +124,72 @@ pub fn execute_without_commit( )) } +fn execute_production( + instance: ExecutionInstance, + block: Components, +) -> ExecutorResult> { + let block = ExecutionBlockWithSource::Production(block); + let ( + ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }, + changes, + ) = instance.execute_without_commit(block)?.into(); + + Ok(Uncommitted::new( + ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }, + changes, + )) +} + +fn execute_validation( + instance: ExecutionInstance, + block: Block, +) -> ExecutorResult> { + let ( + ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }, + changes, + ) = instance.validate_without_commit(block)?.into(); + + Ok(Uncommitted::new( + ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }, + changes, + )) +} + +fn use_wasm_tx_source(component: Components<()>) -> Components { + let Components { + header_to_produce, + gas_price, + coinbase_recipient, + .. + } = component; + + Components { + header_to_produce, + gas_price, + transactions_source: WasmTxSource::new(), + coinbase_recipient, + } +} + // It is not used. It was added to make clippy happy. fn main() {} diff --git a/crates/services/upgradable-executor/wasm-executor/src/utils.rs b/crates/services/upgradable-executor/wasm-executor/src/utils.rs index 91355c2e6a5..6069c23a1bf 100644 --- a/crates/services/upgradable-executor/wasm-executor/src/utils.rs +++ b/crates/services/upgradable-executor/wasm-executor/src/utils.rs @@ -1,14 +1,15 @@ -use fuel_core_executor::executor::{ - ExecutionBlockWithSource, - ExecutionOptions, -}; +use fuel_core_executor::executor::ExecutionOptions; use fuel_core_storage::transactional::Changes; -use fuel_core_types::services::{ - executor::{ - ExecutionResult, - Result as ExecutorResult, +use fuel_core_types::{ + blockchain::block::Block, + services::{ + block_producer::Components, + executor::{ + ExecutionResult, + Result as ExecutorResult, + }, + Uncommitted, }, - Uncommitted, }; /// Pack a pointer and length into an `u64`. @@ -46,11 +47,21 @@ pub fn unpack_exists_size_result(val: u64) -> (bool, u32, u16) { #[derive(Debug, serde::Serialize, serde::Deserialize)] pub enum InputType { V1 { - block: ExecutionBlockWithSource<()>, + block: WasmExecutionBlockTypes<()>, options: ExecutionOptions, }, } +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub enum WasmExecutionBlockTypes { + /// DryRun mode where P is being produced. + DryRun(Components), + /// Production mode where P is being produced. + Production(Components), + /// Validation of a produced block. + Validation(Block), +} + /// The return type for the WASM executor. Enum allows handling different /// versions of the return without introducing new host functions. #[derive(Debug, serde::Serialize, serde::Deserialize)] From 1cdc8860ffc2e499c572d81bb7f16ab27d80e6c9 Mon Sep 17 00:00:00 2001 From: Turner Date: Thu, 18 Apr 2024 17:42:53 -0700 Subject: [PATCH 09/13] Refactor and DRY up executor code --- crates/services/executor/src/executor.rs | 238 ++++++++++------------- 1 file changed, 99 insertions(+), 139 deletions(-) diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index a16c5aaf9a7..ce21bf8caa3 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -190,6 +190,23 @@ pub struct ExecutionData { event_inbox_root: Bytes32, } +impl ExecutionData { + pub fn new() -> Self { + ExecutionData { + coinbase: 0, + used_gas: 0, + tx_count: 0, + found_mint: false, + message_ids: Vec::new(), + tx_status: Vec::new(), + events: Vec::new(), + changes: Default::default(), + skipped_transactions: Vec::new(), + event_inbox_root: Default::default(), + } + } +} + /// Per-block execution options #[derive(serde::Serialize, serde::Deserialize, Clone, Default, Debug)] pub struct ExecutionOptions { @@ -503,19 +520,7 @@ where TxSource: TransactionsSource, { let block_gas_limit = self.consensus_params.block_gas_limit(); - let mut data = ExecutionData { - coinbase: 0, - used_gas: 0, - tx_count: 0, - found_mint: false, - message_ids: Vec::new(), - tx_status: Vec::new(), - events: Vec::new(), - changes: Default::default(), - skipped_transactions: Vec::new(), - event_inbox_root: Default::default(), - }; - let execution_data = &mut data; + let mut data = ExecutionData::new(); // Split out the execution kind and partial block. let (execution_kind, component) = block.split(); @@ -526,7 +531,7 @@ where let block_height = *block.header.height(); let forced_transactions = if self.relayer.enabled() { - self.process_da(&block.header, execution_data)? + self.process_da(&block.header, &mut data)? } else { Vec::with_capacity(0) }; @@ -546,47 +551,19 @@ where debug_assert!(block.transactions.is_empty()); - let mut execute_transaction = |execution_data: &mut ExecutionData, - tx: MaybeCheckedTransaction, - gas_price: Word| - -> ExecutorResult<()> { - let tx_count = execution_data.tx_count; - let tx = { - let mut tx_st_transaction = thread_block_transaction - .write_transaction() - .with_policy(ConflictPolicy::Overwrite); - let tx_id = tx.id(&self.consensus_params.chain_id()); - let tx = self.execute_transaction( - tx, - &tx_id, - &block.header, - coinbase_contract_id, - gas_price, - execution_data, - execution_kind, - &mut tx_st_transaction, - )?; - tx_st_transaction.commit()?; - tx - }; - - block.transactions.push(tx); - execution_data.tx_count = tx_count - .checked_add(1) - .ok_or(ExecutorError::TooManyTransactions)?; - - Ok(()) - }; - let relayed_tx_iter = forced_transactions.into_iter(); for transaction in relayed_tx_iter { const RELAYED_GAS_PRICE: Word = 0; let transaction = MaybeCheckedTransaction::CheckedTransaction(transaction); let tx_id = transaction.id(&self.consensus_params.chain_id()); - match execute_transaction( - &mut *execution_data, + match self.foobar( + block, + &mut thread_block_transaction, + &mut data, transaction, RELAYED_GAS_PRICE, + coinbase_contract_id, + execution_kind, ) { Ok(_) => {} Err(err) => { @@ -595,12 +572,12 @@ where block_height, failure: err.to_string(), }; - execution_data.events.push(event); + data.events.push(event); } } } - let remaining_gas_limit = block_gas_limit.saturating_sub(execution_data.used_gas); + let remaining_gas_limit = block_gas_limit.saturating_sub(data.used_gas); // L2 originated transactions should be in the `TxSource`. This will be triggered after // all relayed transactions are processed. @@ -608,11 +585,19 @@ where while regular_tx_iter.peek().is_some() { for transaction in regular_tx_iter { let tx_id = transaction.id(&self.consensus_params.chain_id()); - match execute_transaction(&mut *execution_data, transaction, gas_price) { + match self.foobar( + block, + &mut thread_block_transaction, + &mut data, + transaction, + gas_price, + coinbase_contract_id, + execution_kind, + ) { Ok(_) => {} Err(err) => match execution_kind { ExecutionKind::Production => { - execution_data.skipped_transactions.push((tx_id, err)); + data.skipped_transactions.push((tx_id, err)); } ExecutionKind::DryRun | ExecutionKind::Validation => { return Err(err); @@ -621,8 +606,7 @@ where } } - let new_remaining_gas_limit = - block_gas_limit.saturating_sub(execution_data.used_gas); + let new_remaining_gas_limit = block_gas_limit.saturating_sub(data.used_gas); regular_tx_iter = source.next(new_remaining_gas_limit).into_iter().peekable(); } @@ -630,13 +614,13 @@ where // After the execution of all transactions in production mode, we can set the final fee. if execution_kind == ExecutionKind::Production { let amount_to_mint = if coinbase_contract_id != ContractId::zeroed() { - execution_data.coinbase + data.coinbase } else { 0 }; let coinbase_tx = Transaction::mint( - TxPointer::new(block_height, execution_data.tx_count), + TxPointer::new(block_height, data.tx_count), input::contract::Contract { utxo_id: UtxoId::new(Bytes32::zeroed(), 0), balance_root: Bytes32::zeroed(), @@ -654,10 +638,14 @@ where gas_price, ); - execute_transaction( - execution_data, + self.foobar( + block, + &mut thread_block_transaction, + &mut data, MaybeCheckedTransaction::Transaction(coinbase_tx.into()), gas_price, + coinbase_contract_id, + execution_kind, )?; } @@ -674,38 +662,58 @@ where Ok(data) } + fn foobar( + &self, + block: &mut PartialFuelBlock, + thread_block_transaction: &mut StorageTransaction< + &StorageTransaction<&StorageTransaction>, + >, + execution_data: &mut ExecutionData, + tx: MaybeCheckedTransaction, + gas_price: Word, + coinbase_contract_id: ContractId, + execution_kind: ExecutionKind, + ) -> ExecutorResult<()> { + let tx_count = execution_data.tx_count; + let tx = { + let mut tx_st_transaction = thread_block_transaction + .write_transaction() + .with_policy(ConflictPolicy::Overwrite); + let tx_id = tx.id(&self.consensus_params.chain_id()); + let tx = self.execute_transaction( + tx, + &tx_id, + &block.header, + coinbase_contract_id, + gas_price, + execution_data, + execution_kind, + &mut tx_st_transaction, + )?; + tx_st_transaction.commit()?; + tx + }; + + block.transactions.push(tx); + execution_data.tx_count = tx_count + .checked_add(1) + .ok_or(ExecutorError::TooManyTransactions)?; + + Ok(()) + } + #[tracing::instrument(skip_all)] fn validate_block( mut self, component: PartialBlockComponent, ) -> ExecutorResult { let block_gas_limit = self.consensus_params.block_gas_limit(); - let mut data = ExecutionData { - coinbase: 0, - used_gas: 0, - tx_count: 0, - found_mint: false, - message_ids: Vec::new(), - tx_status: Vec::new(), - events: Vec::new(), - changes: Default::default(), - skipped_transactions: Vec::new(), - event_inbox_root: Default::default(), - }; - let execution_data = &mut data; + let mut data = ExecutionData::new(); - // Split out the execution kind and partial block. let block = component.empty_block; let source = component.transactions_source; let gas_price = component.gas_price; let coinbase_contract_id = component.coinbase_contract_id; - let block_height = *block.header.height(); - - let forced_transactions = if self.relayer.enabled() { - self.process_da(&block.header, execution_data)? - } else { - Vec::with_capacity(0) - }; // The block level storage transaction that also contains data from the relayer. // Starting from this point, modifications from each thread should be independent @@ -722,72 +730,24 @@ where debug_assert!(block.transactions.is_empty()); - let mut execute_transaction = |execution_data: &mut ExecutionData, - tx: MaybeCheckedTransaction, - gas_price: Word| - -> ExecutorResult<()> { - let tx_count = execution_data.tx_count; - let tx = { - let mut tx_st_transaction = thread_block_transaction - .write_transaction() - .with_policy(ConflictPolicy::Overwrite); - let tx_id = tx.id(&self.consensus_params.chain_id()); - let tx = self.execute_transaction( - tx, - &tx_id, - &block.header, - coinbase_contract_id, - gas_price, - execution_data, - ExecutionKind::Validation, - &mut tx_st_transaction, - )?; - tx_st_transaction.commit()?; - tx - }; - - block.transactions.push(tx); - execution_data.tx_count = tx_count - .checked_add(1) - .ok_or(ExecutorError::TooManyTransactions)?; - - Ok(()) - }; - - let relayed_tx_iter = forced_transactions.into_iter(); - for transaction in relayed_tx_iter { - const RELAYED_GAS_PRICE: Word = 0; - let transaction = MaybeCheckedTransaction::CheckedTransaction(transaction); - let tx_id = transaction.id(&self.consensus_params.chain_id()); - match execute_transaction( - &mut *execution_data, - transaction, - RELAYED_GAS_PRICE, - ) { - Ok(_) => {} - Err(err) => { - let event = ExecutorEvent::ForcedTransactionFailed { - id: tx_id.into(), - block_height, - failure: err.to_string(), - }; - execution_data.events.push(event); - } - } - } - - let remaining_gas_limit = block_gas_limit.saturating_sub(execution_data.used_gas); - + let execution_kind = ExecutionKind::Validation; // L2 originated transactions should be in the `TxSource`. This will be triggered after // all relayed transactions are processed. - let mut regular_tx_iter = source.next(remaining_gas_limit).into_iter().peekable(); + let mut regular_tx_iter = source.next(block_gas_limit).into_iter().peekable(); while regular_tx_iter.peek().is_some() { for transaction in regular_tx_iter { - execute_transaction(&mut *execution_data, transaction, gas_price)?; + self.foobar( + block, + &mut thread_block_transaction, + &mut data, + transaction, + gas_price, + coinbase_contract_id, + execution_kind, + )?; } - let new_remaining_gas_limit = - block_gas_limit.saturating_sub(execution_data.used_gas); + let new_remaining_gas_limit = block_gas_limit.saturating_sub(data.used_gas); regular_tx_iter = source.next(new_remaining_gas_limit).into_iter().peekable(); } From 28a611807875f81e3ade6ef1ff5ceaee672c8c94 Mon Sep 17 00:00:00 2001 From: Turner Date: Thu, 18 Apr 2024 18:37:33 -0700 Subject: [PATCH 10/13] Appease Clippy-sama --- crates/services/executor/src/executor.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index ce21bf8caa3..fb2c5c85c80 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -556,7 +556,7 @@ where const RELAYED_GAS_PRICE: Word = 0; let transaction = MaybeCheckedTransaction::CheckedTransaction(transaction); let tx_id = transaction.id(&self.consensus_params.chain_id()); - match self.foobar( + match self.execute_transaction_and_commit( block, &mut thread_block_transaction, &mut data, @@ -585,7 +585,7 @@ where while regular_tx_iter.peek().is_some() { for transaction in regular_tx_iter { let tx_id = transaction.id(&self.consensus_params.chain_id()); - match self.foobar( + match self.execute_transaction_and_commit( block, &mut thread_block_transaction, &mut data, @@ -638,7 +638,7 @@ where gas_price, ); - self.foobar( + self.execute_transaction_and_commit( block, &mut thread_block_transaction, &mut data, @@ -662,7 +662,9 @@ where Ok(data) } - fn foobar( + // TODO: Refactor this function to reduce the number of arguments. + #[allow(clippy::too_many_arguments)] + fn execute_transaction_and_commit( &self, block: &mut PartialFuelBlock, thread_block_transaction: &mut StorageTransaction< @@ -736,7 +738,7 @@ where let mut regular_tx_iter = source.next(block_gas_limit).into_iter().peekable(); while regular_tx_iter.peek().is_some() { for transaction in regular_tx_iter { - self.foobar( + self.execute_transaction_and_commit( block, &mut thread_block_transaction, &mut data, From fbfa9de4afd0b55c311b6e6437beec845b069536 Mon Sep 17 00:00:00 2001 From: Turner Date: Thu, 18 Apr 2024 19:01:14 -0700 Subject: [PATCH 11/13] Replace relayed tx stuff --- crates/services/executor/src/executor.rs | 35 +++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index fb2c5c85c80..49b49d4a8b3 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -716,6 +716,14 @@ where let source = component.transactions_source; let gas_price = component.gas_price; let coinbase_contract_id = component.coinbase_contract_id; + let block_height = *block.header.height(); + let execution_kind = ExecutionKind::Validation; + + let forced_transactions = if self.relayer.enabled() { + self.process_da(&block.header, &mut data)? + } else { + Vec::with_capacity(0) + }; // The block level storage transaction that also contains data from the relayer. // Starting from this point, modifications from each thread should be independent @@ -732,7 +740,32 @@ where debug_assert!(block.transactions.is_empty()); - let execution_kind = ExecutionKind::Validation; + let relayed_tx_iter = forced_transactions.into_iter(); + for transaction in relayed_tx_iter { + const RELAYED_GAS_PRICE: Word = 0; + let transaction = MaybeCheckedTransaction::CheckedTransaction(transaction); + let tx_id = transaction.id(&self.consensus_params.chain_id()); + match self.execute_transaction_and_commit( + block, + &mut thread_block_transaction, + &mut data, + transaction, + RELAYED_GAS_PRICE, + coinbase_contract_id, + execution_kind, + ) { + Ok(_) => {} + Err(err) => { + let event = ExecutorEvent::ForcedTransactionFailed { + id: tx_id.into(), + block_height, + failure: err.to_string(), + }; + data.events.push(event); + } + } + } + // L2 originated transactions should be in the `TxSource`. This will be triggered after // all relayed transactions are processed. let mut regular_tx_iter = source.next(block_gas_limit).into_iter().peekable(); From aad5b63fd97999869e0e98298f08f67ec8154f57 Mon Sep 17 00:00:00 2001 From: Mitchell Turner Date: Fri, 19 Apr 2024 16:39:16 -0700 Subject: [PATCH 12/13] Update CHANGELOG.md --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 186627d2453..3310a972fab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ Description of the upcoming release here. - [#1844](https://github.com/FuelLabs/fuel-core/pull/1844): Fixed the publishing of the `fuel-core 0.25.1` release. - [1842](https://github.com/FuelLabs/fuel-core/pull/1842): Ignore RUSTSEC-2024-0336: `rustls::ConnectionCommon::complete_io` could fall into an infinite loop based on network +### Changed + +- [#1837](https://github.com/FuelLabs/fuel-core/pull/1837): Refactor the executor and separate validation from the other use cases + ## [Version 0.25.1] ### Fixed @@ -36,7 +40,6 @@ Description of the upcoming release here. ### Changed -- [#1837](https://github.com/FuelLabs/fuel-core/pull/1837): Refactor the executor and separate validation from the other use cases - [#1833](https://github.com/FuelLabs/fuel-core/pull/1833): Regenesis of `SpentMessages` and `ProcessedTransactions`. - [#1830](https://github.com/FuelLabs/fuel-core/pull/1830): Use versioning enum for WASM executor input and output. - [#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. From 2639ba63b0f97aeea93ef2109bfa66559216d4be Mon Sep 17 00:00:00 2001 From: Turner Date: Mon, 22 Apr 2024 08:32:38 -0700 Subject: [PATCH 13/13] Cleanup, make suggested changes from PR review --- CHANGELOG.md | 5 ++ .../src/service/adapters/block_importer.rs | 2 +- .../src/service/adapters/executor.rs | 54 ++----------------- .../src/service/adapters/producer.rs | 28 +++++----- crates/services/executor/src/executor.rs | 8 +-- .../upgradable-executor/src/executor.rs | 4 +- .../wasm-executor/src/main.rs | 40 +------------- crates/types/src/services/executor.rs | 11 ---- 8 files changed, 32 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d88a58d7597..05603d8d08e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Description of the upcoming release here. +### Changed + +- [#1837](https://github.com/FuelLabs/fuel-core/pull/1837): Refactor the executor and separate validation from the other use cases + ## [Version 0.25.2] ### Fixed @@ -42,6 +46,7 @@ Description of the upcoming release here. ### Changed +- [#1837](https://github.com/FuelLabs/fuel-core/pull/1837): Refactor the executor and separate validation from the other use cases - [#1833](https://github.com/FuelLabs/fuel-core/pull/1833): Regenesis of `SpentMessages` and `ProcessedTransactions`. - [#1830](https://github.com/FuelLabs/fuel-core/pull/1830): Use versioning enum for WASM executor input and output. - [#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. diff --git a/crates/fuel-core/src/service/adapters/block_importer.rs b/crates/fuel-core/src/service/adapters/block_importer.rs index 12a2ad57192..e6bcf8b9fbe 100644 --- a/crates/fuel-core/src/service/adapters/block_importer.rs +++ b/crates/fuel-core/src/service/adapters/block_importer.rs @@ -105,6 +105,6 @@ impl Validator for ExecutorAdapter { &self, block: Block, ) -> ExecutorResult> { - self._validate_block(block) + self.executor.validate(block) } } diff --git a/crates/fuel-core/src/service/adapters/executor.rs b/crates/fuel-core/src/service/adapters/executor.rs index 815325b439c..10218c4e4ac 100644 --- a/crates/fuel-core/src/service/adapters/executor.rs +++ b/crates/fuel-core/src/service/adapters/executor.rs @@ -3,31 +3,12 @@ use crate::{ database_description::relayer::Relayer, Database, }, - service::adapters::{ - ExecutorAdapter, - TransactionsSource, - }, -}; -use fuel_core_executor::{ - executor::ExecutionBlockWithSource, - ports::MaybeCheckedTransaction, + service::adapters::TransactionsSource, }; -use fuel_core_storage::transactional::Changes; +use fuel_core_executor::ports::MaybeCheckedTransaction; use fuel_core_types::{ - blockchain::{ - block::Block, - primitives::DaBlockHeight, - }, - fuel_tx, - services::{ - block_producer::Components, - executor::{ - Result as ExecutorResult, - TransactionExecutionStatus, - UncommittedResult, - }, - relayer::Event, - }, + blockchain::primitives::DaBlockHeight, + services::relayer::Event, }; impl fuel_core_executor::ports::TransactionsSource for TransactionsSource { @@ -40,33 +21,6 @@ impl fuel_core_executor::ports::TransactionsSource for TransactionsSource { } } -impl ExecutorAdapter { - pub(crate) fn _execute_without_commit( - &self, - block: ExecutionBlockWithSource, - ) -> ExecutorResult> - where - TxSource: fuel_core_executor::ports::TransactionsSource + Send + Sync + 'static, - { - self.executor.execute_without_commit_with_source(block) - } - - pub(crate) fn _dry_run( - &self, - block: Components>, - utxo_validation: Option, - ) -> ExecutorResult> { - self.executor.dry_run(block, utxo_validation) - } - - pub(crate) fn _validate_block( - &self, - block: Block, - ) -> ExecutorResult> { - self.executor.validate(block) - } -} - impl fuel_core_executor::ports::RelayerPort for Database { fn enabled(&self) -> bool { #[cfg(feature = "relayer")] diff --git a/crates/fuel-core/src/service/adapters/producer.rs b/crates/fuel-core/src/service/adapters/producer.rs index add8752869b..cdccedd254a 100644 --- a/crates/fuel-core/src/service/adapters/producer.rs +++ b/crates/fuel-core/src/service/adapters/producer.rs @@ -92,7 +92,8 @@ impl fuel_core_producer::ports::Executor for ExecutorAdapter &self, component: Components, ) -> ExecutorResult> { - self._execute_without_commit(ExecutionTypes::Production(component)) + self.executor + .execute_without_commit_with_source(ExecutionTypes::Production(component)) } } @@ -101,18 +102,17 @@ impl fuel_core_producer::ports::Executor> for ExecutorAdapter { &self, component: Components>, ) -> ExecutorResult> { - let Components { - header_to_produce, - transactions_source, - gas_price, - coinbase_recipient, - } = component; - self._execute_without_commit(ExecutionTypes::Production(Components { - header_to_produce, - transactions_source: OnceTransactionsSource::new(transactions_source), - gas_price, - coinbase_recipient, - })) + let new_components = Components { + header_to_produce: component.header_to_produce, + transactions_source: OnceTransactionsSource::new( + component.transactions_source, + ), + gas_price: component.gas_price, + coinbase_recipient: component.coinbase_recipient, + }; + let block = ExecutionTypes::Production(new_components); + + self.executor.execute_without_commit_with_source(block) } } @@ -122,7 +122,7 @@ impl fuel_core_producer::ports::DryRunner for ExecutorAdapter { block: Components>, utxo_validation: Option, ) -> ExecutorResult> { - self._dry_run(block, utxo_validation) + self.executor.dry_run(block, utxo_validation) } } diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index 49b49d4a8b3..56e292537c8 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -664,12 +664,12 @@ where // TODO: Refactor this function to reduce the number of arguments. #[allow(clippy::too_many_arguments)] - fn execute_transaction_and_commit( + fn execute_transaction_and_commit< + W: WriteTransaction + KeyValueInspect + Modifiable, + >( &self, block: &mut PartialFuelBlock, - thread_block_transaction: &mut StorageTransaction< - &StorageTransaction<&StorageTransaction>, - >, + thread_block_transaction: &mut W, execution_data: &mut ExecutionData, tx: MaybeCheckedTransaction, gas_price: Word, diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 8efec4c65c8..fa1e48d230c 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -209,9 +209,9 @@ where /// Executes the block and commits the result of the execution into the inner `Database`. pub fn validate_and_commit( &mut self, - _block: Block, + block: Block, ) -> fuel_core_types::services::executor::Result { - let (result, changes) = self.validate_without_commit(_block)?.into(); + let (result, changes) = self.validate_without_commit(block)?.into(); self.storage_view_provider.commit_changes(changes)?; Ok(result) diff --git a/crates/services/upgradable-executor/wasm-executor/src/main.rs b/crates/services/upgradable-executor/wasm-executor/src/main.rs index e7fa0c99ac2..c349bc7a824 100644 --- a/crates/services/upgradable-executor/wasm-executor/src/main.rs +++ b/crates/services/upgradable-executor/wasm-executor/src/main.rs @@ -103,25 +103,7 @@ fn execute_dry_run( block: Components, ) -> ExecutorResult> { let block = ExecutionBlockWithSource::DryRun(block); - let ( - ExecutionResult { - block, - skipped_transactions, - tx_status, - events, - }, - changes, - ) = instance.execute_without_commit(block)?.into(); - - Ok(Uncommitted::new( - ExecutionResult { - block, - skipped_transactions, - tx_status, - events, - }, - changes, - )) + instance.execute_without_commit(block) } fn execute_production( @@ -129,25 +111,7 @@ fn execute_production( block: Components, ) -> ExecutorResult> { let block = ExecutionBlockWithSource::Production(block); - let ( - ExecutionResult { - block, - skipped_transactions, - tx_status, - events, - }, - changes, - ) = instance.execute_without_commit(block)?.into(); - - Ok(Uncommitted::new( - ExecutionResult { - block, - skipped_transactions, - tx_status, - events, - }, - changes, - )) + instance.execute_without_commit(block) } fn execute_validation( diff --git a/crates/types/src/services/executor.rs b/crates/types/src/services/executor.rs index 2287a2b84fb..4c89943bdb6 100644 --- a/crates/types/src/services/executor.rs +++ b/crates/types/src/services/executor.rs @@ -305,17 +305,6 @@ pub enum ExecutionKind { Validation, } -impl ExecutionKind { - /// Wrap a type in this execution kind. - pub fn wrap(self, t: T) -> ExecutionType { - match self { - ExecutionKind::DryRun => ExecutionTypes::DryRun(t), - ExecutionKind::Production => ExecutionTypes::Production(t), - ExecutionKind::Validation => todo!("remove this variant"), - } - } -} - #[allow(missing_docs)] #[derive(Debug, Clone, PartialEq, derive_more::Display, derive_more::From)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]