用户数据全部存储在chaintable的BlockDB数据库中,所有用户表的创建和管理,都是由BlockDB这个组件完成的。
什么是BlockDB
BlockDB解决的核心痛点: 区块链数据获取面临三个难题:状态难追溯(不知道过去某个时刻的余额)、事件难同步(链上操作零散,对不同区块事件处理的先后顺序有要求)、链路太长(需要搭建复杂的 ETL 队列)。 BlockDB 的定义: BlockDB 是专为区块链设计的“逻辑多模型数据库”。它在底层(在线表)提供标准在线数据库的存储能力,在逻辑层提供开箱即用的“链上语义表”(Block表)。 BlockDB对用户提供的核心能力:- **链上数据特化:**用户可以通过Block表直接查询任意时刻的链上状态,或者订阅任何合约的实时变动,无需理解底层复杂的区块回滚(Reorg)和数据管理逻辑。
- 在线数据库, 传统的 ETL 需要先离线计算再导出到在线库。在 ChainTable,BlockDB 即在线库。
- 事件订阅能力:BlockDB的通过提供表的事件订阅能力,使用户可以自由处理任何上游表的实时数据,让业务代码像“虚拟智能合约”一样运行在数据库的变更流上。
架构模型—BlockDB的“两层楼”
BlockDB在架构上分为两层的表模型:-
存储层---普通在线表
- 提供实时读取,高吞吐写入基础能力
-
业务抽象层---区块链场景的特化逻辑表
- 提供链上数据存取场景的定制化能力,业务抽象层是BlockDB的核心功能
Level 1:存储层
存储层负责创建和维护在线数据库表,可以称为普通表。 对用户而言,用户创建普通表,用于存储:- 非链上的业务数据,辅助数据处理。
- 链上数据处理后的高价值数据,支持在线应用搭建。
- 用户创建level 2的区块链逻辑表时,level 1层实际会为逻辑表创建1个或者多个普通表
-
核心操作:
-
GetRow/FilterRows:快速精准地获取特定行或按条件筛选。 -
UpsertRows:高并发、异步地批量插入或更新数据。 -
DeleteRows:批量清理过期或无效数据。
-
todo,存储层也支持事件订阅,但是非核心feature,先不表。Scan也没提
Level 2:业务抽象层
这是专门为“链上数据”定制的逻辑模型。目前有Block State表,Block Event表两个逻辑模型。 当你在 Level 2 创建一个 Block 表时,BlockDB 并没有在存储引擎上创建一个表,而是自动在 Level 1 创建了多个互相协作的普通表。-
“影子表”机制:
-
不同逻辑模型,会映射成多个普通表,具体映射关系:
-
L2
onchain_state→ L1onchain_state(查最新值)、onchain_state.archive(查任意历史值)、onchain_state.height(查处理高度情况) -
L2
onchain_event→ L1onchain_event(查任意事件)、onchain_event.height(查处理高度情况)
-
L2
-
不同逻辑模型,会映射成多个普通表,具体映射关系:
-
双重操作能力:
- 高级模式 (Level 2 API):用户使用“链上语义”操作(例如:按区块粒度原子性写入数据,按区块时刻读取state记录),简单省事,系统自动拆解并操作底层的三个表。
-
专家模式 (Level 1 API):用户也可以直接通过
GetRow等 API 绕过 L2,直接对底层的三个 Online 表进行操作(通常是读取操作)。
-
核心操作:
- GetState/GetEvent:按区块时刻读取state记录,event记录。
- GetBlockData:获取表的任意区块的全部数据。
- BlockWrite:按区块粒度原子写入新数据。
- SubscribeTableEvent:实时订阅表的区块处理事件。
深入理解Block表
Block State表:单行状态模型
定义: 用于存储链上实体的最新状态以及所有历史高度状态。每当有新高度的数据进入,blockDB保存历史高度数据并且异步自动处理最新状态表的更新。**Schema **
用户只需定义最核心的业务列,BlockDB 会自动补全运维列:-
ID (主键):必须名为
id,类型为String。 - 业务属性列:用户可以添加多列,任意逻辑类型皆可。
- CHAINID:标识该数据属于哪条链。
物理存储实现 (L1 层映射)
在底层,BlockDB 会自动驱动三张普通表来保障数据的完整性:| 表名 | 角色 | 核心 Schema 特件 | 业务场景 |
|---|---|---|---|
$table_name | 最新状态表 | 包含 id、业务列、Height、blockID、Blocktimestamp。 | 实际用户的索引,也是应用在最新状态表。查询此时此刻的最新余额。 |
$table_name.archived | 历史快照表 | 主键为 hash(id, height)。包含原始 ID 和历史每一个变动点的数据。 | 追溯用户在 1 个月前链上的资产状态。 |
$table_name.height | 进度管理表 | 记录 [start, end] 闭区间,标注哪些高度区间已成功处理。 | 检查数据是否连续,是否有“断档”。 |
- 最终一致性,BlockDB会同步更新历史快照表和进度管理表,然后异步更新最新状态表
Block Event表
**定义:**用于存储用户关心的区块链上的每一条事件。 用户只需定义最核心的业务列,BlockDB 会自动补全运维列:-
ID (主键):必须名为
id,类型为String。 - 业务属性列:用户可以添加多列,任意逻辑类型皆可。
- CHAINID:标识该数据属于哪条链。
.archived 表
- 逻辑背景:因为链上事件(如一笔转账、一次授权)在特定高度发生后就是唯一的、不可变的。它没有“更新”的概念,只有“追加”。
-
$table_name:存储所有原始事件数据。 -
$table_name.height:同样维护处理进度,确保开发者知道哪些区块的事件已经被拉取。
Block表的事件订阅能力
每次用户调用BlockWrite API写入Block表成功,BlockDB会自动产生一个区块写入事件 (BlockWriteEvent)。 事件包含关键信息:- Table Name:哪个Block表更新了
- Block信息:关联的区块高度和区块哈希
- Data Hash:这一批写入行数据的整体哈希值
- Data Hash等于0值,意为订阅表当前高度没有产出数据,只表达该高度计算完成
- 携带Data hash和Block信息调用Block表数据读取API,BlockDB会使用高速缓存,快速返回表指定区块的所有数据行
- 事件驱动的处理循环:同步出块的节奏
- BlockDB 的方式:数据库的每一次写入(BlockWriteEvent)都对应着一次区块链的真实出块。这意味着你的业务系统不再是“追赶”区块链,而是成为了区块链计算链条的一部分。每出一个块,数据自动流向下一站。
- 从表到表的“ETL 流水线”
Block表核心优势总结
| 维度 | 传统方式处理链上数据 | BlockDB 模式 |
|---|---|---|
| 实时性 | 手动同步,存在分钟级延迟 | 区块级同步,毫秒级感知 |
| 开发难度 | 理解区块,学习合约,从源头开始处理 | python API 开发,在数据库层面操作读写,可以订阅解码和建模后的数据表 |
| 链路复杂度 | 维护队列、离线脚本、中间表 | 表与表直接驱动,天然的加工链路 |
| 一致性 | 自己处理多表更新,自己处理reorg | BlockDB 会原子化地更新block表,reorg免维护,BlockDB自动撤销数据更改 |