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:
@yangby-cryptape
input * 2 = (32(tx_hash) + 4(index) + 8(since)) * 2 = 44, output * 2 = lock (32 + 1 + 20) + capacity(4) + lock (32 + 1 + 20) + capacity(4) + type(32+1+32) + output_data(100) = 279, cell_deps * 2 = 33 * 2 = 66, version = 4.
total = 393.
如果是MMR Cell进行循环队列的模式,那我觉得是OK的。
在整个CKB交易中,Witness, output_data 以及script args 是用户可以自由写入的区域,如果攻击者想要恶意占用网络带宽和大幅度增大历史存储,在这三项里写,攻击者付出的成本是相差无几的。因为即便 args 和 output_data 需要占用CKB,也因可随时解锁无限复用失去约束效果,所以不存在提高 Witness 成本的问题,如果要提高攻击成本,就应该抬高整个 1000 Shannon/KB 的 基础 feeRate,而不只是Witnesses的定价。
身份不明的攻击者正尝试对 Zcash 网络进行垃圾交易攻击,相比 Zcash,至少 CKB 拥有动态的费率调整,以及根据交易大小定价的机制。但CKB目前经济模型过度依赖于状态占用,而将 FeeRate 设置为一个极低的值,可能也不是一个合理的设计,其对于网络带宽,历史存储,全节点同步速度都有影响。
在进行历史裁剪时,由于隔离见证的设计,所有的Witness数据可以首先被裁剪,并且影响最小,从这个角度考虑,Witnesses 的 定价理应比 outputs_data 的 feeRate 便宜一些。