fuels-rs:使用 RocksDB 将 Fuel 节点链状态持久化到本地
本篇指南基于 fuels-rs 官方文档中的 RocksDB 章节,讲解如何在 Fuel Rust SDK 的测试/本地节点中启用 RocksDB 数据库,把 fuel-core 节点的区块链状态持久化保存到磁盘并在后续复用。读完后你将掌握:NodeConfig 中 DbType 的两种取值及其默认行为、数据库路径与缓存大小的配置方式,以及 fuel-core 二进制与 fuel-core-lib + rocksdb 两种运行模式的区别和启用条件。
为什么需要 RocksDB:从内存数据库到本地持久化
fuels-rs 在启动本地 fuel-core 测试节点时,默认使用内存数据库(in-memory),节点进程退出后所有链状态(区块、UTXO、合约存储等)随之丢失。文档 docs/src/connecting/rocksdb.md 对此的总结是:
RocksDB enables the preservation of the blockchain's state locally, facilitating its future utilization. (RocksDB 使区块链状态可以本地保存,便于后续使用。)
换句话说,启用 RocksDB 后,链状态会以文件形式落在指定目录中,下次再启动节点时可以直接加载既有的数据库,而不是每次都从零开始。这在需要跨进程复用的开发场景(例如反复调试同一本地链、保留交易历史供后续查询)中非常实用。
创建或复用本地数据库
文档给出的核心用法是构造一个 NodeConfig,把 database_type 设置为 DbType::RocksDb(Some(path)),再通过 launch_custom_provider_and_get_wallets 启动节点。该示例源码位于 examples/cookbook/src/lib.rs:
use fuels::prelude::*;
let provider_config = NodeConfig {
database_type: DbType::RocksDb(Some(PathBuf::from("/tmp/.spider/db"))),
..NodeConfig::default()
};
launch_custom_provider_and_get_wallets(Default::default(), Some(provider_config), None)
.await?;
三个关键步骤:
- 构造
NodeConfig,仅覆盖database_type字段,其余字段沿用Default; DbType::RocksDb(Some(PathBuf::from(...)))指定数据库目录。若该路径下的数据库不存在,SDK 会在该路径创建一个新的数据库——因此同一个 API 同时覆盖"创建新库"和"复用已有库"两种场景;- 将配置作为第二个参数传入
launch_custom_provider_and_get_wallets。该函数定义在 packages/fuels-test-helpers/src/accounts.rs,签名为:
pub async fn launch_custom_provider_and_get_wallets(
wallet_config: WalletsConfig,
node_config: Option<NodeConfig>,
chain_config: Option<ChainConfig>,
) -> Result<Vec<Wallet>>
第二个参数 node_config: Option<NodeConfig> 为 None 时使用默认节点配置(即内存数据库)。
参数说明:DbType 与 NodeConfig
DbType 是一个双变体枚举,定义在 packages/fuels-test-helpers/src/node_types.rs:
#[derive(Clone, Debug)]
pub enum DbType {
InMemory,
RocksDb(Option<PathBuf>),
}
两个变体的含义:
InMemory:默认值,状态仅存在于进程内存中,进程退出即丢失;RocksDb(Option<PathBuf>):使用 RocksDB 持久化存储。注意其参数是Option<PathBuf>——传入Some(path)时数据库创建在指定路径;从源码结构看,若传入None,SDK 会回退到默认路径$HOME/.fuel/db(见下文二进制模式的参数构造逻辑)。
与之相关的 NodeConfig 字段同样定义在 node_types.rs,与 RocksDB 直接相关的有两个:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
database_type |
DbType |
DbType::InMemory |
选择内存库或 RocksDB |
max_database_cache_size |
Option<usize> |
None |
RocksDB 块缓存大小,None 表示不显式设置 |
其他字段(如 block_production、starting_gas_price、utxo_validation 等)控制出块触发方式、起始 gas 价格等行为,与本文主题无直接关系,此处不展开。
底层实现:两种运行模式如何落地
fuels-rs 启动本地节点有两条代码路径,由 Cargo feature fuel-core-lib 决定是否走进程内库模式,两条路径都会把 DbType 正确翻译成底层存储配置。
模式一:启动 fuel-core 二进制(默认)
当未启用 fuel-core-lib feature 时,SDK 通过 packages/fuels-test-helpers/src/fuel_bin_service.rs 以子进程方式拉起 fuel-core 可执行文件。在 ExtendedConfig::args_vec() 中可以看到 DbType 到命令行参数的映射(L43-L60):
args.push("--db-type".to_string());
match &self.node_config.database_type {
DbType::InMemory => args.push("in-memory".to_string()),
DbType::RocksDb(path_to_db) => {
args.push("rocks-db".to_string());
let path = path_to_db.as_ref().cloned().unwrap_or_else(|| {
PathBuf::from(std::env::var("HOME").expect("HOME env var missing"))
.join(".fuel/db")
});
args.push("--db-path".to_string());
args.push(path.to_string_lossy().to_string());
}
}
if let Some(cache_size) = self.node_config.max_database_cache_size {
args.push("--max-database-cache-size".to_string());
args.push(cache_size.to_string());
}
这段代码印证了三个事实:
DbType::InMemory对应--db-type in-memory;DbType::RocksDb对应--db-type rocks-db,并追加--db-path <path>;None时默认路径为$HOME/.fuel/db;max_database_cache_size仅在为Some时才追加--max-database-cache-size参数。
该模式的前提是 fuel-core 二进制存在于 PATH 中。源码通过 which::which_all("fuel-core") 查找可执行文件,找不到时会返回 no fuel-core in PATH 错误(L185-L191),这与文档末尾的 Note 完全一致。
模式二:进程内使用 fuel-core-lib 库
启用 fuel-core-lib feature 后,节点不再作为子进程运行,而是直接以库的形式跑在当前进程里。配置转换发生在 packages/fuels-test-helpers/src/service.rs 的 service_config() 中:
let combined_db_config = CombinedDatabaseConfig {
database_path: match &node_config.database_type {
DbType::InMemory => Default::default(),
DbType::RocksDb(path) => path.clone().unwrap_or_default(),
},
database_type: node_config.database_type.into(),
#[cfg(feature = "rocksdb")]
database_config: DatabaseConfig {
cache_capacity: node_config.max_database_cache_size,
max_fds: 512,
columns_policy: ColumnsPolicy::Lazy,
},
#[cfg(feature = "rocksdb")]
state_rewind_policy:
fuel_core::state::historical_rocksdb::StateRewindPolicy::RewindFullRange,
};
可以看到库模式下:
max_database_cache_size直接映射为 RocksDB 的cache_capacity;- 库模式还固定了
max_fds: 512、列策略ColumnsPolicy::Lazy与状态回退策略StateRewindPolicy::RewindFullRange,这些是 SDK 为本地测试场景预设的参数; - SDK 自己的
DbType通过From实现(node_types.rs L31-L39)转换为fuel_core::service::DbType,两条模式最终汇入同一套 fuel-core 存储抽象。
两条路径的分发点在 service.rs:FuelService::start() 根据 #[cfg(feature = "fuel-core-lib")] 决定调用 CoreFuelService::new_node(库模式)还是 BinFuelService::new_node(二进制模式),对上层 launch_custom_provider_and_get_wallets 的调用者完全透明。
启用条件:feature 开关与依赖
文档 Note 指出:要使用上述 RocksDB 示例,要么 PATH 中存在 fuel-core 二进制,要么同时启用 fuel-core-lib 和 rocksdb 两个 feature。从仓库配置看这一要求的传递链是:
- packages/fuels/Cargo.toml:
fuel-core-lib = ["fuels-test-helpers?/fuel-core-lib"]、rocksdb = ["fuels-test-helpers?/rocksdb"],即主包fuels把两个 feature 原样转发给测试辅助包; - packages/fuels-test-helpers/Cargo.toml:
fuel-core-lib = ["dep:fuel-core"]引入 fuel-core 库依赖,rocksdb = ["fuel-core?/rocksdb"]再打开 fuel-core 的 RocksDB 支持(编译 RocksDB 需要对应的 C/C++ 环境支持,这也是它被独立成 feature 的原因); - 示例工程 examples/cookbook/Cargo.toml 同样暴露了
rocksdb与fuel-core-lib两个 feature 供外部开启。
在 e2e 测试中,这条链体现为 e2e/Cargo.toml 的 fuel-core-lib = ["fuels/fuel-core-lib"] 与 rocksdb = ["fuels/rocksdb"]。
验证:仓库中的对应测试
文档引用的代码片段同时就是仓库中的端到端测试用例 create_or_use_rocksdb(examples/cookbook/src/lib.rs L215-L232)。其属性值得注意:
#[tokio::test]
#[cfg(any(not(feature = "fuel-core-lib"), feature = "rocksdb"))]
async fn create_or_use_rocksdb() -> Result<()> { ... }
该 cfg 条件的含义是:未启用 fuel-core-lib 时(走二进制模式)测试始终参与编译;启用 fuel-core-lib 库模式时则必须同时启用 rocksdb feature 才会编译。这与文档 Note 的启用条件表述互为印证,也说明该用例覆盖了"创建或复用 RocksDB 数据库"这一完整路径:配置 DbType::RocksDb(Some(PathBuf::from("/tmp/.spider/db"))) → launch_custom_provider_and_get_wallets 起节点 → 请求成功即视为通过。
小结与适用前提
- 只需把
NodeConfig的database_type改为DbType::RocksDb(Some(路径))即可让本地fuel-core节点把链状态持久化到磁盘,数据库不存在时会在该路径自动创建; - 可选通过
max_database_cache_size调整 RocksDB 块缓存,默认不设置;不指定路径时二进制模式回退到$HOME/.fuel/db; - 运行前提是:
PATH中可找到fuel-core二进制,或者同时启用fuel-core-lib与rocksdb两个 Cargo feature 走进程内库模式; - 本文内容基于当前仓库源码验证,涉及的关键文件为 examples/cookbook/src/lib.rs、packages/fuels-test-helpers/src/node_types.rs、packages/fuels-test-helpers/src/fuel_bin_service.rs 与 packages/fuels-test-helpers/src/service.rs。RocksDB 持久化主要面向本地开发与测试节点场景;面向生产环境时,文档建议通过 testnet 或自管节点配合
Provider连接真实网络,而不是依赖 SDK 内置的本地节点启动能力。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00