|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to AI coding assistants (such as Claude Code, Cursor, Copilot, etc.) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +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). |
| 8 | + |
| 9 | +## Development Commands |
| 10 | + |
| 11 | +### Building and Installing |
| 12 | + |
| 13 | +```bash |
| 14 | +# Install Forest binaries with release profile (recommended) |
| 15 | +mise install |
| 16 | + |
| 17 | +# Install with different profiles |
| 18 | +mise install quick # Faster build, less optimization |
| 19 | +mise install release-lto-fat # Maximum optimization (slower build) |
| 20 | +mise install dev # Debug build |
| 21 | + |
| 22 | +# Install slim version (minimal features) |
| 23 | +mise install --slim |
| 24 | + |
| 25 | +# Build without installing |
| 26 | +cargo build --release |
| 27 | +cargo build --profile quick # Faster compile time |
| 28 | + |
| 29 | +# Run binaries directly (for development) |
| 30 | +cargo daemon --chain calibnet # Alias for: cargo run --bin forest -- |
| 31 | +cargo cli info show # Alias for: cargo run --bin forest-cli -- |
| 32 | +cargo forest-tool --help # Alias for: cargo run --bin forest-tool --release -- |
| 33 | +``` |
| 34 | + |
| 35 | +### Testing |
| 36 | + |
| 37 | +```bash |
| 38 | +# Run all tests (requires cargo-nextest: cargo install cargo-nextest --locked) |
| 39 | +mise test # Uses 'quick' profile by default |
| 40 | +mise test release # Run with release profile |
| 41 | +mise test dev # Run with dev profile |
| 42 | + |
| 43 | +# Run only Rust tests (no doctests) |
| 44 | +mise test:rust |
| 45 | +mise test:rust release |
| 46 | + |
| 47 | +# Run only doctests |
| 48 | +mise test:docs |
| 49 | +mise test:docs release |
| 50 | + |
| 51 | +# Run specific test |
| 52 | +cargo nextest run --cargo-profile quick <test_name> |
| 53 | + |
| 54 | +# Run tests in a specific file/module |
| 55 | +cargo nextest run --cargo-profile quick state_manager:: |
| 56 | + |
| 57 | +# Run single test with full output |
| 58 | +cargo nextest run --cargo-profile quick --no-capture <test_name> |
| 59 | + |
| 60 | +# Run doctests for private items |
| 61 | +cargo test --doc --profile quick --features doctest-private |
| 62 | +``` |
| 63 | + |
| 64 | +### Linting and Formatting |
| 65 | + |
| 66 | +```bash |
| 67 | +# Install all linting tools |
| 68 | +mise install-lint-tools |
| 69 | + |
| 70 | +# Run all linters |
| 71 | +mise lint |
| 72 | + |
| 73 | +# Run specific linters |
| 74 | +mise lint:rust-fmt # Rust formatting check |
| 75 | +mise lint:clippy # Rust linter |
| 76 | +mise lint:toml # TOML formatting/linting |
| 77 | +mise lint:spellcheck # Spell checking |
| 78 | +mise lint:deny # Check licenses and security |
| 79 | +mise lint:unused-deps # Check for unused dependencies |
| 80 | +mise lint:dockerfile # Lint Dockerfiles |
| 81 | +mise lint:shellcheck # Lint shell scripts |
| 82 | +mise lint:golang # Lint Go code (F3 sidecar) |
| 83 | + |
| 84 | +# Format code |
| 85 | +mise fmt # Format Rust, TOML, markdown, YAML |
| 86 | + |
| 87 | +# Check specific issues |
| 88 | +cargo fmt --all -- --check |
| 89 | +cargo clippy --all-targets --no-deps -- --deny=warnings |
| 90 | +taplo fmt --check && taplo lint |
| 91 | +``` |
| 92 | + |
| 93 | +### Code Coverage |
| 94 | + |
| 95 | +```bash |
| 96 | +# Generate coverage report (requires cargo-llvm-cov: cargo install cargo-llvm-cov) |
| 97 | +mise codecov |
| 98 | +``` |
| 99 | + |
| 100 | +### Cleaning |
| 101 | + |
| 102 | +```bash |
| 103 | +# Clean all build artifacts and dependencies |
| 104 | +mise clean |
| 105 | +``` |
| 106 | + |
| 107 | +## High-Level Architecture |
| 108 | + |
| 109 | +### Core Modules |
| 110 | + |
| 111 | +- **`daemon/`** - Node startup, initialization, and service orchestration |
| 112 | +- **`chain/`** - Blockchain storage (`ChainStore`) and index management |
| 113 | +- **`chain_sync/`** - Chain synchronization, consensus (`ChainFollower`, `ChainMuxer`) |
| 114 | +- **`state_manager/`** - State tree management and FVM execution coordinator |
| 115 | +- **`rpc/`** - JSON-RPC API server with authentication and filtering middleware |
| 116 | +- **`libp2p/`** - P2P networking (peer discovery, chain exchange, gossipsub) |
| 117 | +- **`message_pool/`** - Transaction pool for pending messages |
| 118 | +- **`db/`** - Database abstraction layer (ParityDb, MemoryDB, CAR format) |
| 119 | +- **`interpreter/`** - Filecoin Virtual Machine (FVM) integration (multi-version) |
| 120 | +- **`blocks/`** - Block and tipset structures |
| 121 | +- **`shim/`** - Filecoin protocol primitives (actors, crypto, addresses, state tree) |
| 122 | +- **`eth/`** - Ethereum compatibility layer (EVM transactions, address mapping) |
| 123 | +- **`wallet/`** - Key management and transaction signing |
| 124 | +- **`networks/`** - Network configurations (mainnet, calibnet, devnet) |
| 125 | + |
| 126 | +### Key Architectural Patterns |
| 127 | + |
| 128 | +**Blockstore Pattern**: Generic database trait (`fvm_ipld_blockstore::Blockstore`) allows swapping storage implementations. Most core structures are generic over `DB: Blockstore`: |
| 129 | + |
| 130 | +```rust |
| 131 | +pub struct StateManager<DB> where DB: Blockstore { ... } |
| 132 | +pub struct ChainStore<DB> where DB: Blockstore { ... } |
| 133 | +``` |
| 134 | + |
| 135 | +**Publisher/Subscriber**: `HeadChange` events (new tipsets, reorg reverts) are broadcast via `Publisher` to multiple subscribers (RPC, message pool, chain indexer). |
| 136 | + |
| 137 | +**State Management**: `StateManager` is the central coordinator for state transitions, actor queries, and FVM execution. It caches state roots and receipts in `TipsetStateCache`. |
| 138 | + |
| 139 | +**Multi-version FVM**: Supports FVM2, FVM3, and FVM4 for different network versions. Stack size management with `stacker::grow()` is required for WASM execution. |
| 140 | + |
| 141 | +### Daemon Startup Flow |
| 142 | + |
| 143 | +1. `startup_init()` - Increase file descriptor limits, initialize proof cache |
| 144 | +2. `AppContext::init()` - Initialize database, state manager, keystore, JWT |
| 145 | +3. `create_p2p_service()` - Start libp2p networking stack |
| 146 | +4. `create_mpool()` - Initialize message pool |
| 147 | +5. `create_chain_follower()` - Start chain synchronization |
| 148 | +6. `maybe_start_rpc_service()` - Start JSON-RPC server |
| 149 | +7. `maybe_start_metrics_service()` - Start Prometheus metrics endpoint |
| 150 | +8. `maybe_start_health_check_service()` - Start health check service |
| 151 | +9. `maybe_start_f3_service()` - Start F3 sidecar (Fast Finality, optional) |
| 152 | + |
| 153 | +### Chain Synchronization |
| 154 | + |
| 155 | +**ChainFollower** orchestrates synchronization: |
| 156 | + |
| 157 | +- Receives tipsets from network peers |
| 158 | +- Validates blocks via `TipsetSyncer` and `TipsetValidator` |
| 159 | +- Resolves forks via `ChainMuxer` (heaviest chain wins) |
| 160 | +- Updates chain head through `StateManager` |
| 161 | +- Maintains `BadBlockCache` for invalid blocks |
| 162 | +- Reports `SyncStatus` to RPC clients |
| 163 | + |
| 164 | +### RPC Server Architecture |
| 165 | + |
| 166 | +Multi-layer middleware stack: |
| 167 | + |
| 168 | +``` |
| 169 | +Request → AuthLayer → FilterLayer → SegregationLayer → |
| 170 | +SetExtensionLayer → LogLayer → MetricsLayer → RpcHandler |
| 171 | +``` |
| 172 | + |
| 173 | +Major RPC namespaces: `auth::`, `chain::`, `state::`, `mpool::`, `eth::`, `net::`, `sync::`, `wallet::` |
| 174 | + |
| 175 | +### FVM Integration |
| 176 | + |
| 177 | +**Version Selection**: Network version determines FVM version (FVM2 for v1-v15, FVM3 for v16-v20, FVM4 for v21+) |
| 178 | + |
| 179 | +**VM Execution Flow**: |
| 180 | + |
| 181 | +``` |
| 182 | +StateManager::call_with_gas() |
| 183 | + → VM::new(ExecutionContext) |
| 184 | + → vm.apply_message() / apply_implicit_message() |
| 185 | + → VM::flush() → new_state_root |
| 186 | +``` |
| 187 | + |
| 188 | +**Key Concepts**: |
| 189 | + |
| 190 | +- **State Tree** - IPLD-based Merkle tree of actor states |
| 191 | +- **Actors** - Smart contracts (System, Init, Power, Market, Miner, etc.) |
| 192 | +- **Messages** - Transactions that execute actor methods |
| 193 | +- **Receipts** - Execution results (gas used, exit code, return value) |
| 194 | +- **Randomness** - Provided by Drand beacon (via `ChainRand`) |
| 195 | +- **State Migrations** - Automatic upgrades at network version boundaries |
| 196 | + |
| 197 | +### P2P Networking |
| 198 | + |
| 199 | +Libp2p protocols: |
| 200 | + |
| 201 | +- **Chain Exchange** - Fetch blocks and messages during sync |
| 202 | +- **Hello** - Exchange peer info and genesis CID |
| 203 | +- **Gossipsub** - Broadcast new blocks and messages |
| 204 | +- **Bitswap** - IPLD block exchange (legacy) |
| 205 | +- **Kademlia DHT** - Peer discovery |
| 206 | +- **mDNS** - Local network discovery |
| 207 | + |
| 208 | +**Peer Manager** tracks peer quality, manages connections, and scores peers based on message validity. |
| 209 | + |
| 210 | +### Database Organization |
| 211 | + |
| 212 | +Storage layers: |
| 213 | + |
| 214 | +``` |
| 215 | +Application (StateManager, ChainStore) |
| 216 | + ↓ |
| 217 | +IPLD Blockstore (LogicalDB) |
| 218 | + ↓ |
| 219 | +Write Buffer / Read Cache (optional) |
| 220 | + ↓ |
| 221 | +ParityDb (embedded KV store) |
| 222 | +``` |
| 223 | + |
| 224 | +Special stores: |
| 225 | + |
| 226 | +- **Settings Store** - Configuration persistence (chain head, message pool config) |
| 227 | +- **Eth Mappings Store** - ETH ↔ Filecoin address mappings |
| 228 | +- **Indices Store** - Message and event indices |
| 229 | +- **CAR DB** - Snapshot import/export (v1, v2 with F3 data) |
| 230 | + |
| 231 | +### Ethereum Compatibility |
| 232 | + |
| 233 | +Supports legacy transactions, EIP-155, and EIP-1559. Provides standard Ethereum RPC methods (`eth_call`, `eth_sendTransaction`, `eth_getTransactionReceipt`, `eth_subscribe`, etc.) |
| 234 | + |
| 235 | +**Address Mapping**: EVM addresses map to Filecoin f4 (delegated) addresses. Precompiles provide Filecoin-specific operations. |
| 236 | + |
| 237 | +## Project-Specific Patterns |
| 238 | + |
| 239 | +### Error Handling |
| 240 | + |
| 241 | +Use `anyhow::Result<T>` for most operations. Add context with `.context()`: |
| 242 | + |
| 243 | +```rust |
| 244 | +some_operation().context("Failed to execute VM")? |
| 245 | +``` |
| 246 | + |
| 247 | +### Async/Await |
| 248 | + |
| 249 | +- Tokio runtime for async execution |
| 250 | +- Use `tokio::task::spawn_blocking` for CPU-intensive work (VM execution, cryptography) |
| 251 | +- Channel-based communication between tasks (flume, tokio channels) |
| 252 | + |
| 253 | +### Module Organization |
| 254 | + |
| 255 | +Each module has: |
| 256 | + |
| 257 | +- `mod.rs` - Public API exports |
| 258 | +- Private submodules for implementation details |
| 259 | +- Clear trait boundaries for extensibility |
| 260 | + |
| 261 | +### Code Style |
| 262 | + |
| 263 | +- **No indexing** - Use `.get()` instead of `[index]` (enforced by clippy) |
| 264 | +- **No unwrap in production** - Use `?` or `expect()` with descriptive messages |
| 265 | +- **No dbg! or todo!** - Enforced in non-test code |
| 266 | +- Use `strum` for enum string conversions |
| 267 | +- Use `derive_more` for common trait implementations |
| 268 | + |
| 269 | +### Testing Utilities |
| 270 | + |
| 271 | +- `test_utils/` provides fixtures and helpers |
| 272 | +- Use `#[cfg(test)]` or `#[cfg(feature = "doctest-private")]` for test-only code |
| 273 | +- Serial tests (database tests) use `#[serial_test::serial]` |
| 274 | + |
| 275 | +### Network-Specific Configuration |
| 276 | + |
| 277 | +Networks defined in `networks/`: |
| 278 | + |
| 279 | +- **mainnet** - Production Filecoin network |
| 280 | +- **calibnet** - Public testnet (recommended for development) |
| 281 | +- **devnet** - Lightweight local network |
| 282 | +- **butterflynet** - Alternative testnet |
| 283 | + |
| 284 | +Each network has its own genesis, bootstrap peers, actor bundles, and upgrade epochs. |
| 285 | + |
| 286 | +## Common Development Workflows |
| 287 | + |
| 288 | +### Running a Local Node |
| 289 | + |
| 290 | +```bash |
| 291 | +# Mainnet (requires snapshot download) |
| 292 | +forest --encrypt-keystore false |
| 293 | + |
| 294 | +# Calibnet (testnet, auto-download snapshot) |
| 295 | +forest --chain calibnet --auto-download-snapshot --encrypt-keystore false |
| 296 | + |
| 297 | +# Using Docker |
| 298 | +docker run --init -it --rm ghcr.io/chainsafe/forest:latest --chain calibnet --auto-download-snapshot |
| 299 | +``` |
| 300 | + |
| 301 | +### Using the CLI |
| 302 | + |
| 303 | +```bash |
| 304 | +# Set admin token for privileged operations |
| 305 | +export FULLNODE_API_INFO="<token>:/ip4/127.0.0.1/tcp/2345/http" |
| 306 | + |
| 307 | +# Or use --token flag |
| 308 | +forest-cli --token <ADMIN_TOKEN> info show |
| 309 | + |
| 310 | +# Common commands |
| 311 | +forest-cli info show # Node status |
| 312 | +forest-cli chain head # Current chain head |
| 313 | +forest-cli sync status # Sync progress |
| 314 | +forest-cli net peers # Connected peers |
| 315 | +forest-cli wallet list # List wallets |
| 316 | +forest-cli mpool pending # Pending messages |
| 317 | +``` |
| 318 | + |
| 319 | +### Working with Snapshots |
| 320 | + |
| 321 | +```bash |
| 322 | +# Fetch snapshot |
| 323 | +forest-tool snapshot fetch --chain calibnet |
| 324 | + |
| 325 | +# Export snapshot |
| 326 | +forest-tool snapshot export --output snapshot.car |
| 327 | + |
| 328 | +# Import snapshot |
| 329 | +forest --import-snapshot snapshot.car --encrypt-keystore false |
| 330 | +``` |
| 331 | + |
| 332 | +### Debugging |
| 333 | + |
| 334 | +```bash |
| 335 | +# Enable debug logging |
| 336 | +RUST_LOG=debug forest --chain calibnet |
| 337 | + |
| 338 | +# Filter specific modules |
| 339 | +RUST_LOG="debug,forest_libp2p::service=info" forest |
| 340 | + |
| 341 | +# Use tokio-console (requires tokio-console feature) |
| 342 | +tokio-console # In separate terminal |
| 343 | +forest # With RUSTFLAGS="--cfg tokio_unstable" |
| 344 | + |
| 345 | +# Profile with debugging symbols |
| 346 | +FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT=1 cargo build --profile debugging |
| 347 | +lldb target/debugging/forest |
| 348 | +``` |
| 349 | + |
| 350 | +## Important Environment Variables |
| 351 | + |
| 352 | +- `FOREST_KEYSTORE_PHRASE` - Passphrase for encrypted keystore (headless mode) |
| 353 | +- `FOREST_CONFIG_PATH` - Path to config file (overrides default locations) |
| 354 | +- `RUST_LOG` - Logging configuration (e.g., `debug`, `forest=trace`) |
| 355 | +- `FULLNODE_API_INFO` - RPC endpoint and authentication token |
| 356 | +- `FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT` - Disable F3 sidecar build (for debugging profile) |
| 357 | + |
| 358 | +## Cargo Features |
| 359 | + |
| 360 | +- **`default`** - `jemalloc`, `tokio-console`, `tracing-loki`, `tracing-chrome` |
| 361 | +- **`slim`** - Minimal feature set (uses rustalloc) |
| 362 | +- **`jemalloc`** - Use jemalloc allocator (production default) |
| 363 | +- **`rustalloc`** - Use Rust standard allocator |
| 364 | +- **`system-alloc`** - Use system allocator (for memory profiling) |
| 365 | +- **`tokio-console`** - Enable tokio-console integration |
| 366 | +- **`tracing-loki`** - Send telemetry to Loki |
| 367 | +- **`tracing-chrome`** - Chrome tracing support |
| 368 | +- **`no-f3-sidecar`** - Disable F3 sidecar build |
| 369 | +- **`doctest-private`** - Enable doctests for private items |
| 370 | +- **`benchmark-private`** - Enable benchmark suite |
| 371 | +- **`interop-tests-private`** - Enable interop tests |
| 372 | + |
| 373 | +## Build Profiles |
| 374 | + |
| 375 | +- **`dev`** - Fast compile, line-table-only debug info, opt-level=1 for deps |
| 376 | +- **`quick`** - Inherits from release, opt-level=1, no LTO (good for testing) |
| 377 | +- **`release`** - Optimized, stripped, thin LTO, panic=abort |
| 378 | +- **`release-lto-fat`** - Maximum optimization with fat LTO |
| 379 | +- **`debugging`** - Full debug info (requires `FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT=1`) |
| 380 | +- **`profiling`** - For profiling tools |
| 381 | + |
| 382 | +## Key Dependencies |
| 383 | + |
| 384 | +- **Rust**: Version specified in `rust-toolchain.toml` |
| 385 | +- **Go**: Version specified in `go.work` (required for F3 sidecar) |
| 386 | +- **OS packages**: `build-essential` (Ubuntu), `clang`, `clang-devel` (Fedora) |
| 387 | +- **mise-en-place**: Task runner and tool installer (`mise.jdx.dev`) |
| 388 | + |
| 389 | +## Contributing Guidelines |
| 390 | + |
| 391 | +From CONTRIBUTING.md: |
| 392 | + |
| 393 | +- Use conventional commits (e.g., `feat: add Filecoin.RuleTheWorld RPC method`) |
| 394 | +- Run linters before submitting: `mise lint` |
| 395 | +- Format code: `mise fmt` |
| 396 | +- Ensure tests pass: `mise test` |
| 397 | +- Fill PR template exhaustively |
| 398 | +- First-time contributors sign CLA when opening PR |
| 399 | +- Document public functions and structs (see [Documentation practices](https://github.com/ChainSafe/forest/wiki/Documentation-practices)) |
0 commit comments