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:
@xcshuan
现在的 Multi Cell 方案也暂时不需要在 Cell Data 里放 Headers 。
我说的也可以把数据放 Cell Data 里,是一个通用讨论,无论什么方案, Witnesses 如果不够用都可以走 Cell Data 。
强调下,目前的设计 Multi Cell 设计下,SPV 只提供 API 和一个 Cell :通过 Cell Dep 引用 Cell Data,然后调用 API , Proof 想放哪儿都可以。
总之,用于 Prove ,用户需要的是:
你的方案下,
用户需要,除了上面的 Proof 用的,还需要:
按照你说的:
不包含 Type Script ,没有 Cell Data ,总之,最简化的一个 2-in-2-out 的 secp256k1-blake160 交易的 size 是 597 (含了 witnesses )。
去掉 witnesses 也还有 560 ,假设 Client Data 本身还要 100 bytes ,就是 660 了 ,再加一个 type ,算 700 好了。
假设引用它的 tx 也是一个 2-in-2-out 的,那么不考虑用户业务占用的 witnesses ,就已经是一个大约 1300 bytes 的 Transaction (含了 witnesses , 其中 witnesses 算 700 ,比本身 tx 还大)。
一个怂人听闻的说法可以这么说:你这个设计使得 交易 尺寸 翻倍,使得 链 性能减半了。
用户随着自己的设计,Witnesses 里大概还要放自己的业务相关数据。
上面的 witnesses 算 700 还没考虑用户自己的数据呢。
Multi Cells 方案里,需要用户提供的数据,都是 CKB 确实没有的数据;你的方案的数据,对于 Chain 来说就是冗余数据。
而且以上 Proof 都是用一次,就要提交一次的(除非使用 Cell Data 先存 Chain 上)。
现在 mainnet 是 40Gib 的 DB, testnet 已经 128 GiB 。
不是和 BTC 比价格,也是资源浪费。
你的经济模型问题,我就不能理解了,现在是 N 个 SPV Cells 循环的模式,怎么会有公地问题?
假设用户的 各种 Proof 合起来过大了,在 Witnesses 里提交不了,放一个 Cell Data 提交 Proof,验证完 BTC Tx 自己回收掉就好了。
Summary
我觉得我和你的分歧,类比一下,就是,我相对更认同 Luke Dashjr ,我觉得这样利用 Witnesses 塞 冗余数据 ,是不好的。
同时我还觉得你的方案,点儿当年 ETH 的 io 指令 price 设置低了,被钻空子了的感觉,感觉 CKB 目前对 witness 太宽松了。
Update:
我的想法是:看了你的设计,我觉得应该提高 witness 的成本。
于是,我在 CKB Core 里问了下,有人说,“这个模式已经泛滥了,我记得很久之前提过,说是不处理,不知道现在有没有态度上的变化” ;有待进一步讨论。