BTC SPV on CKB 需要的需求有:
- 更新必须进行合法性验证。
- 所有权和使用权分离。
- 尽量避免读写竞争问题。
- 可以用来验证 BTC TX 。
- 支持一定高度的 Revert (or Reorg)。
Refs:
SPV Client contracts 需要 4 个 Operations:
- Initialiaze
- Append
- Revert (or Reorg)
- Destory (only owner)
SPV Client 还需要提供 library,包含 1 个 function:
- Prove if a TXID in SPV Client.
一个 SPV Cell 的 Data 包含:
- index (用来做 Multi SPV Cells )
- min height
- max height
- hash of the max height header
- MMR root digest
- total diff from 0 to max height
使用 Multi SPV Cells 的设计,是为了解决上面需求中的 "3. 避免读写竞争" 和 "5. 支持 Revert" 。
将一个 BTC SPV Client 设计成
-
$N$ 个 SPV Cells-
所有 SPV Cells 的 min height 都是相同的,这里记做
$H_{min}$ 。 -
所有 SPV Cells 的 max height 都是不同的,分别是:
$H_{min} + a_{0}$ $H_{min} + a_{0} + a_{1}$ $\cdots$ $H_{min} + a_{0} + a_{1} + \cdots + a_{n-2}$ $H_{min} + a_{0} + a_{1} + \cdots + a_{n-2} + a_{n-1}$
其中
$a_{i} \gt 0$ ,代表每次更新 SPV 对应的 BTC height interval 。
如果每个 BTC block 都立刻更新,就是$a_{i} = 1$ 。如果同步服务出现了异常中断,再恢复时可以设置
$a_{i} \gt 1$ 来提速同步。
或者 reorg 的时候,不可能再去一个一个补,肯定也是一次多个 heights 快速同步,即$a_{i} \gt 1$ 。
-
-
$1$ 个 Index Cell由于有 Multi SPV Cells ,循环更新,所以需要:
- 每个 SPV Cells 里记录自己的 Index Number ,
- 有一个 Index Cell 来保存当前最新的一个 SPV Cell 的 Index Number 。
假设 Index Cell 里记录 Latest SPV Cell 的 index 为
- CellDep 包含:
- index 为
$t$ 的 SPV Cell
- index 为
- Inputs 包含:
- index 为
$t+1$ (如果$t+1 = N$ 则取 index 为$0$ ) 的 SPV Cell - Index Cell
- index 为
- Outputs 包含:
- index 为
$t+1$ (如果$t+1 = N$ 则取 index 为$0$ ) 的 SPV Cell 更新 Cell Data - Index Cell
将 index 修改为
$t+1$ (如果$t+1 = N$ 则为$0$ )
- index 为
- Witnesses 包含:
- 从 index 为
$t$ 的 SPV Cell 的 max height 开始的新的 headers 。
- 从 index 为
验证逻辑:
- 检查 Index Cell 里 index 为
$t$ - 检查 Witnesses 包含的 tip headers 是连续的,且验证 POW
- 检查 Witnesses 包含的 tip headers 可以和 index 为
$t$ 的 SPV Cell 连上 - 检查 将要更新的 SPV Cell 的 index 为
$t+1$
总结下,每次更新的时候需要检查 Input,CellDep 和 Output 的 index :
$i_{\mathrm{Output}} = i_{\mathrm{Input}}$ $i_{\mathrm{Output}} \equiv i_{\mathrm{CellDep}} + 1 \pmod{N}$ $i \in {0, 1, \dots, N-1}$
用户如果要验证一笔高度在
但建议选择 Index Cell 里记录的 Latest SPV Cell ,因为这个 Cell 的下一次更新时刻,距离当前时间最长。
这样可以 "3. 避免读写竞争" 。
用
假设目前要从
- CellDep 包含:
-
$C_{r}$ 的 SPV Cell
-
- Inputs 包含:
-
$C_{r+1}$ 的 SPV Cell -
$C_{r+2}$ 的 SPV Cell $\cdots$ -
$C_{N-1}$ 的 SPV Cell - 指向
$C_{N-1}$ 的 Index Cell
-
- Outputs 包含:
-
$C_{r+1}$ 的 SPV Cell 更新 Cell Data 为最新 tip 对应的数据 -
$C_{r+2}$ 到$C_{N-1}$ 的 SPV Cells 清空数据,等待后面 turns 再写入新数据 - Index Cell
修改为 指向
$C_{r+1}$
-
- Witnesses 包含:
- 从
$C_{r}$ 开始的,到要 reorg 到的最新 tip 之间的所有的 headers 。
- 从
验证逻辑:
- 检查 Index Cell 指向的是
$C_{N-1}$ - 检查 Witnesses 包含的 tip headers 是连续的,且验证 POW
- 检查 Witnesses 包含的 tip headers 可以和
$C_{r}$ 连上 - 检查 Witnesses 包含的 tip headers 比当前
$C_{N-1}$ 拥有 better total diff 。
如果 Reorg 操作受到 CKB Block Size Limit 或 Cycles Limit 影响无法做到,那么只能先强行进行 Revert 操作,然后重新同步。
考虑到单纯的 revert 意味没有验证 better total diff ,所以这个操作应该是需要 Owenrship 的。
我理解这个操作不可以有,因为违背了需求 "2. 所有权和使用权分离。" 。
所以对于 reorg 不了的,无论是
- 计算或数据 超出 CKB 的 limit ,无法验证;
- 还是预先 Multi SPV Cells 个数设置太少了, reorg 不到。
我的建议是用户应该另部署一套 SPV Client 。
用户如果需要在一个 script 里校验 TX 或 TXID 在 BTC chain 上(仅限于 SPV Cell 的 min height 和 max height 之间的 TX),则:
- CellDeps 包含:
- 包含 有该 TX 的 Block 的 SPV Cell
- Witnesses 包含:
- TX data (如果不需要验证 data ,可以直接用 TXID )
- TX 的 Merkle Proof
- TX 所在 Header
- TX 所在 Header 的 MMR Proof
验证逻辑:
- [Optional] 用 TX data 计算出 TXID 。
- 用 TX 的 Merkle Proof,TXID 和 Header 里的 merkle root 进行校验:TX 在 Header 里。
- 用 TX 所在 Header 的 MMR Proof, TX 的 Header 和 SPV Cell 里的 MMR root digest 进行校验:header 在 SPV Cell 里。
References:
context:
https://www.notion.so/BTC-b90f7341a6734c9490ae2171124500c2?d=47bec34d8962415e89ca247ccf2f4480&pvs=4#1cddc637eb7043fc9efebfb0f791e735
我对仅能验证 SPV Cell 的 min height 和 max height 之间的 TX 的原始需求抱有疑虑。