This file provides guidance to AI coding assistants (such as Claude Code, Cursor, Copilot, etc.) when working with code in this repository.
Forest is a Rust implementation of a Filecoin node that can transfer FIL, host a high-performance RPC API, validate the Filecoin blockchain, and generate blockchain snapshots. It aims to be faster and easier-to-use than the canonical Filecoin node (Lotus).
# Install Forest binaries with release profile (recommended)
mise run install
# Install with different profiles
mise run install quick # Faster build, less optimization
mise run install release-lto-fat # Maximum optimization (slower build)
mise run install dev # Debug build
# Install slim version (minimal features)
mise run install --slim
# Build without installing
cargo build --release
cargo build --profile quick # Faster compile time
# Run binaries directly (for development)
cargo daemon --chain calibnet # Alias for: cargo run --bin forest --
cargo cli info show # Alias for: cargo run --bin forest-cli --
cargo forest-tool --help # Alias for: cargo run --bin forest-tool --release --# Run all tests (requires cargo-nextest: cargo install cargo-nextest --locked)
mise test # Uses 'quick' profile by default
mise test release # Run with release profile
mise test dev # Run with dev profile
# Run only Rust tests (no doctests)
mise test:rust
mise test:rust release
# Run only doctests
mise test:docs
mise test:docs release
# Run specific test
cargo nextest run --cargo-profile quick <test_name>
# Run tests in a specific file/module
cargo nextest run --cargo-profile quick state_manager::
# Run single test with full output
cargo nextest run --cargo-profile quick --no-capture <test_name>
# Run doctests for private items
cargo test --doc --profile quick --features doctest-private# Install all linting tools
mise install-lint-tools
# Run all linters
mise lint
# Run specific linters
mise lint:rust-fmt # Rust formatting check
mise lint:clippy # Rust linter
mise lint:toml # TOML formatting/linting
mise lint:spellcheck # Spell checking
mise lint:deny # Check licenses and security
mise lint:unused-deps # Check for unused dependencies
mise lint:dockerfile # Lint Dockerfiles
mise lint:shellcheck # Lint shell scripts
mise lint:golang # Lint Go code (F3 sidecar)
# Format code
mise fmt # Format Rust, TOML, markdown, YAML
# Check specific issues
cargo fmt --all -- --check
cargo clippy --all-targets --no-deps -- --deny=warnings
taplo fmt --check && taplo lint# Generate coverage report (requires cargo-llvm-cov: cargo install cargo-llvm-cov)
mise codecov# Clean all build artifacts and dependencies
mise cleandaemon/- Node startup, initialization, and service orchestrationchain/- Blockchain storage (ChainStore) and index managementchain_sync/- Chain synchronization, consensus (ChainFollower,ChainMuxer)state_manager/- State tree management and FVM execution coordinatorrpc/- JSON-RPC API server with authentication and filtering middlewarelibp2p/- P2P networking (peer discovery, chain exchange,gossipsub)message_pool/- Transaction pool for pending messagesdb/- Database abstraction layer (ParityDb,MemoryDB, CAR format)interpreter/- Filecoin Virtual Machine (FVM) integration (multi-version)blocks/- Block and tipset structuresshim/- Filecoin protocol primitives (actors, crypto, addresses, state tree)eth/- Ethereum compatibility layer (EVM transactions, address mapping)wallet/- Key management and transaction signingnetworks/- Network configurations (mainnet, calibnet, devnet)
Blockstore Pattern: Generic database trait (fvm_ipld_blockstore::Blockstore) allows swapping storage implementations. Most core structures are generic over DB: Blockstore:
pub struct StateManager<DB> where DB: Blockstore { ... }
pub struct ChainStore<DB> where DB: Blockstore { ... }Publisher/Subscriber: HeadChange events (new tipsets, reorg reverts) are broadcast via Publisher to multiple subscribers (RPC, message pool, chain indexer).
State Management: StateManager is the central coordinator for state transitions, actor queries, and FVM execution. It caches state roots and receipts in TipsetStateCache.
Multi-version FVM: Supports FVM2, FVM3, and FVM4 for different network versions. Stack size management with stacker::grow() is required for WASM execution.
startup_init()- Increase file descriptor limits, initialize proof cacheAppContext::init()- Initialize database, state manager, keystore, JWTcreate_p2p_service()- Start libp2p networking stackcreate_mpool()- Initialize message poolcreate_chain_follower()- Start chain synchronizationmaybe_start_rpc_service()- Start JSON-RPC servermaybe_start_metrics_service()- Start Prometheus metrics endpointmaybe_start_health_check_service()- Start health check servicemaybe_start_f3_service()- Start F3 sidecar (Fast Finality, optional)
ChainFollower orchestrates synchronization:
- Receives tipsets from network peers
- Validates blocks via
TipsetSyncerandTipsetValidator - Resolves forks via
ChainMuxer(heaviest chain wins) - Updates chain head through
StateManager - Maintains
BadBlockCachefor invalid blocks - Reports
SyncStatusto RPC clients
Multi-layer middleware stack:
Request β AuthLayer β FilterLayer β SegregationLayer β
SetExtensionLayer β LogLayer β MetricsLayer β RpcHandler
Major RPC namespaces: auth::, chain::, state::, mpool::, eth::, net::, sync::, wallet::
Version Selection: Network version determines FVM version (FVM2 for v1-v15, FVM3 for v16-v20, FVM4 for v21+)
VM Execution Flow:
StateManager::call_with_gas()
β VM::new(ExecutionContext)
β vm.apply_message() / apply_implicit_message()
β VM::flush() β new_state_root
Key Concepts:
- State Tree - IPLD-based Merkle tree of actor states
- Actors - Smart contracts (System, Init, Power, Market, Miner, etc.)
- Messages - Transactions that execute actor methods
- Receipts - Execution results (gas used, exit code, return value)
- Randomness - Provided by Drand beacon (via
ChainRand) - State Migrations - Automatic upgrades at network version boundaries
Libp2p protocols:
- Chain Exchange - Fetch blocks and messages during sync
- Hello - Exchange peer info and genesis CID
Gossipsub- Broadcast new blocks and messages- Bitswap - IPLD block exchange (legacy)
- Kademlia DHT - Peer discovery
mDNS- Local network discovery
Peer Manager tracks peer quality, manages connections, and scores peers based on message validity.
Storage layers:
Application (StateManager, ChainStore)
β
IPLD Blockstore (LogicalDB)
β
Write Buffer / Read Cache (optional)
β
ParityDb (embedded KV store)
Special stores:
- Settings Store - Configuration persistence (chain head, message pool config)
- Eth Mappings Store - ETH β Filecoin address mappings
- Indices Store - Message and event indices
- CAR DB - Snapshot import/export (v1, v2 with F3 data)
Supports legacy transactions, EIP-155, and EIP-1559. Provides standard Ethereum RPC methods (eth_call, eth_sendTransaction, eth_getTransactionReceipt, eth_subscribe, etc.)
Address Mapping: EVM addresses map to Filecoin f4 (delegated) addresses. Precompiles provide Filecoin-specific operations.
Use anyhow::Result<T> for most operations. Add context with .context():
some_operation().context("Failed to execute VM")?Tokioruntime for async execution- Use
tokio::task::spawn_blockingfor CPU-intensive work (VM execution, cryptography) - Channel-based communication between tasks (flume,
tokiochannels)
Each module has:
mod.rs- Public API exports- Private submodules for implementation details
- Clear trait boundaries for extensibility
- No indexing - Use
.get()instead of[index](enforced by clippy) - No unwrap in production - Use
?orexpect()with descriptive messages - No
dbg!ortodo!- Enforced in non-test code - Use
strumfor enum string conversions - Use
derive_morefor common trait implementations
test_utils/provides fixtures and helpers- Use
#[cfg(test)]or#[cfg(feature = "doctest-private")]for test-only code - Serial tests (database tests) use
#[serial_test::serial]
Networks defined in networks/:
- mainnet - Production Filecoin network
- calibnet - Public testnet (recommended for development)
- devnet - Lightweight local network
- butterflynet - Alternative testnet
Each network has its own genesis, bootstrap peers, actor bundles, and upgrade epochs.
# Mainnet (requires snapshot download)
forest
# Calibnet (testnet, auto-download snapshot)
forest --chain calibnet --auto-download-snapshot
# Using Docker
docker run --init -it --rm ghcr.io/chainsafe/forest:latest --chain calibnet --auto-download-snapshot# Set admin token for privileged operations
export FULLNODE_API_INFO="<token>:/ip4/127.0.0.1/tcp/2345/http"
# Or use --token flag
forest-cli --token <ADMIN_TOKEN> info show
# Common commands
forest-cli info show # Node status
forest-cli chain head # Current chain head
forest-cli sync status # Sync progress
forest-cli net peers # Connected peers
forest-cli wallet list # List wallets
forest-cli mpool pending # Pending messages# Fetch snapshot
forest-tool snapshot fetch --chain calibnet
# Export snapshot
forest-tool snapshot export --output snapshot.car
# Import snapshot
forest --import-snapshot snapshot.car# Enable debug logging
RUST_LOG=debug forest --chain calibnet
# Filter specific modules
RUST_LOG="debug,forest_libp2p::service=info" forest
# Use tokio-console (requires tokio-console feature)
tokio-console # In separate terminal
forest # With RUSTFLAGS="--cfg tokio_unstable"
# Profile with debugging symbols
FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT=1 cargo build --profile debugging
lldb target/debugging/forestFOREST_KEYSTORE_PHRASE- Passphrase for encrypted keystore (headless mode)FOREST_CONFIG_PATH- Path to config file (overrides default locations)RUST_LOG- Logging configuration (e.g.,debug,forest=trace)FULLNODE_API_INFO- RPC endpoint and authentication tokenFOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT- Disable F3 sidecar build (for debugging profile)
dev- Fast compile, line-table-only debug info, opt-level=1 for depsquick- Inherits from release, opt-level=1, no LTO (good for testing)release- Optimized, stripped, thin LTO, panic=abortrelease-lto-fat- Maximum optimization with fat LTOdebugging- Full debug info (requiresFOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT=1)profiling- For profiling tools
- Rust: Version specified in
rust-toolchain.toml - Go: Version specified in
go.work(required for F3 sidecar) - OS packages:
build-essential(Ubuntu),clang,clang-devel(Fedora) - mise-en-place: Task runner and tool installer (
mise.jdx.dev)
From CONTRIBUTING.md:
- Use conventional commits (e.g.,
feat: add Filecoin.RuleTheWorld RPC method) - Run linters before submitting:
mise lint - Format code:
mise fmt - Ensure tests pass:
mise test - Fill PR template exhaustively
- First-time contributors sign CLA when opening PR
- Document public functions and structs (see Documentation practices)