从零开始学习CKB:动手实践

我们已经在学习过了理论知识,下面让我们进入动手实践阶段。

第二步:动手实践

亲自上手摸摸 CKB 这条链,

才能更好体会到前面的理论知识。


我们已经在云端运行了一条测试链, 并预先生成了一些账户地址,方便这次教程的使用。

试试点击下面的按钮,查看这条链最新的区块。

Fetch Blocks

接下来我们准备了 3 个钱包。

试试看把鼠标移到钱包上,打开钱包。

☠️ 仅作为演示用途,请勿在正式场合或主网下使用这些钱包

钱包 1

mainet:        ckb1qyqy84gfm9ljvqr69p0njfqullx5zy2hr9kqjynwlg 
testnet:       ckt1qyqy84gfm9ljvqr69p0njfqullx5zy2hr9kq0pd3n5 
lock_arg:      0x43d509d97f26007a285f39241cffcd411157196c
private_key:   0xdd50cac37ec6dd12539a968c1a2cbedda75bd8724f7bcad486548eaabb87fc8b

钱包 2

mainet:        ckb1qyqf22qfzaer95xm5d2m5km0f6k288x9warqwjwke8 
testnet:       ckt1qyqf22qfzaer95xm5d2m5km0f6k288x9warqnhsf4m
lock_arg:      0x952809177232d0dba355ba5b6f4eaca39cc57746
private_key:   0x6cd5e7be2f6504aa5ae7c0c04178d8f47b7cfc63b71d95d9e6282f5b090431bf

钱包 3

mainet:        ckb1qyqtxvjgczx9tmtrd5hsp5r96g37cxsdxvaqp6culx
testnet:       ckt1qyqtxvjgczx9tmtrd5hsp5r96g37cxsdxvaqulxrn6 
lock_arg:      0xb33248c08c55ed636d2f00d065d223ec1a0d333a
private_key:   0x8ca6891c2386d71a6206f1d56888b48a4ee335ca8b03ed04ac31b143c0d8c609

每个钱包有四条信息,其含义如下:

  • mainnet,表示钱包的主网地址。
  • testnet,表示钱包的测试网地址。本次教程我们只会用到 testnet 地址。
  • lock_arg,是钱包对应的公钥哈希的前20位。你可以简单把它理解成公钥的指纹。
  • private_key,是钱包的私钥。你不应该像我这样把它暴露出来。

在本次教程中,这 3 个钱包将被我们用于发送交易、部署合约等各种用途。


现在,你可以通过下面的按钮,选择其中任意一个钱包,查看这个钱包相关的 Cell 和交易。

image-20210502184647285

点击上面任意一个 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 表明这条链是测试链,而不是主网。

scripts 里代表的则是链内置的智能合约,也就是 type 和 lock 可以利用的系统内置的一些锁。

每条 CKB 链都会预先在创世块部署几个系统内置的智能合约,上面显示了3个系统合约的具体信息。

  • SECP256K1_BLAKE160:是系统默认使用的 Cell 的 lock 锁的合约,用来保护 Cell 的所有权
  • SECP256K1_BLAKE160_MULTISIG:是 SECP256K1_BLAKE160 的多签版本
  • DAO:NervosDAO 合约,暂时可以不用管

好了,这就是我们所有必须了解的信息了。

接下来,我们将开始构建并发送第一笔交易!

发送一笔交易

我们将在本节内容学会并亲自动手完成一笔最基础的转账交易。

在开始之前,让我们在黑板上再次重写一遍:

一笔CKB的交易,无非是消费一些已有的 live cell,去创造出另一些新的 live cell。

同时,因为 CKB 采用的是“链下计算、链上确认”的设计,所以我们在转账的时候,甚至可以采用手动拼贴交易的方式,去完成一笔转账操作。

只要我们事先拟好交易的内容(也就是注明这笔交易要消费哪些cell、创造出什么样的新cell),然后用相应的私钥对交易进行签名, 当这笔交易被提交到链上,只要验证通过、签名有效,那么交易就会被打包完成。

这种手动拼贴交易的方式意味着什么呢?

在 CKB 这种体系下,其实我们人肉组成了一个 layer2 网络。

想象现在你有一位朋友住在亚马逊丛林里,他独自生活,身边只有一台离线的电脑,没有网络,与世隔绝。

某天下午他打猎归来,突然想起来还欠你一点钱,他打开电脑,想转给你 1 万个 CKB 还债。

尽管没有网络,他还是把转账交易的内容写在了一张纸上,然后在电脑里输入自己的私钥,计算出了这笔转账相应的签名,最后把签名也附在了纸上。

过了半个月,当有信差来访时,他托人把这张纸邮寄到中国,又过了半个月,信纸终于送到了你的手上。

你看着信纸,交易确实指明创造 1 万 CKB 的 cell 给你,你决定把这笔交易提交到 CKB 主网上。 主网验证附上的签名有效,于是交易完成,你的账户里多了一万个CKB,债务两清了。

你和亚马逊丛林的朋友共同组成了一个包含 2 个节点的 layer2 网络,虽然这个网络的吞吐量只有 1 笔交易/每月。

尽管 CKB 目前已经有了各种各样的工具,帮助你自动构建交易、完成转账、部署合约,等等, 但接下来,我们还是会延续亚马逊朋友的这种方法,来实现一笔普通的转账交易。

目的是使用手动拼接交易的方式,让你更深刻的理解 CKB cell 的工作原理。

我们将使用 JSON 格式来手动拼接交易。

交易的 INPUT

下面是钱包 1 的 4 个 live cell,直接把 cell 拖到下面的框中,看看自动生成的 input 是什么样子的。

image-20210502185111754

你可能看到了,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 是什么样子了。

image-20210502185453333

你应该注意到了,交易中的 outputs把新生成的 cell 的信息都写出来了,包括 capactiy 大小、lock 锁等信息。

但 output 中的 cell 并没有指明 data 的信息,相反,data 被统一挪到了outputs_data 字段中,按顺序对应 outputs 中的 cell。

这样做也是出于性能优化角度来设计的。

最后,一笔完整的交易还包括 versionheader_deps 两个字段。 前者为版本信息,目前固定设置为 0x0 ,后者暂时不用管,放空就行。

对交易进行签名

一笔转账拼好之后,需要用相应的私钥,对这笔交易进行签名,表明我们确实是 cell 的主人,有权对这些 cell 执行操作。

签名将被放入一个新的名为 witnesses 的字段中,作为交易的证明。

到这里你已经完整了解了一笔交易的过程,我们马上开始动手发交易。


现在,把下面白框中的空白交易填满。

把它当作一次练习,自己用手动的方式填写一笔转账交易。

你可能需要用到查找钱包对应的 live Cell、查看链配置信息(用来填写 cell_deps)、16 进制与 10 进制互相转换这些功能,它们在工具箱中都可以找到。

点击👇 Nervos 的图拍呢 ,即可打开工具箱。

image-20210502185812767

将下面的交易补充完成

{
      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 已经可以提前确定出来。

点击下面的按钮,试试生成生成交易的哈希。

image-20210502185630564

尽管这笔交易已经可以提前生成 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。

image-20210502185937873

开始签名

有了 message,以及钱包里的私钥,我们就可以计算出签名了。

image-20210502185949180

把签名放回到交易中

把生成的签名填入下面的输入框中,点击按钮,以 witnessArgs 的形式做一遍序列化:

image-20210502190016609

现在我们可以完善原本的交易了,把序列化好的签名放进 witnesses 字段里:

最后一步,把交易发送到链上

image-20210502190050699

注意看下,交易成功上链后返回的 tx_hash,是不是和之前事先生成的那个 tx_hash 一模一样?

CKB 的确定性诚不欺我。

现在,你可以通过下面的按钮,看看刚才我们发送的交易是不是真的在链上了。如果提示 tx_status: pending , 则表明交易还在pending,稍后重试就可以了。

image-20210502190117775

最后恭喜你,成功完成了第一小节的内容~

原文链接

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 2021-04-28 17:15
  • 阅读 ( 82 )
  • 学分 ( 0 )
  • 分类:Nervos

0 条评论

请先 登录 后评论
CKBFans
CKBFans

3 篇文章, 15 学分