我们已经在学习过了理论知识,下面让我们进入动手实践阶段。
点击上面任意一个 Cell 或者任意一笔交易,你会看到 JSON 格式的详细信息。
当我们在说,一个钱包拥有多少 CKB (原生代币)的时候,我们其实指的是,这个钱包能够解锁的所有的 live Cell 的 capacity 之和,也是这个钱包在链上占有的总存储空间。
现在,钱包 1 是云端这一条测试链默认的矿工地址。
也就是说,钱包 1 将源源不断收到来自挖矿所获得的出块奖励。所以你会看到钱包 1 查找出来的 live Cell 是最多的。钱包 2 和钱包 3 只有很少、甚至还没有 live cell。
目前,测试链只有一个矿工。
最后,我们还需要知道这条测试链的配置信息。
测试链的配置信息
{ "PREFIX": "ckt", "SCRIPTS": { "SECP256K1_BLAKE160": { "CODE_HASH": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", "HASH_TYPE": "type", "TX_HASH": "0x4f1097802dc6fe19b942f1c2e8e52d564ee35899e4aef308101c86c49bc1f471", "INDEX": "0x0", "DEP_TYPE": "dep_group", "SHORT_ID": 0 }, "SECP256K1_BLAKE160_MULTISIG": { "CODE_HASH": "0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8", "HASH_TYPE": "type", "TX_HASH": "0x4f1097802dc6fe19b942f1c2e8e52d564ee35899e4aef308101c86c49bc1f471", "INDEX": "0x1", "DEP_TYPE": "dep_group", "SHORT_ID": 1 }, "DAO": { "CODE_HASH": "0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e", "HASH_TYPE": "type", "TX_HASH": "0x075c01b717840fd37fcf4a2f1b1bcdbf7c26f9c4781855bb772ac9d1a57eb2f0", "INDEX": "0x2", "DEP_TYPE": "code" } } }
prefix:ckt
表明这条链是测试链,而不是主网。
你可能看到了,input 中的 cell 是以 previous_output
的形式出现的, 传入的是 tx_hash 和 index 组成的 outpoint,相当于是对 cell 的一个索引,或者像 cell 的一个指针,通过 outpoint 我们找到想要消费的 cell。
inputs 中还有一个字段叫 since
,它是用来控制时间的,我们暂且不必管它。
除了inputs,还有一个字段叫 cell_deps
,它是一笔交易中需要依赖的 cell, 也是以 outpoint 这种索引结果出现的。
什么是需要依赖的 cell 呢?
比如在普通的转账交易中,lock 锁需要用到固定的加密算法 SECP256K1_BLAKE160,也就是系统内置的一个智能合约, 这个加密算法的代码存放在某个 cell 中,就需要在 cell_deps 中引用进来, 这样 CKB-VM 虚拟机才能知道从哪里载入代码进行运算。
通过上文测试链的配置信息,我们很容易找到 cell_deps 中需要传入的参数。
交易的 OUTPUT
接下来我们再使用另一个工具,看看生成的output、以及一笔完整的交易长什么样子。
同样,把钱包 1 的 cell 拖到 input 中。
output 方框内将马上自动生成一个相同大小的新 cell。
点击 output 中的设置按钮,可以对新生成的 cell 进行重新分配,包括生成几个 cell、设置每个新 cell 的大小,设置每个 cell 的解锁地址,等等。
output 占用的 capacity 空间必须小于 input,二者的差值即为矿工能挣到的手续费。
设置完成后,点击“生成交易”的按钮,就可以看到这笔交易的 JSON 是什么样子了。
你应该注意到了,交易中的 outputs
把新生成的 cell 的信息都写出来了,包括 capactiy 大小、lock 锁等信息。
但 output 中的 cell 并没有指明 data 的信息,相反,data 被统一挪到了outputs_data
字段中,按顺序对应 outputs 中的 cell。
这样做也是出于性能优化角度来设计的。
最后,一笔完整的交易还包括 version
和 header_deps
两个字段。 前者为版本信息,目前固定设置为 0x0 ,后者暂时不用管,放空就行。
对交易进行签名
一笔转账拼好之后,需要用相应的私钥,对这笔交易进行签名,表明我们确实是 cell 的主人,有权对这些 cell 执行操作。
签名将被放入一个新的名为 witnesses 的字段中,作为交易的证明。
到这里你已经完整了解了一笔交易的过程,我们马上开始动手发交易。
现在,把下面白框中的空白交易填满。
把它当作一次练习,自己用手动的方式填写一笔转账交易。
你可能需要用到查找钱包对应的 live Cell、查看链配置信息(用来填写 cell_deps)、16 进制与 10 进制互相转换这些功能,它们在工具箱中都可以找到。
点击👇 Nervos 的图拍呢 ,即可打开工具箱。
将下面的交易补充完成
{ version: "0x0", cell_deps: [ { out_point: { tx_hash: "将此处补充完整", index: "将此处补充完整", }, dep_type: "将此处补充完整", }, ], header_deps: [], inputs: [ { since: "0x0", previous_output: { tx_hash: "将此处补充完整", index: "将此处补充完整", }, }, ], outputs: [ { capacity: "将此处补充完整", lock: { code_hash: "将此处补充完整", hash_type: "将此处补充完整", args: "将此处补充完整", }, }, ], outputs_data: ["0x"], witnesses: ["0x"] }
保存
填写完成后,点击保存按钮。
好了,到这里你已经手动把交易全部填好了。
这时我们已经可以为这笔交易生成一个独一无二的哈希了,也就是 tx_hash 已经可以提前确定出来。
点击下面的按钮,试试生成生成交易的哈希。
尽管这笔交易已经可以提前生成 tx_hash,但它现在仍然是一笔 raw_tx。raw_tx 跟 tx 最大的不同是, tx 会在 witnesses 字段中放入交易的签名。
事实上,你可以在 witnesses 里放入任何你需要的参数或者证明。而且因为它是一个数组,还可以放入多个证明。 但因为现在我们在尝试的是系统内建的转账交易, 这种交易互相约定会在每一组 witnesses 的第一个位置,放入这样一个结构:
{ "lock": "证明", "input_type": "证明", "output_type": "证明" }
这一个结构被称为 WitnessArgs。不同的锁会从 WitnessArgs 不同的字段中读取自己需要的签名。 其中,lock 字段是 input 使用到的 lock 锁需要验证的签名。 在我们现在要实验的普通转账交易中,就是 SECP256K1_BLAKE160 算法需要验证的签名。
input_type 和 output_type 则是 input 和 output 中 type 锁需要验证的签名,暂时不必管它。
签名是一个比较繁琐的过程。更详细的技术细节在这里:How to sign transaction
现在,为了完成签名,让我们首先为这笔交易生成一个待签名的 message。
开始签名
有了 message,以及钱包里的私钥,我们就可以计算出签名了。
把签名放回到交易中
把生成的签名填入下面的输入框中,点击按钮,以 witnessArgs 的形式做一遍序列化:
现在我们可以完善原本的交易了,把序列化好的签名放进 witnesses 字段里:
最后一步,把交易发送到链上
注意看下,交易成功上链后返回的 tx_hash,是不是和之前事先生成的那个 tx_hash 一模一样?
CKB 的确定性诚不欺我。
现在,你可以通过下面的按钮,看看刚才我们发送的交易是不是真的在链上了。如果提示 tx_status: pending , 则表明交易还在pending,稍后重试就可以了。
最后恭喜你,成功完成了第一小节的内容~
原文链接