首页
/ fuels-rs:使用 RocksDB 将 Fuel 节点链状态持久化到本地

fuels-rs:使用 RocksDB 将 Fuel 节点链状态持久化到本地

2026-09-05 13:16:31作者:卓炯娓

本篇指南基于 fuels-rs 官方文档中的 RocksDB 章节,讲解如何在 Fuel Rust SDK 的测试/本地节点中启用 RocksDB 数据库,把 fuel-core 节点的区块链状态持久化保存到磁盘并在后续复用。读完后你将掌握:NodeConfigDbType 的两种取值及其默认行为、数据库路径与缓存大小的配置方式,以及 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?;

三个关键步骤:

  1. 构造 NodeConfig,仅覆盖 database_type 字段,其余字段沿用 Default
  2. DbType::RocksDb(Some(PathBuf::from(...))) 指定数据库目录。若该路径下的数据库不存在,SDK 会在该路径创建一个新的数据库——因此同一个 API 同时覆盖"创建新库"和"复用已有库"两种场景;
  3. 将配置作为第二个参数传入 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_productionstarting_gas_priceutxo_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.rsservice_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.rsFuelService::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-librocksdb 两个 feature。从仓库配置看这一要求的传递链是:

  • packages/fuels/Cargo.tomlfuel-core-lib = ["fuels-test-helpers?/fuel-core-lib"]rocksdb = ["fuels-test-helpers?/rocksdb"],即主包 fuels 把两个 feature 原样转发给测试辅助包;
  • packages/fuels-test-helpers/Cargo.tomlfuel-core-lib = ["dep:fuel-core"] 引入 fuel-core 库依赖,rocksdb = ["fuel-core?/rocksdb"] 再打开 fuel-core 的 RocksDB 支持(编译 RocksDB 需要对应的 C/C++ 环境支持,这也是它被独立成 feature 的原因);
  • 示例工程 examples/cookbook/Cargo.toml 同样暴露了 rocksdbfuel-core-lib 两个 feature 供外部开启。

在 e2e 测试中,这条链体现为 e2e/Cargo.tomlfuel-core-lib = ["fuels/fuel-core-lib"]rocksdb = ["fuels/rocksdb"]

验证:仓库中的对应测试

文档引用的代码片段同时就是仓库中的端到端测试用例 create_or_use_rocksdbexamples/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 起节点 → 请求成功即视为通过。

小结与适用前提

  • 只需把 NodeConfigdatabase_type 改为 DbType::RocksDb(Some(路径)) 即可让本地 fuel-core 节点把链状态持久化到磁盘,数据库不存在时会在该路径自动创建;
  • 可选通过 max_database_cache_size 调整 RocksDB 块缓存,默认不设置;不指定路径时二进制模式回退到 $HOME/.fuel/db
  • 运行前提是:PATH 中可找到 fuel-core 二进制,或者同时启用 fuel-core-librocksdb 两个 Cargo feature 走进程内库模式;
  • 本文内容基于当前仓库源码验证,涉及的关键文件为 examples/cookbook/src/lib.rspackages/fuels-test-helpers/src/node_types.rspackages/fuels-test-helpers/src/fuel_bin_service.rspackages/fuels-test-helpers/src/service.rs。RocksDB 持久化主要面向本地开发与测试节点场景;面向生产环境时,文档建议通过 testnet 或自管节点配合 Provider 连接真实网络,而不是依赖 SDK 内置的本地节点启动能力。
登录后查看全文
热门项目推荐
相关项目推荐