本文将回顾 Ordinals 以及 Colored Coin 的实现理论来进行对比,并且进一步介绍 Taro 的实现以及现有的进展,以深层次地探讨 Bitcoin 二层网络实现的可行性。
撰文:3P-Labs
在 Ordinals vs Taro 系列文章的上篇中我们简单地介绍了 Taro 协议中对 Taro 资产的铸造、转账操作的理论实现。在这里,我们会回顾 Ordinals 以及 Colored Coin 的实现理论来进行对比,并且进一步介绍 Taro 的实现以及现有的进展,以深层次地探讨 Bitcoin 二层网络实现的可行性。
文章会分为以下四个部分:Bitcoin 同质化代币起源 Colored Coin、序数理论与 Ordinals、Taro 实现及进展、拓展阅读:Atomicals Protocol。
彩色币(Colored Coin)是由 Yoni Assia、Vitalik Buterin 等人在 2012 年所提出的一种在比特币网络上生成的新的代币 [1] [2]。彩色币应该是目前常见的 ERC-20 代币的雏形,它在当时被用来代表资产、进行投票,这和今天 ERC-20 所承载的功能是类似的。在曾经的彩色币浏览器 Coinprism 上,我们还能看到在 2015 年时人们所发行的一系列资产,图片截自网页在 2015 年所留下的快照:[Coinprism Snapshoot - archive.org]
彩色币通过「染色」的方式将一组比特币和其他比特币区分出来,对彩色币的实现方式有两种:ChromaWay 提出的 EPOBC 协议和利用 OP_RETURN 存放元数据的开放资产(Open Assets)。在这里,简单地介绍开放资产的实现原理,这也是 Yoni 等人在 Colored Coins 白皮书中所提及的一种方法 [3]。
OP_RETURN 在 Bitcoin v0.9.0 中被提出,可以用于在 Bitcoin 上存放少量的数据 [4],起初的限制存放 40 bytes 长度的数据,后续被增加到 80 bytes。彩色币白皮书(2013)中使用了 40bytes 长度的编码来实现染色,而在 2016 年的彩色币协议规范 [5] 中使用了 80 byts 长度的规范。2016 年的彩色币协议规范较为复杂,其中还涉及到彩色币的迷你脚本语言,这里不作展开介绍。彩色币最初的思想是利用 OP_RETURN 将特定的编码信息存放在一笔交易的输出脚本中,然后依靠链下的索引程序去识别这些交易的合法性(正如 2022 年底所出现的 Ordinals)。
最初的彩色币白皮书中,创建资产的数据编码如下所示
编码数据以 0x0043438000(「CCP」)开头以标识这是一笔彩色币创世交易,随后跟两个字节表示当前协议的版本。再后的两个字节是增发说明,全为 0 表示该资产不可增发,全为 1 表示该资产可无限增发。最后的 31 bytes 用于存放关于染色的信息。白皮书中所描述的一笔资产创世交易如下
INPUTS
17zt...sSrb : 500000
19GA...PUXr : 2125735
1MyK...NySN : 2500000
OUTPUTS
1LQh...5ziD : 1000000
1PEF...7dpL : 1000000
1Pmq...4Mxi : 1000000
1DCo...e5dy : 2000000
OP_RETURN : [ 0 67 67 80 0 0 0 255 255 ] + [0] * 71
1MyK...NySN : 115735
在输出的 OP_RETURN 中的编码数据表明了这笔交易是资产的创世交易,依据编码规则,这笔交易所创建的资产可以由地址为 17zt…sSrb 的钱包无限增发(因为输入的第一个地址是该地址,按照协议它可以作为增发地址),而在 OP_RETURN 输出前的地址可以识别为接收创世资产的地址,前三个地址会接收 9,900,000 个该资产,而最后一个地址会接收 19,900,000 个该资产。由此可以看出,可以看出彩色币中每个聪被染色对应某个染色资产。
为什么接收的资产数量会被减去 10,000?这是由于协议中定义了默认 10,000 的填充(padding),这样可以使得有 10,000 聪是不被染色的,以避免粉尘交易。
资产的转移可以设计得较为复杂,比如在一笔交易中转移不同染色的多种代币,但是为了方便表示转移的过程,这里假定转移的是单一的染色代币。并且转移时涉及到输入的序列号(sequence,它是 Bitcoin 交易的输入中的一个字段,通常在浏览器中可以看到 nSequence 字段),它的二进制表示该笔输入将代币输出到哪一个输出中。例如 6(110b)表示输出到第 1、2 笔输出中,而非第 0 或其他笔输出中。一笔代币转移交易如下所示,这里省略了输入、输出的地址信息。图中的深色表明该笔输入或输出被进行了染色。
把它表示为彩色币的转移状态,即去除掉 padding 并且将序列号的二进制转换为易读的形式,可以得到初始状态如下,输出的染色标记是通过最后的状态表示的,这里直接标记出来。
从第 0 个输入开始遍历序列号进行状态的转移,其过程的转移过程如下图所示
通过这个过程,可以看出彩色币的转移规则是比较繁杂的,链下的索引程序需要按照一系列的规则在 Bitcoin 的 UTxO 的基础上再实现一个对彩色币转移的 UTxO 计算。在 2012 年的彩色币白皮书中还提及了去中心化交易所技术,在一笔交易中完成彩色币的交换。很可惜的是,这项技术所需要的部分签名交易技术(PSBTs - BIP0174)在 2017 年才被纳入 BIP,在当时这就需要一个中心化的平台来标识以通过订单簿的方式实现(那么,这还是中心化吗?)。
而且 2016 年的 v2 版本的彩色币协议规范中,更进一步地设计了彩色币中需要的字节码、转移地址、验证规则。很可惜的是,这一套规则由于受限于当时 Bitcoin 的功能限制并没有得到更进一步的发展,而且 2015 年出现的以太坊更进一步使得这样的设计显得鸡肋,彩色币也于此结束了它的发展。也有人说彩色币失败的原因是它和原生的 btc 耦合在一起,在一些情况下就会被当成 btc 发送出去而减少。但是笔者认为它失败的原因是流通的不便捷以及应用场景较少。
时间来到 2022 年 12 月,得益于 2017 年的隔离见证、部分签名交易技术,以及 2021 年的 Taproot 升级激活,Casey Rodarmor 发明了序数理论 [7]:
序数是一种比特币的编号方案,这是的跟踪和转移单个 sat 成为可能 [6],它按照每个比特币被挖掘出的顺序以及交易时根据先入先出的规则来进行编号
序数的表示方式:
2099994106992659
这个序号是根据挖掘聪的顺序分配。3891094.16797
,第一个数字是挖掘聪的区块高度,第二个数字是区块内聪的偏移量。3°111094′214″16797‴
,具体的度数表示原理见序数理论手册99.99971949060254%
。以百分比表示聪在比特币供应中的位置。satoshi
(聪)。使用字符 a 到 z 对序号进行编码。序数理论更多地是对 Bitcoin 的最小单位 sat 的追溯,它所设计的规则使得每个 sat 都有自己独一无二的编号。而基于序数理论,可以把链上一些独特的数据和这些 sats 关联起来,也就是「铭刻」铭文。铭文被存放在 taproot 脚本中,taproot 脚本对内容的限制很少,而且可以获得额外的见证折扣,这使得铭文的存储较为经济。铭文的 Taproot 脚本格式类似于:
OP_FALSE
OP_IF
OP_PUSH "ord"
OP_1
OP_PUSH "text/plain;charset=utf-8"
OP_0
OP_PUSH "Hello, world!"
OP_ENDIF
它被存放在 Reveal 交易的输入见证脚本中,由链下的索引节点(ord)在遍历区块时识别并且将它显露出来。
而受限于索引而不能在链上进行操作的原因,这使得 Inscription 需要实现其他额外的功能时只能由 ord 的开放来实现,例如近期的父子铭文,以及几个月前的诅咒铭文索引。铭文的基本思路是和 Colored Coin 极为相似的,它们将数据存放到交易中由链下的程序进行索引,而不同之处在于铭文是将数据存放到输入的 Taproot 脚本中,Colored Coin 则是将编码数据存放到一笔输出中。
至此,Bitcoin 的生态得以发展,人们可以在链上铸造 NFT,并且得益于部分交易签名技术,交易市场也随之出现。铭文的技术本身和彩色币是极为相似的,它们都将数据存放到链上,由链下的索引工具来进行索引。然而, 由于时代的不同以及所面向的功能不一样,这使得彩色币受限于当时 Bitcoin 的功能缺陷而没有得到更多地发展。使得 Ordinals 得以发展、爆发的应该是它更低的铭刻费用(相较于前期竞品 bitcoin stamp [8]),以及受益于部分签名交易技术所出现的市场使得人们可以方便地进行铭文的交易。
此后基于铭文的 BRC-20 协议也在 2023 年 3 月出现,正如上篇中所说,这样的同质化代币实现方式颇有暴力美学的美感,将代币的铸造、转移过程写在纸上,剩下的交给 BRC-20 索引器,这相当于在 Bitcoin 的索引 Inscription 之上再加了一个索引。当然,在实际的实现中 BRC-20 索引器是可以直接忽略其他的 NFT 铸造而只关心 BRC-20 的铸造、转移的。
而 BRC-20 至此也有了一点比特币二层网络的样子:二层网络处理一系列的交易,定期和主链通信、提交交易实现捆绑来确保去中心化。在 BRC-20 中则是体现为索引器索引用户的账户余额来确保某些 BRC-20 铭文是否有效(处理交易),转移、铸造的过程由用户自己实现(提交交易到主链)。
有意思的是,在前不久 Ordinals Summit 所放出的照片中,BRC-20 的创始人 domo 所展示的一张 brc20-swap 的 PPT 中提到了这么两个概念:Inscription-Based Virtual Machines 和 Rollup,这似乎预示着 BRC-20 后续也会走入二层网络。
在上篇中,介绍了 Taro 资产在链上被铸造、转移的原理,那么在实际中,又是如何实现的?相比于上篇对原理的介绍,在这里我们将会介绍目前 Taro 的实现方式和最新进展。
由于众所周知的原因在本地搭建测试使用的闪电网络节点无法正常加入测试网络,在这里会通过 Understanding Taproot Assets Protocol #2 的测试过程来进行说明
正如上篇所说,资产的铸造需要选定输入的 UTxO,并且在资产树中记录一棵新的默克尔总和 - 默克尔树(MS-SMT)的根节点信息
在完成资产的铸造后,可以获取到资产的信息:
{
"assets": [
{
"version": 0,
"asset_genesis": {
"genesis_point": "ba779153....ffb34e88ce:0",
"name": "fantasycoin",
"meta_hash": "04e552053fd4c....934b22a43",
"asset_id": "20cecdb6626705....ebf2e84f6852874",
"output_index": 0,
"version": 0
},
"asset_type": "NORMAL",
"amount": "100",
"lock_time": 0,
"relative_lock_time": 0,
"script_version": 0,
"script_key": "02b4c71447e7....adefad3b31",
"script_key_is_local": true,
"asset_group": null,
"chain_anchor": {
"anchor_tx": "02000000000101ce884eb3ff....",
"anchor_txid": "ebe73fb60dfa99d191ed1....69e01d6abfd66356",
"anchor_block_hash": "0000000000....00000000000000000000",
"anchor_outpoint": "ebe73fb60dfa99d191e....d6abfd66356:0",
"internal_key": "03d9f42daae1b78....9672177c9301",
"merkle_root": "634ff6d86....40a439fce37184badff63f",
"tapscript_sibling": null
},
"prev_witnesses": [
],
"is_spent": false
}
]
}
这里的输出包含了三个重要的字段:asset_genesis
、script_key
和 chain_anchor
asset_genesis
:说明了资产的创建信息,例如元数据哈希值、输入的 UTxO 编号、资产 idscript_key
:类似于 P2TR 交易中的 ScriptPubKey
,需要满足条件的见证脚本才能花费这笔代表资产的 UTxO(正如上篇中提到的 UTxO*)chain_anchor
:说明了资产在当前所锚定的链上交易信息,它存储了交易、交易哈希值、交易所在区块的哈希值,该笔资产转移的输出 UTxO同样地,在创世交易 ebe73fb60dfa99d191ed1e43a0509cc93c5223fa202656c469e01d6abfd66356 中也生成了对应的输出,需要满足输出 ScriptPubKey (通过私钥或者路径)的脚本才能解锁这笔 UTxO 并用于下一笔交易。并且,下一笔交易在用于进行 Taro 资产转移时还需要满足内部的 script_key 要求
这里所存在的一个问题是:如何保证这笔 UTxO 能够正常地被用于进行 Taro 资产的花费?或许可以强制将私钥路径解锁的方式去除(P2TR 下可以使用私钥解锁 UTxO 或输入脚本来解锁 UTxO),让用户只能通过脚本路径的方式必须花费 Taro 资产。由于所能查阅的资料有限,这部分问题的解决方案并没有体现出来,或许这也是 Lightning Labs 团队正在解决的一个问题,正如他们在 Github 页面所说:目前的代码还不支持主网的运行,很可能使得用户丢失 Taro 资产以及包含了 BTC 的 UTxO。
此外,对见证脚本的实现细节也无法查阅到相关资料,如果需要更深层次的了解,只能翻阅源代码,而这需要更多的时间,所以在此无法进行更深入的讲解。
在 Taro Asset 中,资产的转移需要转移的双方同步它们的 universe,正如上篇所说,Taro Universe 保存了 Taro 资产的元信息,可以看作保存这一系列交易信息的数据库。只有在需要证明这些交易、铸造行为确实发生了的时候才会发送交易到 Bitcoin 上(这似乎也可以作为一种限制的机制,例如上一小节中对保证 UTxO 必然被作为 Taro 资产花费的讨论)。所以,在交易前,交易的双方需要同步信息以保证交易的有效。此后,发送 Taro 资产到另外一个地址,这样会生成一个类似交易的 transfer
信息:
{
"transfer": {
"transfer_timestamp": "1684836471",
"anchor_tx_hash": "e4efa1c32....f94056a41387835b3",
"anchor_tx_height_hint": 2434958,
"anchor_tx_chain_fees": "12725",
"inputs": [
{
"anchor_point": "ebe73fb60dfa....abfd66356:0",
"asset_id": "20cecdb662670....4f6852874",
"script_key": "02b4c71447e74672f8cd....502fe8adefad3b31",
"amount": "100"
}
],
"outputs": [
{
"anchor": {
"outpoint": "b3357838416....19092027c3a1efe4:0",
"value": "1000",
"internal_key": "024a3cb06616bb154....10ed83745bbe968",
"taproot_asset_root": "42ac8c233....60249e4698d",
"merkle_root": "42ac8c2....9e4698d",
"tapscript_sibling": null,
"num_passive_assets": 0
},
"script_key": "0225842....8c2d946c62",
"script_key_is_local": true,
"amount": "79",
"new_proof_blob": "00245663d6bf6a1...",
"split_commit_root_hash": "fdee0a27....6088874546a",
"output_type": "OUTPUT_TYPE_SPLIT_ROOT"
},
{
"anchor": {
"outpoint": "b3357838....19092027c3a1efe4:1",
"value": "1000",
"internal_key": "033e42d7bdc3....94651b048ce",
"taproot_asset_root": "8aada842....8e7e79506f41",
"merkle_root": "8aada842f74c2....8e7e79506f41",
"tapscript_sibling": null,
"num_passive_assets": 0
},
"script_key": "0225357fc148c....5f433c",
"script_key_is_local": true,
"amount": "21",
"new_proof_blob": "00245663d6bf6a1de069c4562620f...",
"split_commit_root_hash": null,
"output_type": "OUTPUT_TYPE_SIMPLE"
}
]
}
}
铸造资产的用户使用对应锚定了资产的 UTxO 作为输入,并且产生两笔输出到两个地址。outputs 中的信息则便于接收者验证自己所收到的 UTxO 是否合法,同时 outputs 中的信息也为接收者提供了生成下一次转账时所需要的信息,用以生成合法的见证脚本保证这笔 UTxO 能够被正常消费。结合前文对资产树和 Taro 资产转移的过程,asset_id
可以被用于在资产树中索引到表示资产的叶子节点,叶子节点还存放了资产的总额,而这些信息被存放在 Taro Universe 中,可以将它看作一个链下的索引程序。而通过 script_key
,可以在对应资产的 MS-SMT 中查询到对应可花费这些资产的余额。满足可消费条件的钱包可以利用这些输出作为下一笔交易的输入来进行交易。
上面的「转移」是一个「分割」的过程(100 -> <79, 21>),所以到自身的输出类型是 OUTPUT_TYPE_SPLIT_ROOT
,类似的还有合并操作,合并将某个钱包能够消费的不同 script_key
下的资产合并为一份。
Taro 资产所涉及的这些操作只在区块链上体现为一个 Pay-To-Taproot (P2TR)的形式,主要的资产转移过程还是在链下发生,所以从这个角度看 Taro Asset 可以看作是比特币的一个二层网络。
在 Taproot-Asset 页面中可以看到目前已经实现的功能有:
而从最新的 v0.2.3 版本来看,Lightning Labs 团队还在修复 Taro 程序的遗留问题,并且对原来的程序逻辑进行改进,例如将区块高度添加到资产的铸造证明。而在该程序的 Github 页面下,也写到该代码不适用于主网,可能导致 Taro 资产和 BTC 的丢失。在官方讨论的 Slack 下,开发者也提到闪电网络还不支持 Taro 资产。
满足资产铸造的的 v0.2.0 版本也是在今年五月份才正式发布,该版本已经实现了资产铸造 / 转移 / 接收功能,剩下的或许是细化交易规则(正如前文提到的问题),修正程序存在的 bug。所以,Taro 资产仍然有很长的路要走,它目前还无法满足在主网运行的要求,笔者认为,在未来一两年的时间里或许有希望能见证 Taro 资产的正式运行。
在笔者完成该系列的上篇,到撰写本文的两周时间里,出现了另一个 Ordinals 的竞品 —— Atomicals Protocol [9](原子协议),它和 Ordinals Inscription 的铸造很像,都是需要一笔 commit 交易作为输入,并在见证脚本中写入「信封」再进行 reveal,且数据格式也特别类似:
OP_FALSE
OP_IF
0x0461746F6D // Push "atom" 4 bytes
<Operation> // Followed by a single push to denote the operation type
<Payload> // Payload (CBOR encoded) for the operation
OP_ENDIF
ARC-20 是基于原子协议的同质化代币,它有和 BRC-20 完全不一样的铸造、转移规则
铸造:ARC-20 的铸造也需要有预先的代币部署,部署的方式是发送 Atomicals 格式的交易,部署需要指定代币的名称、铸造高度、关联的图像、铸造数量等信息,在索引器索引到后,其他人可以通过索引器得到代币的信息并且进行铸造。ARC-20 还设计了类似挖矿的铸造方式,部署者可以指定 commit tx 的碰撞前缀和 reveal tx 的碰撞前缀,如果有设置这些前缀信息,铸造者就需要在铸造的时候选取一个 nonce 来改变 commit tx 和 reveal tx 的哈希来选择满足条件的前缀(截至目前还没有要求 reveal tx 碰撞的需求,但是源代码中拥有该功能)。在用户找到满足条件的 nonce 后会发送铸造代币名和满足条件的 nonce 到编码后的原子协议交易到 Bitcoin 链上完成铸造,而余额信息则由索引器进行索引。
例如最开始发行的 ATOM 的拥有碰撞前缀 1618,这就要求铸造者需要通过查找满足条件的 nonce 使得 commit 交易的前缀为 1618,这样的碰撞查找最慢需要一分钟。而第二个需要挖矿铸造的 PEPE 的碰撞前缀为 0420. 11,暂不知道这样的非 16 进制前缀是如何匹配的,但是在实际的铸造过程中这样的前缀匹配最长需要 15 分钟。
转移:ARC-20 的转移和彩色币极为相似,但又简单得多,ARC-20 和聪进行了绑定,如果使用到了这些代币的 UTxO 作为输入,那么第 i 个输入会流向第 i 个输出,如果没有足够的输出,即输入数量大于输出数量的情况下,这些代币会流向第一个输出。
这样的转移方式的好处是避免了像 BRC-20 一样的需要先铸造 transfer 铭文才能交易的过程,使得同质化代币的交易更为方便,如果使用部分签名技术,可以通过整合交易的方式来完成单笔交易内的代币和 BTC 的交换,甚至是多种不同代币的交换。而缺点则是这样的实现太容易使得用户丢失代币了,特别是在用户接收多份同类代币,整合过 UTxO 后,这些表示着代币的 UTxO 极容易被当作 gas 花费出去,甚至是在铸造其他代币的过程中花费出去。
此外原子协议中还包含了 NFT、域名(独立于 NFT)的设计,文档中还有未完工的合约、事件,由于官方文档的缺失无法继续深入介绍。
在此需要把 Taro 资产、 Ordinals 的 BRC-20 代币以及原子协议进行对比,它们的相似之处在于代币的铸造、转移都是由链下程序追踪并记录的,但是记录的规则和在链上的体现又不尽相同
最后,在介绍完这些技术后探讨一下 Bitcoin 实现的可能性:在常见的二层网络实现中,通常是另外构建一个区块链网络来执行事务,然后将这些已执行的证明放到 Layer 1 的主链中,这也是 Rollup 的基本原理,定期向主链提交证明。闪电网络作为 Bitcoin 的一个二层支付网络,它的实现方式也类似 Rollup 技术,交易双方在建立通道后进行一系列的交互,最后确认的时候关闭通道,再向链上提供证明。
Taro 资产设计了类似 UTxO 的方式来完成资产的铸造、转移,其目的或许在于能够兼容闪电网络,使得这样的交换模式也可以在闪电网络中生效。双方只需要利用类似闪电网络的模式进行资产的交换,最后需要回到 Bitcoin 时再提交证明交易,以证明这些资产已经再二层网络中实现。如果这些资产的实现过程都在 Bitcoin 上实现,那么可以看成每一笔交易都被在 Bitcoin 上提交了证明,保证了链下的资产证明是有效的。但是这样的实现方式极度依赖于链下的 Taro Universe 索引,如果元数据丢失,很有可能造成用户资产的流失。这些索引是十分分散的,或许能够将这些 Universe 组成一个 P2P 网络,形成一个类似 IPFS 的分布式存储?这样的好处是便于用户进行同质化代币类资产的流通,缺点在于非同质化代币资产就显得没有意义(正如会有人问,那为什么不直接使用 ERC721?)。
而 BRC-20 是暴力地记录铸造、转账数据,索引器索引账本信息。它所存在的缺点是显而易见的,用户需要先铭刻转账铭文才能进行转账,而这是它依赖 Ordinals 实现而不得不满足的条件。如果 BRC-20 不依赖于 Ordinals 实现而是设计一套类似 Ordinals 的设计来实现,或许能满足较好的流动性,但是这样或许就不能利用 Ordinals 的热度而爆火了。当然,这样带来的好处是索引的方法很简单,也不用存储过多额外的元数据(对比 Taro 资产所存放的元数据信息),而这也限制了它的扩展性。而 Ordinals 作为 NFT 所能表现出的功能是很好的,它的数据存放在链上可索引(尽管矿工可以舍弃掉这部分 witness 数据),表现出了和 ERC-721 不一样的方式。Ordinals 本身不能算是一个二层网络,但是在有了 BRC-20 之后表现出了一个二层网络的样子,但是数据的变动都是表现在 Bitcoin 上,而非表现在这个二层网络(索引器)中,它本身只是为了保证记账的准确。
由此可见,Taro 资产和 Ordinals 都有各自的亮点,特别是在同质化代币和非同质化代币的实现下,Taro 对同质化代币的实现考虑得很多,考虑了 Taproot 来压缩交易,使得一笔交易中可以交换数额庞大的资产,以及 UTxO 类的交易方式来满足闪电网络的兼容。但是其对 NFT 的实现则显得尤为鸡肋,相比于 Ordinals 铭文的链上数据存放以区别和 ERC-721 的不同而成为亮点。而基于它所实现的 BRC-20 在用户交易过程中又显得繁琐,Taro 资产中的交互不会让用户感知这一切。从这样的对立中很明显能感受到同质化代币和非同质化代币的不同,特别是在 Bitcoin 这样基于 UTxO 的区块链上,协议所采取的底层设计方式显得尤为重要。
参考文章
Colored Coins - wikipedia
bitcoin 2.X (aka Colored Bitcoin) – initial specs
Colored Coins whitepaper
NULL DATA - learn me a bitcoin
Coloring Scheme - Github
概述 - 序数理论手册
ORDINALS 的崛起,BTC 生态寒武纪大爆发
Bitcoin Stamps
Atomicals Protocol
Taproot Assets Protocol
Understanding Taproot Assets Protocol #2
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。