菜单

存储系统

相关源文件

Fuel Core 存储系统提供了一个灵活的、支持事务的数据库层,为区块链状态提供支持。它同时支持持久化存储和内存存储,并具备历史状态访问能力。本文档解释了存储系统的架构、组件和关键概念。

有关基于此存储系统构建的数据模型的信息,请参阅数据模型

核心概念

  • 数据库类型:针对不同类型数据(链上、链下等)的不同数据库
  • :数据被组织成类型化列(类似于表)
  • 事务性存储:更改被累积并原子地提交
  • 历史状态访问:能够查询任何先前区块高度的状态
  • 存储后端:实现包括 RocksDB 和内存存储

来源:[crates/fuel-core/src/database.rs], [crates/fuel-core/src/state/data_source.rs]

存储架构

存储系统分为多层组织

  1. 高级数据库Database<OnChain>, Database<OffChain>
  2. 数据源:存储后端之上的抽象
  3. 存储后端RocksDbMemoryStore 等实现

数据库类型

Fuel Core 为不同类别的数据使用独立的数据库实例

  • 链上数据库:存储核心区块链数据(区块、事务、合约状态)
  • 链下数据库:存储索引数据以支持高效查询
  • 中继器数据库:存储与中继器功能相关的数据
  • 压缩数据库:存储压缩后的区块数据

每个数据库都实现了 DatabaseDescription trait(特性),该 trait 定义了其列、高度类型和其他特征。

来源:[crates/fuel-core/src/database/database_description], [crates/fuel-core/src/database/database_description/compression.rs]

数据库组织

数据被组织成(类似于关系数据库中的表)。每列存储特定类型的数据,并通过唯一 ID 标识。例如

数据库类型列类型示例列
链上链上列Fuel区块、事务、合约状态、消息
链下GraphQL 列持有的代币、事务状态、持有的消息 ID
中继器中继器列事件历史、DA 区块
压缩压缩列压缩区块

每列都由一个表蓝图进一步描述,该蓝图定义了键和值的编码、解码和访问方式。

来源:[crates/fuel-core/src/graphql_api/storage.rs], [crates/storage/src/structured_storage.rs]

存储后端

RocksDB 后端

主要的存储后端是 RocksDB,由 [crates/fuel-core/src/state/rocks_db.rs] 中的 RocksDb 结构体实现。它提供持久化存储,并具有以下特性:

  • 列族:每个逻辑列都映射到 RocksDB 列族
  • 前缀迭代:高效迭代具有共同前缀的键
  • 可配置缓存:控制区块缓存大小和其他参数
  • 压缩:LZ4 压缩以实现高效存储

The columns_policy 决定列族是惰性创建还是全部一次性创建

  • ColumnsPolicy::Lazy:仅在需要时创建列族
  • ColumnsPolicy::OnCreation:在数据库打开时创建所有列族

来源:[crates/fuel-core/src/state/rocks_db.rs:124-143]

历史 RocksDB

HistoricalRocksDB 扩展了基本的 RocksDB 实现,增加了历史状态访问能力。它提供:

  • 状态回溯功能:能够查看任何区块高度的数据库状态
  • 回溯策略:控制保留多少历史记录
  • 修改跟踪:记录反向更改以启用状态回溯

来源:[crates/fuel-core/src/state/historical_rocksdb.rs:76-87]

内存存储

对于测试和临时用例,MemoryStore 后端提供内存实现

  • 将数据存储在 BTreeMap 集合中
  • 实现与持久化存储相同的接口
  • 主要用于测试(不适用于生产环境)

来源:[crates/fuel-core/src/state/in_memory/memory_store.rs]

事务系统

存储系统采用事务模型,在原子提交之前将更改累积在内存中。

交易创建

事务通过 read_transaction()write_transaction() 方法创建

更改累积

对事务执行的操作在内存中累积

更改以嵌套映射结构存储

  • 列 ID → (键 → 写入操作) 的映射
  • 其中 WriteOperation 是 Insert(value) 或 Remove

提交更改

当事务提交时,更改将应用于底层存储

对于区块链数据库,提交过程还会:

  1. 验证高度单调递增
  2. 更新当前区块高度元数据
  3. 存储反向更改以供历史访问

来源:[crates/storage/src/transactional.rs], [crates/fuel-core/src/database.rs:490-628]

历史数据访问

存储系统的关键特性之一是能够访问历史状态。

基于高度的状态跟踪

系统跟踪每个区块高度的数据库状态

  • 每个数据库在其元数据中存储当前高度
  • 高度必须单调递增(不允许有间隙)
  • 提交过程强制执行正确的高度序列

指定高度视图功能

view_at 方法提供对历史状态的访问

历史访问的工作原理

历史访问通过以下方式实现:

  1. 存储还原每次更改所需的反向操作
  2. 在请求历史视图时检索这些操作
  3. 应用相关操作以在该高度重新创建状态

状态回溯策略

系统支持不同的历史数据保留策略

  • NoRewind:仅存储最新状态(最小存储使用)
  • RewindFullRange:保留所有历史状态(最大灵活性)
  • RewindRange:保留最近 N 个区块的历史数据(存储和灵活性的平衡)

来源:[crates/fuel-core/src/state/historical_rocksdb.rs], [crates/fuel-core/src/state/historical_rocksdb/view_at_height.rs]

GraphQL 集成

存储系统为 GraphQL API 提供专用适配器

数据库适配器

GraphQL 服务使用专用接口与存储交互

  • OnChainDatabase:访问区块链状态(区块、事务等)
  • OffChainDatabase:访问索引数据(余额、所有权信息等)
  • OnChainDatabaseAt/OffChainDatabaseAt:访问历史状态

这些接口抽象了存储细节,仅提供 GraphQL 解析器所需的功能。

GraphQL 工作服务

一个专门的工作服务处理新区块以更新链下数据库

  1. 监听新的导入区块
  2. 提取相关数据(所有权信息、余额等)
  3. 使用索引数据更新链下数据库
  4. 维护特殊索引以实现高效查询

这种链上和链下数据的分离允许高效查询,同时不影响核心区块链操作。

来源:[crates/fuel-core/src/graphql_api/worker_service.rs], [crates/fuel-core/src/service/adapters/graphql_api.rs]

关键接口

存储系统定义了几个提供不同功能的关键接口

存储访问接口

接口目的关键方法
KeyValueInspect对键值存储的基本只读访问get(), exists()
KeyValueMutate键值存储的写入操作put(), delete()
IterableStore存储内容的迭代iter_store(), iter_store_keys()
原子视图存储在某个时间点的原子视图latest_view()
HistoricalView访问历史状态view_at(), latest_height()
可修改提交更改的能力commit_changes()
TransactableStorage具有历史能力存储view_at_height(), rollback_block_to()

表访问模式

表在原始键值存储之上提供了一个更高级别的接口

这种模式利用 Rust 的类型系统,为存储中的不同数据类型提供类型安全的访问。

来源:[crates/storage/src/kv_store.rs], [crates/fuel-core/src/state.rs], [crates/storage/src/structured_storage.rs]

结论

Fuel Core 存储系统为区块链状态提供了坚实的基础,具有以下特点:

  1. 灵活的抽象层将高级数据访问与存储细节分离
  2. 事务性保证确保对区块链状态的原子更新
  3. 历史状态访问支持查询任何区块高度
  4. 高效的存储后端,RocksDB 针对区块链数据进行了优化

这种设计平衡了区块链执行层的性能、灵活性和可靠性要求。

来源:[crates/fuel-core/src/database.rs], [crates/fuel-core/src/state.rs]