Block State 与 Block Event 表
BlockDB 将链上数据抽象为两种核心逻辑模型:Block State 表与Block Event 表。它们以”区块”为数据单位,理解链上语义,用户不需要自己管理区块高度、数据覆盖与分叉回滚。1. 模型定义
Block State 表:单行状态模型
定义:用于存储链上实体的最新状态,以及所有历史高度的状态。每当新高度的数据进入,BlockDB 会保存该高度的历史快照,并异步更新最新状态表。- 设计哲学:以唯一实体(如地址、合约)为主键,每次写入覆盖上一次状态,但底层保留历史快照。
- 典型场景:用户地址的代币余额、智能合约当前状态变量、NFT 当前持有人。
- 系统内置字段:自动维护
block_id、block_height、block_timestamp,支持状态的历史版本回溯。
Block Event 表:事实记录模型
定义:用于存储链上发生的每一条事件。- 设计哲学:数据只读且追加(Append-only),每一行代表一个确定发生过的链上事实,不可修改。
- 典型场景:代币转账流水(token_transfer)、合约事件、交易所每笔撮合记录。
- 系统内置字段:自动维护
block_id、block_height、block_timestamp。
_archive 表。链上事件在特定高度发生后就是唯一、不可变的,没有”更新”的概念,只有”追加”。
业务抽象表底层的派生表(
_archive、_height 等)可以像普通表一样通过 GetRow / BatchGetRows / FilterRows 直接读取,便于排查数据。但禁止使用 UpsertRows 等普通表写入 API 直接修改派生表——所有写入必须通过 Block 表自身的区块写接口完成。2. 数据逻辑类型
建表时,除主键id 外,业务属性列可以声明为任意逻辑类型。完整的逻辑类型清单见参考。这里介绍与区块链强相关、且长度遵循 EVM 约定的类型:
ADDRESS、TXID、BLOCKID、TOKENID 等固定长度十六进制类型,在 BlockDB API 边界以 0x 十六进制字符串表示,底层存储为定长字节,长度与 EVM 约定及 BlockDB 的代码定义对齐;具体数值以参考与实现为准。- ID(主键):必须名为
id。 - 业务属性列:可添加任意多列,任意逻辑类型皆可。
- CHAINID:标识该数据属于哪条链。
3. 起始高度与共识高度
起始高度(Start Height)
起始高度是用户为该表设置的、所管理区块链数据的开始高度。- 用户的表很可能不需要从 0 高度开始维护数据。例如某个合约从某个高度才出现,用户可以把该高度设为起始高度,只维护该高度之后的数据。
- 不设置时,默认起始高度为
0。
共识高度(Consensus Height)
共识高度是用户数据从起始高度开始、连续覆盖到的高度区间的右边界。- 只要数据从起始高度起连续写入、没有断档,共识高度就会持续推进。
- 它是
GetState、GetEvent等接口可以安全查询的最高高度口径——在这个高度之内查询,保证不会因缺数据而得到错误结果。
读取时传入的
current_block.height 必须 ≤ 表的共识高度(即 _height 表从起始高度起连续覆盖到的最高高度),才能保证读取结果的正确性。4. 核心特性
区块粒度写入的 ACID 保证
BlockDB 的写入以区块为最小原子单位:- 原子性(A):一个区块内的数据要么全部写入成功,要么全部失败,不会出现”半个区块”的脏数据。
- 一致性(C):写入始终按区块粒度完整替换该高度之前的数据——该高度的数据是一份完整、确定性的快照,读取不会看到中间状态或部分写入。
- 隔离性 / 持久性:多并发写入以区块为粒度协调,提交后的数据可持久读取。
历史高度回溯(Time-travel Query)
读取 API 原生支持AS OF BLOCK <height> 语义。即使 State 表存的是最新余额,也能一行代码查询任意历史区块高度下的值。
实时事件订阅(下游联动)
每次按区块写入成功,BlockDB 自动产生区块写入事件,下游任务可实时、增量地处理每个区块高度产出的数据,构建多级级联的事件驱动数据管道。零感知的自动分叉处理(Auto-Reorg)
当底层链发生分叉(Reorg)需回滚 N 个区块时,BlockDB 基于隐式维护的区块列自动撤销分叉区块的写入,删除 Block Event 表相关事件,保证 Block State 表最终一致。Reorg 免维护。总结
在链上数据生产场景中,请优先选择创建 Block 表来管理链上数据。