Chialisp - CHIP编号 | 0011

该CHIP提案旨在为CLVM添加新的操作符,以增强签名功能,例如支持更复杂的BLS操作、零知识证明、计算找零等,同时引入新的SOFTFORK条件。这些操作符将分阶段引入,最初通过softfork guard访问,最终成为核心CLVM的一部分。此外,还通过硬分叉增加了新的AGG_SIG条件以支持不同的消息组合,并对块生成器进行了优化。

CHIP 编号 0011
标题 BLS/SECP CLVM 操作符和 SOFTFORK 条件
描述 添加 CLVM 操作符以增强签名能力;同时添加新的 SOFTFORK 条件
作者 Cameron Cooper, Arvid Norberg, Dan Perry
编辑 Freddie Coleman
评论-URI https://github.com/Chia-Network/chips/wiki/Comments:CHIP-0011
状态 最终
类别 标准跟踪
子类别 Chialisp
创建日期 2022-12-16
要求 0012
替换
取代者

摘要

此 CHIP 将向 CLVM 添加一组新的操作符。这些操作符将启用复杂的 BLS 操作,以及诸如 ZK 证明、计算余数的能力、从其组成部分计算 coin ID 的能力以及验证 secp 签名的能力等新功能。最初,这些操作符将通过 softfork 保护来访问。稍后,它们将成为核心 CLVM 的一部分。

此 CHIP 还将添加一个新的 SOFTFORK 条件,该条件在 CHIP-12 的硬分叉激活后可用。此分叉还将添加创建具有成本的新 CLVM 条件的能力,以及六个新的 AGG_SIG 条件。

定义

在本文档中,我们将使用以下术语:

  • Chialisp - 用于构建 Chia coin 的高级编程语言
  • CLVM - Chialisp 虚拟机,编译后的 Chialisp 中的字节码在此处执行。通常也指编译后的字节码本身
  • BLS - Boneh–Lynn–Shacham,一种支持聚合的数字签名方案。自从主网启动之前,Chia 一直在使用 BLS 密钥
  • secp - 来自 高效密码学标准 的一组椭圆曲线
  • G1 - BLS 椭圆曲线上的第一组点;用于保存公钥
  • G2 - BLS 椭圆曲线上的第二组点;用于保存数字签名
  • Gt - G1 和 G2 点的目标群,定义为 G1 x G2 → Gt
  • ZK 证明 - 零知识证明,一方(证明者)可以向另一方(验证者)证明给定的陈述是真实的,同时证明者避免传递除该陈述确实属实之外的任何附加信息的方法

动机

CLVM 当前包含一个名为 point_add 的 BLS 操作符。此操作符用于 G1 加法,并且是支持合成密钥所必需的。但是,CLVM 缺少执行更复杂操作(例如签名验证)所需的操作符。

此 CHIP 将向 CLVM 添加一组新的操作符,以便利用 BLS 签名的全部功能。例如,新的操作符将添加验证签名和使用 ZK 证明的功能。

此外,CLVM 当前缺少一种在验证其组件时计算 coin ID 的方法。为了解决这个问题,将向 CLVM 添加一个新的操作符,该操作符从其父 coin ID、puzzle-hash 和金额计算 coin ID。如果任何参数无效,则该操作符将失败。

CLVM 还缺少直接从除法计算余数以及从指数运算的除法计算余数的操作符。为了解决这个问题,将添加两个新的操作符。

最后,CLVM 当前缺少验证 secp 签名的能力。为了解决这个问题,将向 CLVM 添加两个新的操作符,一个用于验证 secp256k1 签名,另一个用于验证 secp256r1 签名。

CLVM 是一种可扩展的链上编程语言,因此添加新的操作符并不是很大的技术挑战。

向后兼容性

以下是关于此 CHIP 与当前 CLVM 实现的兼容性的一些注意事项:

  • 要添加的 CLVM 操作符是向后兼容的——在此 CHIP 实现之后成功的任何调用,在此之前也会成功
  • 要添加的 CLVM 操作符不是向前兼容的——在此 CHIP 实现之前成功的某些调用之后将不再成功
  • 由于要添加的操作符的向前不兼容性,此 CHIP 将需要 Chia 区块链的软分叉
  • 要添加的操作符不太可能引起争议。但是,与所有分叉一样,存在链分裂的风险
  • 软分叉也可能无法被采用。如果升级到包含此 CHIP 引入的更改的节点数量不足,可能会在分叉的区块高度之前发生这种情况

操作符将分多个阶段引入:

  • Pre-CHIP: 在区块 4 510 000 之前,任何调用新操作符的尝试都将导致成功的空操作
  • 软分叉: 软分叉将在区块 4 510 000 处激活。从该区块开始,新的操作符将展示此 CHIP 中规定的功能。它们需要使用 softfork 操作符的新语法(从 softfork 保护内部)来调用。此语法在此 CHIP 的规范部分中进行了解释
  • 硬分叉: 硬分叉将在区块 5 496 000 处激活。此硬分叉是 CHIP-12 的结果,CHIP-12 与此 CHIP 无关。从区块 5 496 000 开始,也可以在不使用 softfork 操作符的情况下(从 softfork 保护外部)调用此 CHIP 中引入的操作符。换句话说,新的操作符将被添加到核心 CLVM 操作符集中。(请注意,如果需要,仍然可以从 softfork 保护内部调用这些操作符)

原理

此 CHIP 的设计主要因其标准化实现而被选中。它包括用于添加、减去、乘以和否定 BLS 点的一致方法。为了与这种一致性保持一致,此提案还包括从 point_addg1_add 的映射。

此 CHIP 设计的另一个方面是其增强的多个 BLS 分组之间的跨功能性。该设计包括配对来自不同分组的点的能力,以及向 G1 和 G2 点添加任意数据的能力。

每个新的操作符都将产生一个 CLVM 成本,如下详述。如果此 CHIP 被采用,则在设计 Chia coin 时,新的操作符将是可选的。

规范

BLS 操作符

为了支持 CLVM 中必要的可用 BLS 操作集,需要 G1 和 G2 点上的数学原语,以及配对和映射这些点的函数。因此,将添加以下操作符:

g1_add

Opcode: 29

功能:添加两个或多个 G1 点

注意:此操作符已在 CLVM 中实现为 point_add。为了保持一致性和易用性,将创建一个新的编译器宏,以将 point_add 映射到 g1_add,以便可以使用任一名称,并具有完全的向后兼容性。

参数:

  • 如果没有参数,将返回 G1 标识
  • 如果只有一个参数,结果将是一个成功的空操作
  • 如果有两个或多个参数,则每个参数必须是一个 G1 点;结果将是参数的总和

用法:(g1_add point1 point2 … pointn)

CLVM 成本:101 094 基础,每个参数 1 343 980

g1_subtract

Opcode: 49

功能:从一个基础 G1 点减去一个或多个 G1 点

参数:

  • 如果没有参数,将返回 G1 标识
  • 如果只有一个参数,结果将是一个成功的空操作
  • 如果有两个或多个参数,则必须包含一个基础 G1 点 (point1),后跟要从基础 G1 点减去的一个或多个 G1 点

用法:(g1_subtract point1 point2 … pointn)

CLVM 成本:101 094 基础,每个参数 1 343 980

g1_multiply

Opcode: 50

功能:将 G1 点乘以标量值

参数:单个 G1 点 (point1) 和单个标量值 (scalar)

用法:(g1_multiply point1 scalar)

CLVM 成本:705 500 基础,标量中每字节 10

g1_negate

Opcode: 51

功能:否定 G1 点

参数:单个 G1 点

用法:(g1_negate point1)

CLVM 成本:916

g2_add

Opcode: 52

功能:添加两个或多个 G2 点

参数:

  • 如果没有参数,将返回 G2 标识
  • 如果只有一个参数,结果将是一个成功的空操作
  • 如果有两个或多个参数,则每个参数必须是一个 G2 点;结果将是参数的总和

用法:(g2_add point1 point2 … pointn)

CLVM 成本:80 000 基础,每个参数 1 950 000

g2_subtract

Opcode: 53

功能:从一个基础 G2 点减去一个或多个 G2 点

参数:

  • 如果没有参数,将返回 G2 标识
  • 如果只有一个参数,结果将是一个成功的空操作
  • 如果有两个或多个参数,则必须包含一个基础 G2 点 (point1),后跟要从基础 G2 点减去的一个或多个 G2 点

用法:(g2_subtract point1 point2 … pointn)

CLVM 成本:80 000 基础,每个参数 1 950 000

g2_multiply

Opcode: 54

功能:将 G2 点乘以标量值

参数:单个 G2 点 (point1) 和单个标量值 (scalar)

用法:(g2_multiply point1 scalar)

CLVM 成本:2 100 000 基础,标量中每字节 5

g2_negate

Opcode: 55

功能:否定 G2 点

参数:单个 G2 点

用法:(g2_negate point1)

CLVM 成本:1204

g1_map

Opcode: 56

功能:将任意数据映射到 G1 点。使用 SHA-256 和 ExpandMsgXmd 将指定的消息哈希到 G1,使用指定的 DST (Domain Separation Tag) 或默认 DST

参数:第一个参数(必需)是数据;第二个参数(可选)是一个自定义 DST。如果未使用第二个参数,则将使用默认的 DST BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_

用法:(g1_map data dst)

CLVM 成本:195 000 基础,每字节 4,每个 DST 字节 4

g2_map

Opcode: 57

功能:将任意数据映射到 G2 点。使用 SHA-256 和 ExpandMsgXmd 将指定的消息哈希到 G2,使用指定的 DST 或默认 DST

参数:第一个参数(必需)是数据;第二个参数(可选)是一个自定义 DST。如果未使用第二个参数,则将使用默认的 DST BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_AUG_

用法:(g2_map data dst)

CLVM 成本:815 000 基础,每字节 4,每个 DST 字节 4

bls_pairing_identity

Opcode: 58

功能:如果所有 G1 和 G2 对的配对是 (Gt) 标识,则返回 nil,否则引发异常

参数:G1/G2 对的列表

用法:(bls_pairing_identity g1point1 g2point1 g1point2 g2point2 … g1pointn g2pointn)

CLVM 成本:3 000 000 基础,每 G1/G2 对 1 200 000

bls_verify

Opcode: 59

功能:根据签名 (G2) 验证消息 (msg) 给定的公钥 (G1)。如果签名有效,则返回 nil,否则引发异常。验证使用增强方案,这意味着在将 G1 点哈希到 G2 点之前,会将 G1 点添加到消息中。DST 为 BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_AUG_。验证包括基础配对操作中取反的 G1 生成器和签名的对

参数:一个 G2 点,后跟一个 G1/msg 对的列表

用法:(bls_verify g2point g1point1 msg1 g1point2 msg2 … g1pointn msgn)

CLVM 成本:3 000 000 基础,每 G1/G2 对 1 200 000,每字节 4,每 DST 字节 4,加上对已签名的每条消息执行 g2_map 的成本


其他操作符

此外,还将添加 coinidmodpow% 操作符,以及两个 secp 操作符。还将修改 softfork 操作符的行为。

coinid

Opcode: 48

功能:给定父 coin ID、puzzle-hash 和金额,计算此 coin 的 ID。同时验证参数,确保哈希值为 32 字节,并且 amount 采用规范表示且在有效 coin 的范围内。如果任何参数无效,则引发异常

参数:

  • parent-id -- 此 coin 的父 coin 的 coin ID
  • puzzle-hash -- 此 coin 的 puzzle 的 puzzle-hash
  • amount -- 此 coin 的值,以 mojos 为单位

所有这三个参数都是必需的。

Usage: (coinid parent-id puzzle-hash amount)

CLVM 成本:800

coinid 的 CLVM 成本计算类似于 sha256

  • SHA256_BASE_COST = 87
  • SHA256_COST_PER_ARG = 134(并且有 3 个参数:parent-id、puzzle-hash 和 amount)
  • SHA256_COST_PER_BYTE = 2(并且 parent-id 和 puzzle-hash 都是 32 字节;amount 是 8 字节)
  • 基础 coinid_cost = SHA256_BASE_COST + SHA256_COST_PER_ARG 3 + SHA256_COST_PER_BYTE arg_bytes
  • 基础 coinid_cost = 87 + (134 3) + (2 (32 + 32 + 8))
  • 基础 coinid_cost = 633

除了此成本之外,还有每个字节的 malloc 成本:

  • malloc_cost = 分配给堆的每字节 10
  • 分配的字节数 = 32 (sha256coinid 的输出大小相同)
  • malloc_cost = 320

理论上的 coinid_cost 是基础 coinid_costmalloc_cost 的总和:

  • 理论上的 coinid_cost = 633 + 320 = 953

到目前为止,此成本与 sha256 的成本相同。但是,sha256 更容易出现用户错误。为了激励使用 coinid,我们选择降低成本:

  • coinid_cost = 理论上的 coinid_cost - 折扣
  • coinid_cost = 953 - 153
  • coinid_cost = 800

modpow

Opcode: 60

功能:计算 (base ^ exponent) % modulus

参数:一个 base 值(可以为负数)、一个 exponent(不能为负数)和一个 modulus(不能为 0)

用法:(modpow base exponent modulus)

CLVM 成本:

  • base -- 17 000 基础,每字节 38
  • exponent -- 每平方字节 3
  • modulus -- 每平方字节 21

%

Opcode: 61

功能:计算 numerator 除以 denominator 的余数

参数:一个 numerator 和一个 denominator,可以是负数

用法:(% numerator denominator)

CLVM 成本:988 基础,每字节 4(两个操作数的总和)

请注意,%/ 的成本相同

secp256k1_verify

Opcode: 0x13d61f00

功能:验证使用 secp256k1 曲线的签名

参数:

  • pubkey -- 用于签名的 secp256k1 公钥
  • msg_digest -- 已签名消息的 sha256 哈希值
  • signature -- 要验证的数字签名

关于 msg_digest(要签名的消息的 sha256 哈希值)的说明:此参数与内置 hash-to-curve(或 g2_map)的 bls_verify 不同。它简化了成本模型,因为所有参数的大小几乎都是固定的。

用法:(secp256k1_verify pubkey msg_digest signature)

CLVM 成本:1 300 000

请注意,我们有意使此操作符比 BLS 等效操作符更昂贵,以鼓励使用 BLS 操作符。

secp256r1_verify

Opcode: 0x1c3a8f00

功能:验证使用 secp256r1 曲线的签名

参数:

  • pubkey -- 用于签名的 secp256r1 公钥
  • msg_digest -- 已签名消息的 sha256 哈希值
  • signature -- 要验证的数字签名

关于 msg_digest(要签名的消息的 sha256 哈希值)的说明:此参数与内置 hash-to-curve(或 g2_map)的 bls_verify 不同。它简化了成本模型,因为所有参数的大小几乎都是固定的。

用法:(secp256r1_verify pubkey msg_digest signature)

CLVM 成本:1 850 000

softfork 用法

向后兼容性部分中所述,从区块 4 510 000(包括)开始,此 CHIP 中引入的操作符将从 softfork 保护内部可用。

请注意,从区块 5 496 000 开始,此 CHIP 中的操作符也可以从 softfork 保护外部使用(它们将在硬分叉中成为 CLVM 的一部分)。在此之后,可以有选择地从 softfork 保护内部调用此 CHIP 中的操作符。

另请注意,softfork 操作符的语法已更新。使用更新后的 softfork 操作符调用此 CHIP 中的操作符时,适用以下规则:

  • 操作符的工作方式类似于 apply (a),但采用两个额外的参数,costextension
  • 因此,语法为 softfork (<cost> <extension> <quoted-program> <arguments>)
  • cost 参数是使用指定的 arguments 执行 quoted-program 的 CLVM 成本。如果此成本与执行程序的实际成本不匹配,则 softfork 操作符将引发异常
  • extension 参数是一个整数,指示 softfork 保护中可用的扩展集。此整数必须适合无符号 32 位变量
  • a 操作符一样,quoted-program 参数被引用,并从 softfork 保护内部执行。
  • 无法识别 extension 说明符的客户端必须:
    • 在共识模式下,忽略整个 softfork,返回 null 并收取指定的 cost
    • 在 mempool 模式下,立即失败程序

由于 softfork 保护始终返回 null,因此执行它的唯一有用的结果是终止(即失败)程序或不终止程序。

执行 softfork 操作符的成本为 140。这计入其参数中指定的成本。

以下是使用 softfork 操作符调用新 coinid 操作符的示例:

(softfork
  (q . 1265) ; 预期成本(包括 softfork 本身的成本)
  (q . 0)    ; 扩展 0
  (q a       ; 延迟执行 if 分支
    (i
      (=
        (coinid
          (q . 0x1234500000000000000000000000000000000000000000000000000000000000)
          (q . 0x6789abcdef000000000000000000000000000000000000000000000000000000)
          (q . 123456789)
        )
        (q . 0x69bfe81b052bfc6bd7f3fb9167fec61793175b897c16a35827f947d5cc98e4bc)
      )
      (q . 0)  ; 如果 coin ID 匹配,则返回 0
      (q x)    ; 如果 coin ID 不匹配,则引发
    )
    (q . ())) ; 要应用的环境
  (q . ()))   ; 要 softfork 的环境

硬分叉添加

以下条件和优化将在 CHIP-12 的硬分叉激活后可用。

SOFTFORK

Opcode: 90

功能:允许将未来的具有非零 CLVM 成本的条件作为软分叉添加。(此功能以前只能作为硬分叉实现)

参数:该条件的成本(以万为单位指定)是作为第一个参数必需的,进一步的参数未指定。将成本缩放 10 000 的原因是使参数更小。例如,此条件中的 cost100 将等同于 100 万 (1 000 000) 的实际成本。cost 参数为两个字节,最大大小为 65 535(实际成本为 655 350 000

用法:(90 cost)

CLVM 成本:变化,在调用期间指定,可以为零

具有成本的未知条件

在启用 SOFTFORK 条件之前,所有新条件都必须具有零成本。这些条件必须适合一个字节(这些条件是 u8 的别名)。

在启用 SOFTFORK 条件后,可以添加具有成本的新条件。这些新条件将是软分叉。条件代码将各有两个字节(u16 的别名)。此更改允许条件解析器处理 2 字节条件。为了使用具有成本的新条件,2 字节条件必须使用 0x01 作为其第一个字节。

这些条件的成本是从 chia_rs 存储库的 PR #183 中指定的函数计算得出的。从此函数计算出的确切成本在此表中列出。

关于这些更改,还需要记住两件事:

  • 所有现有的条件代码都将保持不变,作为单字节。
  • 没有前导 0x01 的双字节条件代码(包括那些以 0x00 开头的代码)将被视为空操作。

其他 AGG_SIG 条件

从 CHIP-12 进行硬分叉之前,存在以下 BLS 签名条件:

AGG_SIG_UNSAFE

Opcode: 49

功能:通过其 public_keymessage 验证签名

用法:(AGG_SIG_UNSAFE public_key message)

CLVM 成本:1 200 000

AGG_SIG_ME

Opcode: 50

功能:通过其 public_keymessage 验证签名,其中还包括 coin_idgenesis_id

用法:(AGG_SIG_ME public_key message)

CLVM 成本:1 200 000

<br/>

为了区分这两个签名条件,签名消息包括一个域字符串。对于 AGG_SIG_ME,域字符串是 Chia 区块链的 genesis challenge,一个静态且已知的标识符。AGG_SIG_UNSAFE 的域字符串可以是除 AGG_SIG_ME 的域字符串_之外_的任何内容。

AGG_SIG_MEAGG_SIG_UNSAFE 还包括签名消息中 coin 的 ID(连接的 parent_idpuzzle_hashamount 的 sha256 哈希值)。但是,当验证仅需要知道这些值中的一个或两个时,某些原语(例如支付渠道)更容易实现。

因此,此 CHIP 还将添加具有包括 parent_idpuzzle_hashamount 的所有组合的消息字符串的操作符。每个条件的域字符串都需要是唯一的,因此它将包括该条件的操作码:

domain string = sha256(genesis challenge + opcode)

因此,从 CHIP-12 激活硬分叉之后,以下新条件将变为可用:

AGG_SIG_PARENT

Opcode: 43

功能:通过其 public_keymessage 验证签名;还包括域字符串 sha256(genesis challenge + 43) 和 coin 的 parent_id

用法:(AGG_SIG_PARENT public_key message)

CLVM 成本:1 200 000

AGG_SIG_PUZZLE

Opcode: 44

功能:通过其 public_keymessage 验证签名;还包括域字符串 sha256(genesis challenge + 44) 和 coin 的 puzzle_hash

用法:(AGG_SIG_PUZZLE public_key message)

CLVM 成本:1 200 000

AGG_SIG_AMOUNT

Opcode: 45

功能:通过其 public_keymessage 验证签名;还包括域字符串 sha256(genesis challenge + 45) 和 coin 的 amount

用法:(AGG_SIG_AMOUNT public_key message)

CLVM 成本:1 200 000

AGG_SIG_PUZZLE_AMOUNT

Opcode: 46

功能:通过其 public_keymessage 验证签名;还包括域字符串 sha256(genesis challenge + 46) 和 coin 的 puzzle_hashamount

用法:(AGG_SIG_PUZZLE_AMOUNT public_key message)

CLVM 成本:1 200 000

AGG_SIG_PARENT_AMOUNT

Opcode: 47

功能:通过其 public_keymessage 验证签名;还包括域字符串 sha256(genesis challenge + 47) 和 coin 的 parent_idamount

用法:(AGG_SIG_PARENT_AMOUNT public_key message)

CLVM 成本:1 200 000

AGG_SIG_PARENT_PUZZLE

Opcode: 48

功能:通过其 public_keymessage 验证签名;还包括域字符串 sha256(genesis challenge + 48) 和 coin 的 parent_idpuzzle_hash

用法:(AGG_SIG_PARENT_PUZZLE public_key message)

CLVM 成本:1 200 000

区块生成器优化

作为区块创建过程的一部分,一个名为 ROM generator 的 CLVM 程序负责以下工作:

  • 调用区块生成器,该生成器输出该区块的所有 spend、puzzle 和 solution
  • 使用每个对应的 solution 运行 puzzle
  • 计算 puzzle 哈希值,然后用于从 coin 集中查找要 spend 的 coin

在从 CHIP-12 进行硬分叉之前,运行 ROM 生成器的成本计入每个区块成本限制。

在硬分叉激活后,将不再收取 ROM 生成器的成本。请注意,区块生成器、puzzle 和 solution 将继续产生与之前相同的成本。

硬分叉还将启用 CLVM 的更新序列化格式,该格式将用于区块生成器。生成器将 memoize 子树的树哈希,这是一种优化,允许更紧凑地表示重复的子树。由于相同的树已经被 farmer 去重,因此在区块中存在重复的 puzzle 的常见情况下,计算 puzzle 哈希值将变得更便宜。

测试用例

此 CHIP 的测试用例位于 clvm_rs GitHub 存储库的 op-tests 文件夹中。这些测试包括:

参考实现

以下 pull request 已经合并到 Chia-Network/chia_rs GitHub 仓库,作为此 CHIP 的一部分:

  • 168 - SOFTFORK condition
  • 170 - 将成本分配给当前未知的 condition codes;当 ENABLE_SOFTFORK_CONDITION 标志被设置时生效
  • 181 - 更新未知 condition codes 的成本(两个字节而不是一个字节)
  • 183 - 使用函数来计算未知 condition 的成本,而不是使用表格
  • 185 - 将创建或断言的最大公告数量从 1000 增加到 1024
  • 213 - 新的 AGG_SIG_* conditions
  • 273 - softforkcoinid operators
  • 274 - 此 CHIP 的主要补丁
  • 287 - bls_verifybls_pairing_identity 签名的更改
  • 288 - BLS operators 更新的成本
  • 290 - 如果验证成功,bls_verifybls_pairing_identity 必须返回 nil,如果验证失败,则引发错误
  • 303 - secp operators
  • 312 - modpowmod (%) operators
  • 314 - 调整 secp256k1_verify 的成本

以下 pull request 已经合并到 Chia-Network/chia-blockchain GitHub 仓库,作为此 CHIP 的一部分:

  • 15299 - soft fork 基础设施
  • 15769 - 新的 AGG_SIG_* conditions
  • 15938 - 更新 soft fork 激活高度

安全

Chia Network, Inc. 已经对涉及到此 CHIP 的代码进行了内部审查。

附加资产

勘误

  • 2023-08-29 -- AGG_SIG_ME 部分声明 AGG_SIG_MEAGG_SIG_UNSAFE 都包含了 coin 的 ID。虽然对于 AGG_SIG_ME 总是正确的,但对于 AGG_SIG_UNSAFE 不一定是正确的,它没有要求包含 coin 的 ID。但是,如果需要,可以包含。

版权

通过 CC0 放弃版权及相关权利。

  • 原文链接: github.com/Chia-Network/...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Chia-Network
Chia-Network
江湖只有他的大名,没有他的介绍。