1. Quick Start
Fuel Core is the official Rust implementation of the Fuel protocol — a high-performance, UTXO-based blockchain execution layer designed for modular blockchain architectures. It runs the FuelVM, a purpose-built virtual machine optimized for parallel transaction execution with a fraud-provable design.
Key features:
- UTXO-based transaction model enabling parallel execution
- FuelVM execution environment with native multi-asset support
- GraphQL API for querying blockchain state and submitting transactions
- Peer-to-peer networking via libp2p for block and transaction propagation
- Proof-of-Authority (PoA) consensus with configurable block production triggers
- Ethereum L1 relayer for cross-chain message bridging
- RocksDB-backed persistent storage with historical state access
- WASM-based upgradable executor for forkless protocol upgrades
Prerequisites: Rust 1.93.0+, clang/llvm (for RocksDB), and a chain configuration snapshot.
Fastest way to start a local node:
cargo run -p fuel-core-bin -- run --db-type in-memory
GraphQL API listening on 127.0.0.1:4000
Tip
For quick experimentation, use
--db-type in-memoryto skip RocksDB setup entirely. State is lost on restart but startup is instant.
What to try next: Query the node health at http://127.0.0.1:4000/v1/playground using the built-in GraphiQL interface, or submit a transaction via the fuel-core-client crate.
2. Installation
System Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Rust toolchain | 1.93.0 | Latest stable |
| OS | Linux, macOS, Windows | Linux (Ubuntu 22.04+) |
| RAM | 4 GB | 16 GB+ (production) |
| Disk | 10 GB | 100 GB+ SSD (production with RocksDB) |
| CPU | 2 cores | 4+ cores |
Building from Source
git clone https://github.com/FuelLabs/fuel-core.git
cd fuel-core
cargo build -p fuel-core-bin --release
Compiling fuel-core-bin v0.48.0
Finished release [optimized] target(s)
Important
The default build includes RocksDB support, which requires
clangandllvmdevelopment libraries. On Ubuntu:apt install clang llvm libclang-dev. On macOS:xcode-select --install.
Production Build
For production deployments, enable jemalloc for improved memory performance:
cargo build -p fuel-core-bin --release --features rocksdb-production
Feature Flags
| Feature | Description | Default |
|---|---|---|
rocksdb |
RocksDB persistent storage | Yes |
rocksdb-production |
RocksDB with jemalloc allocator | No |
p2p |
Peer-to-peer networking via libp2p | No |
relayer |
Ethereum L1 relayer for bridge messages | No |
wasm-executor |
WASM upgradable executor | No |
rpc |
Block aggregator RPC/gRPC API | No |
shared-sequencer |
Shared sequencer integration (Cosmos SDK) | No |
Post-Install Verification
./target/release/fuel-core --version
fuel-core 0.48.0
./target/release/fuel-core run --db-type in-memory &
curl -s http://127.0.0.1:4000/v1/health
true
Warning
If building on ARM (aarch64), use the provided cross-compilation Dockerfiles in
ci/Dockerfile.aarch64-unknown-linux-gnu-clangfor reproducible builds.
Key Generation
Generate cryptographic keys for block production or P2P peering:
./target/release/fuel-core-keygen new --key-type block-production
{
"secret": "0x...",
"address": "0x...",
"type": "block-production"
}
./target/release/fuel-core-keygen new --key-type peering
{
"secret": "0x...",
"peer_id": "16Uiu2HAm...",
"type": "p2p"
}
Caution
Store generated secret keys securely. The block production key controls consensus authority. Never commit secrets to version control.
Derive Address from Existing Secret
./target/release/fuel-core-keygen parse --key-type block-production --secret 0xYOUR_SECRET_KEY
{
"address": "0x...",
"type": "block-production"
}
3. Configuration
Fuel Core uses a chain configuration snapshot for genesis state and consensus parameters. The node is configured primarily through CLI flags.
Chain Configuration
The chain configuration defines the genesis state and consensus rules. It consists of:
| File | Purpose |
|---|---|
chain_config.json |
Chain name, consensus parameters, state transition bytecode, consensus type (PoA/PoAV2) |
state_config.json |
Genesis coins, contracts, messages, blobs |
metadata.json |
Chain height, DA height metadata |
Consensus Modes
| Mode | CLI Value | Behavior |
|---|---|---|
| Instant | instant |
Produce a block as soon as transactions arrive (development) |
| Interval | interval { block_time } |
Produce blocks at fixed time intervals (production) |
| Never | N/A | Passive listener — does not produce blocks (follower node) |
Essential CLI Flags
| Flag | Type | Description |
|---|---|---|
--db-type |
rocks-db | in-memory |
Storage backend |
--db-path |
Path | RocksDB database directory |
--ip |
Address | GraphQL API bind address (default: 127.0.0.1) |
--port |
u16 | GraphQL API port (default: 4000) |
--snapshot |
Path | Path to chain configuration snapshot directory |
--utxo-validation |
bool | Enable UTXO existence validation |
--debug |
bool | Enable debug endpoints (VM debugger) |
Note
For full configuration reference including P2P, relayer, gas price, GraphQL tuning, and advanced settings, see the Admin Guide.
Minimal Local Development Configuration
fuel-core run \
--db-type in-memory \
--debug \
--snapshot ./path/to/chain-config
Connecting to an Existing Network
To sync with an existing Fuel network, you need the network's chain configuration snapshot and at least one bootstrap peer:
fuel-core run \
--db-type rocks-db \
--db-path /data/fuel-core \
--snapshot ./chain-config \
--keypair $P2P_SECRET \
--reserved-nodes /dns4/bootstrap.fuel.network/tcp/30333/p2p/$PEER_ID
Tip
Use
--reserved-nodesto specify bootstrap peers. The node discovers additional peers through the Kademlia DHT once connected.
4. Core Usage
Interacting via GraphQL
Fuel Core exposes a GraphQL API as its primary interface. Access the GraphiQL playground at http://<host>:<port>/v1/playground.
Check Node Health
query {
health
}
{
"data": {
"health": true
}
}
Query Node Information
query {
nodeInfo {
utxoValidation
vmBacktrace
maxTx
maxDepth
nodeVersion
peers {
id
blockHeight
}
}
}
Query Chain Information
query {
chain {
name
latestBlock {
header {
height
time
}
}
consensusParameters {
version
}
}
}
Submit a Transaction
mutation {
submit(tx: "0x...hex-encoded-transaction...") {
id
}
}
Warning
When
--utxo-validationis enabled, the node validates that all input UTXOs exist and are unspent before accepting a transaction. Transactions referencing consumed UTXOs are rejected.
Query Transaction Status
query {
transaction(id: "0x...tx_id...") {
status {
... on SuccessStatus {
blockHeight
}
... on FailureStatus {
reason
}
... on SubmittedStatus {
time
}
}
}
}
Subscribe to Transaction Status Changes
subscription {
statusChange(id: "0x...tx_id...") {
... on SubmittedStatus { time }
... on SuccessStatus { blockHeight }
... on FailureStatus { reason }
}
}
Note
Subscriptions use Server-Sent Events (SSE). The
fuel-core-clientcrate handles reconnection automatically when using thesubscriptionsfeature.
Query Account Balance
query {
balance(owner: "0x...address...", assetId: "0x...asset_id...") {
amount
}
}
List Coins (UTXOs)
query {
coins(filter: { owner: "0x...address..." }, first: 10) {
nodes {
utxoId
amount
assetId
}
}
}
Using the Rust Client
The fuel-core-client crate provides a typed Rust client for the GraphQL API:
use fuel_core_client::client::FuelClient;
let client = FuelClient::new("http://127.0.0.1:4000").unwrap();
let health = client.health().await.unwrap();
assert!(health);
The client supports pagination via cursor-based ConnectionArgs with first/after (forward) or last/before (backward) parameters.
VM Debugger (Debug Mode)
When running with --debug, interactive VM debugging is available via GraphQL mutations:
-
Start a debug session:
mutation { startSession } -
Load and execute a transaction:
mutation { startTx(id: $sessionId, txJson: "...") { breakpoint jsonReceipts } } -
Set breakpoints on a contract:
mutation { setBreakpoint(id: $sessionId, breakpoint: { contract: "0x...", pc: 10 }) } -
Step through execution:
mutation { setSingleStepping(id: $sessionId, enable: true) } mutation { continueTx(id: $sessionId) { breakpoint jsonReceipts } } -
Inspect VM state:
query { register(id: $sessionId, register: 16) } query { memory(id: $sessionId, start: 0, size: 256) } -
End session:
mutation { endSession(id: $sessionId) }
Caution
Debug mode exposes full VM state inspection. Never enable
--debugon production nodes — it allows arbitrary transaction execution replay and memory inspection.
5. Common Tasks
Run a Local Development Node
Goal: Start a local node for smart contract development.
Steps:
- Build fuel-core with default features
- Start the node:
fuel-core run \ --db-type in-memory \ --debug \ --utxo-validation
Verify: Query http://127.0.0.1:4000/v1/health returns true.
Run a Persistent Node
Goal: Run a node with data that survives restarts.
Steps:
- Create a data directory:
mkdir -p /var/lib/fuel-core/db - Start the node:
fuel-core run \ --db-type rocks-db \ --db-path /var/lib/fuel-core/db \ --snapshot /etc/fuel-core/chain-config
Verify: Check that /var/lib/fuel-core/db contains RocksDB files after the first block.
If it fails: Ensure the --db-path directory exists and is writable. Check that the chain configuration snapshot at --snapshot contains valid chain_config.json and state_config.json.
Query Gas Price
Goal: Get the current gas price for transaction fee estimation.
query {
latestGasPrice {
gasPrice
blockHeight
}
}
To estimate gas price at a future block:
query {
estimateGasPrice(blockHorizon: 10) {
gasPrice
}
}
Dry-Run a Transaction
Goal: Simulate a transaction without committing it to the chain.
mutation {
dryRun(tx: "0x...hex-encoded-tx...", utxoValidation: true) {
... on SuccessStatus {
totalGas
totalFee
}
receipts {
receiptType
data
}
}
}
Tip
Use dry-run to estimate gas costs before submitting. The
utxoValidationparameter can be set independently of the node's global--utxo-validationflag.
Query Block Details
query {
block(height: "100") {
header {
height
time
daHeight
transactionsCount
}
transactions {
id
}
}
}
Query Cross-Chain Messages
query {
messages(owner: "0x...address...", first: 10) {
nodes {
sender
recipient
amount
data
daHeight
}
}
}
Query Contract State
query {
contract(id: "0x...contract_id...") {
bytecode
salt
}
}
Query DA Compressed Blocks
When the compression service is active, retrieve DA-compressed block data:
query {
daCompressedBlock(height: "100") {
bytes
}
}
Run Benchmarks
Goal: Generate gas cost data for the FuelVM.
Steps:
- Run benchmarks:
cargo bench -p fuel-core-benches - Collect gas cost output:
cargo criterion -p fuel-core-benches --message-format json --bench vm > bench.json cargo run -p fuel-core-benches --bin collect --release -- --input bench.json
Generated gas-costs.yaml
Note
Benchmarks require the
rocksdbandrocksdb-productionfeatures enabled (default). Seebenches/README.mdfor profiling with flamegraphs.
6. Troubleshooting
Diagnostic Decision Tree
Node won't start?
├── Missing chain config? → Provide --snapshot path
├── RocksDB error? → Check --db-path permissions and disk space
├── Port in use? → Change --port or stop conflicting process
└── Version mismatch? → Ensure chain config matches fuel-core version
Transactions rejected?
├── UTXO not found? → UTXO was already spent or doesn't exist
├── Gas too low? → Query latestGasPrice and increase max_fee
├── Blacklisted? → Input address/UTXO/contract is blacklisted in txpool
├── Pool full? → Pool limits reached; retry with higher tip
└── Mint disallowed? → Only coinbase transactions can use Mint type
Node not syncing?
├── No peers? → Check --reserved-nodes and P2P port accessibility
├── Wrong chain? → Ensure chain config checksum matches network
└── Relayer behind? → Wait for Ethereum finality (~13 min)
Error: Failed to create FuelClient. No URL is provided.
Cause: The FuelClient was constructed without specifying a URL.
Solution:
let client = FuelClient::new("http://127.0.0.1:4000").unwrap();
Prevention: Always pass the GraphQL endpoint URL when constructing FuelClient.
Error: unable to produce blocks without a consensus key
Cause: The node is configured for block production (instant or interval trigger) but no signing key was provided.
Solution:
- Generate a key:
fuel-core-keygen new --key-type block-production - Pass it via the
--consensus-keyCLI flag
Prevention: Always configure a consensus key when using block production triggers.
Error: Block production timed out
Cause: Block production exceeded the configured timeout, typically due to slow transaction execution or database I/O.
Solution:
- Check disk I/O performance
- Reduce the number of transactions per block
- Verify the gas limit is not set excessively high
Error: Maximum number of subscriptions reached
Cause: The transaction status manager has reached its subscription limit.
Solution:
- Close unused subscriptions
- Increase the subscription limit in node configuration
Prevention: Clean up subscription handles in client code after receiving terminal status updates (Success or Failure).
Error: Database doesn't have a height to rollback
Cause: Attempted to roll back the database to a height that doesn't exist in the history.
Solution:
- Check the current database height via GraphQL
- Only roll back to heights within the available history window
Error: InvalidDatabaseVersion { expected, found }
Cause: The database was created with an incompatible version of fuel-core.
Solution:
- Back up the existing database
- Re-sync from genesis with the correct fuel-core version
Prevention: Always use matching fuel-core versions with existing databases. Protocol upgrades use the WASM executor for forkless transitions.
Warning
Database version mismatches cannot be resolved by simply upgrading the binary. A re-sync from the chain configuration snapshot is required.
Error: The block timestamp should monotonically increase
Cause: Attempted to produce a block with a timestamp earlier than or equal to the previous block.
Solution: Ensure system clock is synchronized and not drifting backward. Use NTP on production nodes.
Prevention: Run ntpd or chronyd to keep system time accurate.
P2P Connection Issues
Cause: Node cannot connect to peers.
Solution:
- Ensure the P2P port is accessible (not firewalled)
- Verify
--keypairis set with a valid P2P secret key - Check that
--reserved-nodescontains valid multiaddr strings - Verify the chain config checksum matches the network
Prevention: Use DNS-based multiaddrs for bootstrap nodes to handle IP changes.
Tip
Enable
RUST_LOG=fuel_core_p2p=debugto see detailed P2P connection diagnostics.
Error: Failed to acquire the production lock, block production is already in progress
Cause: A new block production request was made while another is still executing.
Solution: Wait for the current block production to complete. This is normal under high load.
Prevention: This is a concurrency guard — the system handles it automatically.
7. FAQ
Q: What database backends does fuel-core support?
Fuel Core supports two backends: RocksDB (persistent, production-ready) and in-memory (ephemeral, for development/testing). Use --db-type rocks-db or --db-type in-memory to select.
Q: What is the difference between PoA and PoAV2 consensus?
PoA (V1) uses a single signing key for block production. PoAV2 extends this with height-based consensus parameter overrides, enabling protocol parameter changes at specific block heights without code changes.
Q: How does the WASM executor enable forkless upgrades?
The upgradable executor can load state transition logic from WASM bytecode stored on-chain. When an Upgrade transaction is included, nodes automatically switch to executing the new WASM bytecode — no binary update or hard fork required. The WASM executor is designed for one block execution per instance.
Q: What is the Ethereum relayer?
The relayer monitors the Fuel bridge contract on Ethereum (FuelMessagePortal), downloading finalized log events. It tracks MessageSent and Transaction events. Messages and relayed transactions become available to the Fuel chain after Ethereum finality (~13 minutes / ~100 blocks). The relayer uses a configurable log_page_size (default 10,000) for batch fetching.
Q: How is gas pricing determined?
Fuel Core supports both static and dynamic gas pricing. The static algorithm returns a fixed price. The dynamic algorithm (v1) uses a cumulative percentage-based model that adjusts based on L2 block utilization and DA layer recording costs. Query current prices via the latestGasPrice GraphQL endpoint.
Q: Can I run a node without P2P?
Yes. P2P is an optional feature flag. Without it, the node operates standalone — useful for local development, testing, and single-validator setups.
Q: What transaction types are supported?
Fuel Core supports six transaction types: Script (execute code), Create (deploy contracts), Mint (coinbase/block reward), Upgrade (protocol upgrades), Upload (upload bytecode chunks), and Blob (store arbitrary data).
Q: How do I monitor node health in production?
Query the /v1/health HTTP endpoint or use the GraphQL health query. Fuel-core exposes Prometheus-compatible metrics via the fuel-core-metrics subsystem covering GraphQL query costs, P2P peer counts, txpool sizes, block import times, gas price updates, and PoA block production timing.
Q: What is the block aggregator API?
The block aggregator API (enabled with --features rpc) provides a gRPC/protobuf interface for efficient block data retrieval, with support for S3-backed remote caching and compressed block storage for DA layer submission.
Q: What is the shared sequencer?
The shared sequencer service (enabled with --features shared-sequencer) integrates with a Cosmos SDK-based shared sequencer chain via Tendermint RPC, enabling cross-rollup ordering of transactions.
Q: How does the transaction pool work?
The txpool (v2) manages pending transactions with configurable limits on count, total gas, and byte size. It supports dependency chain tracking via petgraph, collision detection, TTL-based expiration, and a blacklist system for addresses, UTXOs, message nonces, and contract IDs. Transactions are selected using a ratio-based tip/gas algorithm.