从 omnilock 讲起(五)

到这一篇,omnilock 本身的复杂度基本已经体现出来了,在构造交易和签名过程中需要注意的地方也基本列举并给出了参考代码,接下来麻烦的地方在于交易验证,不经过 vm 验证,始终是无法保证交易正常执行的。通常来说,一般交易会在链上验证,但想要在 ckb 测试网或者主网构造符合自己实验的交易有点复杂,通过本地 dev 网络也是一种办法,但需要自己启动一条 dev 链,我认为最好的方式应该是以单元测试的方法去构建测试,模拟连上数据和交易,通过 vm 进行验证。

交易验证

在做验证之前,需要找到 omnilock 对应的源码,编译成 binary,这样才能进行下一步。在验证过程中,最好是打开 omnilock 源码的 debug 模式,这样会有一些可能有用的 log 可以输出,当然,由于它的复杂性,可能有用的不是很多,但是,在 debug 过程中,可以在源码中加入 log 输出,辅助定位问题,针对特定问题,可以更快找到原因。所谓的 debug 日志,实际上就是在源码中加入 printf,可以将对应的上下文输出出来。

相应的,在 vm 端,也需要打开 log 输出,这就需要在 script 验证的地方加上 logger_printer,这样就能正常输出了。

常用的工具

模拟运行验证,需要一些上下文,去模拟链上环境,包括 dep cell、dep header、live cell 等等,在 vm 验证过程中能正确加载这些数据,才能正常进行模拟验证,一些常用的工具,比如 rust-sdk 中有 test_util 文件,crate 上也有 test-tools,都是对这些功能做了一些帮助性封装,使用起来会相对方便一点。

omnilock 的测试

从前几篇不难看出,omnilock 中大部分功能都是正交的,并且常用的 lock 模式中,除了相对简单的算法区别之外,还有解锁模式的区别,在测试的时候,需要尽可能将这些特性都覆盖到。

这里着重讲一下 ownerlock、exec、dl 三种模式,其他算法上的改变在前面已经细说过了,与正常的交易大差不差,没有很大差异,但这三种模式在测试和使用上,与一般的交易有很大的区别,需要稍微强调一下。涉及到的测试用例,在 PR 中都有。

Ownerlock

ownerlock 在生成的时候,就会在 script 的 args 上填好对应解锁的 lock 的 script hash,当用户想要解锁这个 ownerlock 的 cell 的时候,需要至少存在两个 input,一个是 ownerlock cell 本身,一个是 args 指向的 script hash 的 lock script 的使用 cell。也就是说,ownerlock 在生成的时候,就规定了是由哪一类 cell 进行解锁,只要在同一个交易中,该类型的 cell 解锁成功,那么 owner lock 就自动解锁了。

用示意图表示:

transaction:
 - input A
 	- lock A
 - input B
 	- ownerlock on omnilock
 		- args is lock A's hash
 - output C
 	- capture = input A + input B - 1 ckb
Exec

Exec 代指 ckb 的 syscall exec。使用这种模式的 cell,在生成时,指定了另外的 lock script 进行代理解锁,并将使用的 exec cell 的信息生成一个 preiamge 的 auth 放入 args 中,在解锁时,需要将对应的 script 的 cell 放在 dep cell 中,然后按该 cell 解锁的条件填入信息。

用示意图表示:

transaction:
  - dep cell A
  - input B
    - exec on omnilock
    	- args is exec preimage of A's auth
  - output C
  	- capture = input B - 1 ckb
Dl

DL 指 dynamic loading,它对调用库的 binary 有一定的格式需求。使用这种模式的 cell,在生成时,指定了另外的 lock script 进行代理解锁,并将使用的 dl cell 的信息生成一个 preiamge 的 auth 放入 args 中,在解锁时,需要将对应的 script 的 cell 放在 dep cell 中,然后按该 cell 解锁的条件填入信息。

用示意图表示:

transaction:
  - dep cell A
  - input B
    - dl on omnilock
    	- args is dl preimage of A's auth
  - output C
  	- capture = input B - 1 ckb

小结

这基本就是这个系列的最后一篇了。其实分开看,单一模式的 omnilock 并不复杂,ckb 的 transaction 构建也不复杂,但多算法聚合再加上一些特殊的模式,并且他们之间基本是正交状态,这些加起来就导致了 omnilock 的复杂性,只能慢慢拆解开,理解之后就相对容易了。

5 Likes