The Core Execution Engine processes transactions and manages state transitions in the Fuel blockchain. It consists of two primary components:
Executor<S, R>) - Routes execution to native or WASM implementations based on the block's state transition function (STF) versionExecutionInstance<R, D, M>) - Performs the actual transaction execution using the Fuel VMThe engine handles three execution modes:
Related documentation:
The execution engine is structured around two primary executor types: the Executor (upgradable) and ExecutionInstance (per-execution). The upgradable executor determines which state transition function (STF) version to use, while the execution instance performs the actual block and transaction execution.
Sources: crates/services/upgradable-executor/src/executor.rs142-164 crates/services/executor/src/executor.rs379-384
The Executor<S, R> struct provides version-aware block execution. It maintains three separate memory pools for reuse across executions and determines whether to use native or WASM execution based on the block's STF version.
| Field | Type | Purpose |
|---|---|---|
storage_view_provider | S | Provides historical and latest views of blockchain state |
relayer_view_provider | R | Provides access to relayer events from DA layer |
config | Arc<Config> | Execution configuration including validation rules |
produce_block_pool | MemoryPool | Reusable VM memory for block production (1 instance max) |
validate_block_pool | MemoryPool | Reusable VM memory for block validation (1 instance max) |
dry_run_pool | MemoryPool | Reusable VM memory for dry run executions (unlimited) |
engine | wasmtime::Engine | WASM runtime engine (feature: wasm-executor) |
execution_strategy | ExecutionStrategy | Native or WASM execution choice (feature: wasm-executor) |
cached_modules | Mutex<HashMap<..>> | Cache of compiled WASM modules by version (feature: wasm-executor) |
Sources: crates/services/upgradable-executor/src/executor.rs142-164
The ExecutionInstance<R, D, M> performs the actual execution work. It's created per block execution and manages transaction processing, state changes, and receipt generation.
| Field | Type | Purpose |
|---|---|---|
relayer | R | RelayerPort implementation for DA events |
database | D | KeyValueInspect database for state access |
options | ExecutionOptions | Per-block execution options |
memory | M | Pre-allocated VM memory instance |
Sources: crates/services/executor/src/executor.rs379-384
Execution behavior is controlled through ExecutionOptions:
Sources: crates/services/executor/src/executor.rs357-364
Block production follows a pipeline where transactions are selected, executed, and packaged into a block with a coinbase transaction. The process supports preconfirmations, allowing transaction status updates before block finalization.
Diagram: Block Production Flow
Sources: crates/services/upgradable-executor/src/executor.rs439-473 crates/services/executor/src/executor.rs401-562 crates/services/executor/src/executor.rs269-319
Validation re-executes a sealed block to verify correctness. Unlike production, validation must match the block's transactions, receipts, and state transitions exactly.
Diagram: Block Validation Flow
Sources: crates/services/upgradable-executor/src/executor.rs545-551 crates/services/executor/src/executor.rs564-718 crates/services/executor/src/executor.rs720-1050
The executor determines execution strategy based on the block's state_transition_bytecode_version:
Sources: crates/services/upgradable-executor/src/executor.rs623-686 crates/services/upgradable-executor/src/executor.rs203-211
The current native executor version is defined as:
| Constant | Value | Description |
|---|---|---|
Executor::VERSION | 32 | Current native executor version (LATEST_STATE_TRANSITION_VERSION) |
genesis_state_transition_version | 32 | Version specified in chain config for genesis block |
StateTransitionBytecodeVersion::MIN | 0 | First STF version (0.26.0) |
The Executor::CRATE_VERSIONS constant maps each fuel-core release to its STF version:
Note: Version 25 (0.41.10) replaced the unreleased 0.42.0 on mainnet. This is acceptable because networks can skip versions by upgrading to the old state transition function.
Sources: crates/services/upgradable-executor/src/executor.rs208-267 bin/fuel-core/chainspec/local-testnet/chain_config.json308 crates/types/src/blockchain/header.rs36
Sources: crates/services/executor/src/executor.rs823-1025
The executor produces different result types based on execution outcome:
| Result Enum | Success Case | Failure Case | Contains |
|---|---|---|---|
TransactionExecutionResult::Success | ProgramState::Return, ReturnData | - | total_gas, total_fee, receipts: Arc<[Receipt]> |
TransactionExecutionResult::Failed | - | ProgramState::Revert, validation errors | Same fields, plus result: Option<ProgramState> |
Both variants include:
total_gas: u64 - Gas consumed including VM initializationtotal_fee: u64 - Fee charged based on gas price and gas consumedreceipts: Arc<[Receipt]> - Execution receipts (wrapped in Arc to avoid cloning)The Failed variant additionally includes the VM's final state for debugging.
Sources: crates/types/src/services/executor.rs187-247
During block execution, the ExecutionData struct accumulates state changes and metadata:
| Field | Type | Purpose |
|---|---|---|
coinbase | u64 | Total fees collected for the block producer |
used_gas | u64 | Cumulative gas consumed by all transactions |
used_size | u32 | Total transaction size in bytes |
tx_count | u16 | Number of transactions executed (max 65,535) |
found_mint | bool | Whether a Mint transaction was found (validation only) |
message_ids | Vec<MessageId> | IDs of messages consumed from relayer |
tx_status | Vec<TransactionExecutionStatus> | Success/failure status per transaction |
events | Vec<ExecutorEvent> | Coin/message lifecycle events |
changes | Changes | Storage changes to commit atomically |
skipped_transactions | Vec<(TxId, ExecutorError)> | Transactions excluded from block |
event_inbox_root | Bytes32 | Merkle root of relayer events consumed |
The ExecutionData::new() constructor initializes all fields to default values. During execution, fields are incrementally updated as transactions are processed.
Sources: crates/services/executor/src/executor.rs322-353
The executor maintains separate memory pools to avoid allocation overhead:
Memory instances are borrowed from the appropriate pool before execution and returned after completion. This design ensures:
Sources: crates/services/upgradable-executor/src/executor.rs147-155 crates/services/executor/src/executor.rs394-399
Used for creating new blocks:
TransactionsSourceExecutionResult with skipped_transactionsSources: crates/services/executor/src/executor.rs401-562
Used for verifying imported blocks:
ValidationResult without skipped transactionsSources: crates/services/executor/src/executor.rs564-718
Used for transaction simulation:
forbid_fake_coins)Sources: crates/services/upgradable-executor/src/executor.rs477-543
The ExecutorAdapter bridges the upgradable executor with the rest of the system:
Sources: crates/fuel-core/src/service/adapters/executor.rs1-87 crates/fuel-core/src/service/adapters/block_importer.rs119-153
The executor receives transactions through the TransactionsSource trait:
| Implementation | Usage | Source |
|---|---|---|
OnceTransactionsSource | Wraps a fixed list of transactions | crates/services/executor/src/executor.rs205-241 |
TransactionsSource (adapter) | Pulls from TxPool with constraints | crates/fuel-core/src/service/adapters/executor.rs32-56 |
Execution produces uncommitted results that bundle outcomes with storage changes:
The Uncommitted<Result, Changes> wrapper separates execution results from storage modifications:
| Component | Purpose |
|---|---|
result: Result | Execution outcomes (block, transaction statuses, events) |
changes: Changes | Storage modifications (state transitions, UTXO updates) |
This design enables:
commit_changes()The importer uses this pattern to verify blocks before committing them to the database.
Sources: crates/types/src/services/executor.rs49-72 crates/services/importer/src/importer.rs69-90 fuel_core_storage/src/transactional.rs
Execution generates events for state changes:
| Event | Meaning |
|---|---|
MessageImported | DA layer message available for consumption |
MessageConsumed | Transaction consumed a message |
CoinCreated | Transaction output created a spendable coin |
CoinConsumed | Transaction input spent a coin |
ForcedTransactionFailed | Relayed transaction couldn't be included |
Refresh this wiki