Skip to content

Latest commit

Β 

History

History
384 lines (276 loc) Β· 12.4 KB

File metadata and controls

384 lines (276 loc) Β· 12.4 KB

AGENTS.md

This file provides guidance to AI coding assistants (such as Claude Code, Cursor, Copilot, etc.) when working with code in this repository.

Project Overview

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).

Development Commands

Building and Installing

# 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 --

Testing

# 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

Linting and Formatting

# 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

Code Coverage

# Generate coverage report (requires cargo-llvm-cov: cargo install cargo-llvm-cov)
mise codecov

Cleaning

# Clean all build artifacts and dependencies
mise clean

High-Level Architecture

Core Modules

  • daemon/ - Node startup, initialization, and service orchestration
  • chain/ - Blockchain storage (ChainStore) and index management
  • chain_sync/ - Chain synchronization, consensus (ChainFollower, ChainMuxer)
  • state_manager/ - State tree management and FVM execution coordinator
  • rpc/ - JSON-RPC API server with authentication and filtering middleware
  • libp2p/ - P2P networking (peer discovery, chain exchange, gossipsub)
  • message_pool/ - Transaction pool for pending messages
  • db/ - Database abstraction layer (ParityDb, MemoryDB, CAR format)
  • interpreter/ - Filecoin Virtual Machine (FVM) integration (multi-version)
  • blocks/ - Block and tipset structures
  • shim/ - Filecoin protocol primitives (actors, crypto, addresses, state tree)
  • eth/ - Ethereum compatibility layer (EVM transactions, address mapping)
  • wallet/ - Key management and transaction signing
  • networks/ - Network configurations (mainnet, calibnet, devnet)

Key Architectural Patterns

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.

Daemon Startup Flow

  1. startup_init() - Increase file descriptor limits, initialize proof cache
  2. AppContext::init() - Initialize database, state manager, keystore, JWT
  3. create_p2p_service() - Start libp2p networking stack
  4. create_mpool() - Initialize message pool
  5. create_chain_follower() - Start chain synchronization
  6. maybe_start_rpc_service() - Start JSON-RPC server
  7. maybe_start_metrics_service() - Start Prometheus metrics endpoint
  8. maybe_start_health_check_service() - Start health check service
  9. maybe_start_f3_service() - Start F3 sidecar (Fast Finality, optional)

Chain Synchronization

ChainFollower orchestrates synchronization:

  • Receives tipsets from network peers
  • Validates blocks via TipsetSyncer and TipsetValidator
  • Resolves forks via ChainMuxer (heaviest chain wins)
  • Updates chain head through StateManager
  • Maintains BadBlockCache for invalid blocks
  • Reports SyncStatus to RPC clients

RPC Server Architecture

Multi-layer middleware stack:

Request β†’ AuthLayer β†’ FilterLayer β†’ SegregationLayer β†’
SetExtensionLayer β†’ LogLayer β†’ MetricsLayer β†’ RpcHandler

Major RPC namespaces: auth::, chain::, state::, mpool::, eth::, net::, sync::, wallet::

FVM Integration

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

P2P Networking

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.

Database Organization

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)

Ethereum Compatibility

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.

Project-Specific Patterns

Error Handling

Use anyhow::Result<T> for most operations. Add context with .context():

some_operation().context("Failed to execute VM")?

Async/Await

  • Tokio runtime for async execution
  • Use tokio::task::spawn_blocking for CPU-intensive work (VM execution, cryptography)
  • Channel-based communication between tasks (flume, tokio channels)

Module Organization

Each module has:

  • mod.rs - Public API exports
  • Private submodules for implementation details
  • Clear trait boundaries for extensibility

Code Style

  • No indexing - Use .get() instead of [index] (enforced by clippy)
  • No unwrap in production - Use ? or expect() with descriptive messages
  • No dbg! or todo! - Enforced in non-test code
  • Use strum for enum string conversions
  • Use derive_more for common trait implementations

Testing Utilities

  • 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]

Network-Specific Configuration

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.

Common Development Workflows

Running a Local Node

# 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

Using the CLI

# 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

Working with Snapshots

# Fetch snapshot
forest-tool snapshot fetch --chain calibnet

# Export snapshot
forest-tool snapshot export --output snapshot.car

# Import snapshot
forest --import-snapshot snapshot.car

Debugging

# 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/forest

Important Environment Variables

  • FOREST_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 token
  • FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT - Disable F3 sidecar build (for debugging profile)

Build Profiles

  • dev - Fast compile, line-table-only debug info, opt-level=1 for deps
  • quick - Inherits from release, opt-level=1, no LTO (good for testing)
  • release - Optimized, stripped, thin LTO, panic=abort
  • release-lto-fat - Maximum optimization with fat LTO
  • debugging - Full debug info (requires FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT=1)
  • profiling - For profiling tools

Key Dependencies

  • 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)

Contributing Guidelines

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)