提交的是状态差异而不是交易流水:Starknet 的 state diff 怎么重建链 图 1
提交的是状态差异而不是交易流水:Starknet 的 state diff 怎么重建链 · 图 1

多数二层把每一笔原始交易原样发到一层,让人可以从头重放。Starknet 在数据这件事上选了另一条路:它往以太坊上提交的是证明加上状态差异,也就是 state diff——每个区块里”哪些值变了、变成了什么”,而不是”谁发起了什么”。省下一大笔一层数据费用是这条路的直接收益,但它同时也改变了”如何把这条链重建出来”这个问题的答案,而这个答案决定了不同角色各自需要什么。

差异而非交易:证明之外的另一半载荷

官方文档把这条链的定位说得很清楚:Starknet 是一台 validity rollup,把一批状态变更整理并证明之后,把最新的已证明状态更新到以太坊;随证明一起发送的,是前后两次状态之间的格式化差异,任何监听以太坊的人都可以用这份数据重建 Starknet 的当前状态。注意这句话的主语:可信来源是证明,state diff 提供的是”重建所需的原料”,两者角色不同。

差异的内容按版本有不同写法。在 v0.11.0 之前,state diff 逐合约列出存储更新,并附上合约部署信息,以 calldata 里一长串无符号整数数组的形式登记在以太坊上:先写部署了几个合约,再逐个给出地址与类哈希;接着是发生存储更新的合约数量,每个合约的自身地址,以及一个把”更新条数”和”新 nonce”打包进一个 256 位数的字段,然后是每个存储键及其新值。读这份数据要按顺序拆字段,少一位就全错。

到了 v0.13.1,往一层发送差异的方式从只用 calldata 改为 calldata 或 blob 二选一:正常情况下默认走 blob,只有在 blob 价格显著高过 calldata 的极端情形下,排序器才可能切回 calldata。这条切换规则对使用者的意义是:同一类数据在不同时段可能落在不同的数据载体上,用固定规则去扫一层的工具要能同时认两种位置。

能重建什么,不能重建什么

状态差异与证明一起上层的重建路径示意

从 state diff 出发,一个观察者可以按顺序把每条存储变更打进本地状态树,跟着最新已证明状态推进,得到与网络一致的状态根——这正是文档承诺的那件事。但它与”重放交易”之间有一层落差值得说清楚。差异里记录的是结果:某键变成某值、某合约的 nonce 前进到几。发起者是谁、用了什么 calldata、执行时读了哪些中间值,这些不在差异里。任何需要还原”事件发生过什么”的下游,仍要从别处取数据——一层上验证证明的那笔交易本身会留下痕迹,而完整的链历史在实现层面通常靠节点与 RPC 服务提供,而不再是早期那种查询排序器的 feeder gateway。

这决定了三种角色的需求完全不同。只想确认状态根的验证者,理论上只需要证明加上自己信任的验证合约;要跑一条链的节点,需要能持续拿到完整差异;要重建历史事件索引的服务,需要的东西比 state diff 更多。把这三件事混为一谈,是评价二层数据可用性时最常见的口径错误。

差异会过期吗

数据落在哪里,决定了它能被反复读多久。这一点在以太坊侧是明确的:calldata 作为交易的一部分会长期留在节点可见的数据里,blob 则有自身的保留窗口,过期后一层节点不再携带其内容。因此”链的历史还能不能从一层拿回来”这个问题,对走 blob 的时段和走 calldata 的时段答案并不相同,也需要区分”一层节点是否还带”与”是否有人另行归档”这两件事。文档层面能确认的是数据被放到了哪种载体,长期归档责任由谁承担,属于链的运营安排,应当查阅该链当期文档而不是从协议规则推定。

使用者该核对哪几件事

对普通使用者,这些机制不改变任何一次转账操作,但在两种场景里值得多看一眼。一是评估某个跨链或索引服务的可信路径:它是从一层的证明与状态根出发,还是直接信任某个 RPC 服务给出的当前值——两者在事故时的表现完全不同。二是遇到”数据查不到”时先定位是哪一层缺:一层交易哈希查得到而差异内容读不到,与整笔验证交易不见了,是两类不同的问题。

本文涉及的字段结构与版本行为来自 Starknet 官方文档对数据可用性与链参数的记载,该类内容会随版本调整;具体链的当前行为以官方文档当期描述为准。本文是协议机制解释,不构成任何投资建议。