Post

Ordinals & BRC-20 技术原理详解

本文从技术的角度出发,深入底层,详细介绍了比特币 Ordinals 协议以及 BRC-20 代币标准的原理。主要内容包括 Colored Coins 项目介绍、SegWit 与 Taproot 升级详解、序数铭文及 BRC-20 代币标准说明。

1 背景知识

1.1 比特币交易模型

在比特币网络中,比特币的形式是“未花费交易输出” (Unspent Transaction Output, UTXO),即比特币交易执行后形成的面额不定的单元,其原理可简单类比现实中的现金支付,与传统的基于账户余额的模型有所不同。举例而言:在银行的账户记账模型流程中,当 A 向 B 转账 100 元时,银行会记录三个步骤,这三个步骤构成了一个交易过程。第一步是从 A 的账户中扣除 100 元,这个步骤的记录 ID 为 tid1。第二步是将 100 元存入 B 的账户中,这个步骤的记录 ID 为 tid2。第三步是记录一笔转账记录,该记录将 tid1 和 tid2 关联起来,表示 A 账户减少 100 元,B 账户增加 100 元。这样,A 和 B 之间的转账关系就被记录了下来,并且可以在未来查询与追踪。

而在比特币区块链中,所有的余额都是存储在一个名为 UTXO 的列表中。每个 UTXO 都包含一定数量的比特币,以及这些比特币的所有者信息,并标明是否可用。可以将其想象成一张署有持有人姓名的现金支票,只要持有人在上面签名,就可以将使用权转让给他人。对于特定的地址,其所有的 UTXO 金额加起来即为该地址钱包的余额。通过遍历所有的 UTXO,我们可以获取每个地址的当前余额。将所有的 UTXO 金额加总,则为当前全部流通的比特币。

在比特币的交易结构中,每笔交易都包括若干个输入和输出,其中每个输入是对一个已有的 UTXO 的引用,而每个输出则指定了新的资金接收地址及相应的金额。一旦一笔交易被发起,其输入部分所引用的 UTXO 便会被暂时锁定,以防止在交易完成前被重复使用。只有当这笔交易成功地被矿工打包到一个区块并获得网络确认后,相关的 UTXO 状态才会发生变化。具体来说,用于交易输入的 UTXO 将从 UTXO 列表中移除,表示它们已经被消费,而交易的输出则会生成新的 UTXO,并添加到 UTXO 列表中。可以理解为,旧现金支票被使用后失效,产生了新现金支票,其所有权属于新的持有人。

值得强调的是,每个 UTXO 只能在一笔交易中被使用一次。一旦它作为输入被消费,它就会永久地从 UTXO 列表中移除。同时,新生成的输出作为新的 UTXO 加入到列表中。UTXO 列表是不断变化的,随着每个新区块的创建,它会相应地进行更新。并且,通过分析区块链中的交易历史,我们能够重建在任何给定时间点的 UTXO 列表状态。

此外,一笔交易的总输入金额通常会略微超过其总输出金额。这个差额,称为交易费用 (Transaction fee),是作为激励给予负责将交易打包到区块的矿工的。网络费的大小与交易的复杂性成正比,因此,一笔包含更多输入和输出的交易通常需要支付更高的网络费。

图1 是通过区块链浏览器展示交易信息的例子(假设场景为 Alice 使用了 0.1 BTC,其中的 0.015 BTC 转账给了 Bob 用于购买咖啡,而 0.0845 BTC 退给了自己,0.0005 BTC 是转账手续费,由打包者获得)。这个交易在主网上真实存在,参考: 0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2

图1 交易信息

上图中是比较高层次的交易信息。使用 bitcoin-cli 子命令 getrawtransactiondecoderawtransaction ,可以得到上面 Tx 的底层结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
    "version": 1,
    "locktime": 0,
    "vin": [
        {
            "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
            "vout": 0,
            "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
            "sequence": 4294967295
        }
    ],
    "vout": [
        {
            "value": 0.01500000,
            "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
        },
        {
            "value": 0.08450000,
            "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
        }
    ]
}

可以看到交易中有 Input 和 Output(分别是上面的 vin 和 vout)。Input 标识哪个 UTXO 将被消费,并通过解锁脚本提供所有权证明。Output 则创建新的 UTXO 比特币块并用锁定脚本锁定,供所有者在未来交易中使用。

比特币网络中交易输出有两个重要信息:地址(公钥哈希)和 value(比特币)。如果交易的输出没有出现在其它交易的输入中,则这个 Tx 的输出就称为 UTXO(未花费交易输出)。谁拥有 UTXO 中公钥对应的私钥,谁就可以使用(即花费)这个 UTXO。

上例中交易的输入为:

1
2
3
4
5
6
7
8
     "vin": [
        {
            "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
            "vout": 0,
            "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
            "sequence": 4294967295
        }
     ]

表示这个 Tx 所花费的 UTXO 来自于另外一个 Tx(其 id 为 7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18)的第 0 个输出(一个 Tx 的输出可以有多个,索引从 0 开始编号),我们可以从历史 Tx 中查找出这个 UTXO 的 value(比如为 0.1),所以这个 Tx 中 Alice 花费了 0.1 BTC,数值 0.1 不需要显式地写在 Tx 中,而是通过查找 UTXO 信息来得到的。

一旦这个 Tx 被提交,那么 Tx(7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18)的第 0 个输出就不再是 UTXO 了。

这个 Tx 中,输出有两个条目,如下所示:

1
2
3
4
5
6
7
8
9
10
    "vout": [
        {
            "value": 0.01500000,
            "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
        },
        {
            "value": 0.08450000,
            "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
        }
    ]

这两个条目刚开始都是 UTXO,直到有另外的 Tx 把它们作为输入花费掉为止。

发起⼀笔交易时,发送方在交易中放入 scriptPubKey,即上文提到的锁定脚本。接收方在花费时生成⼀个 scriptSig,即上文提到的解锁脚本,包含了满足 scriptPubKey 脚本的数据参数的集合。针对解锁的条件,可以将比特币交易分为多类,其中经典的两类是 P2PKH 和 P2SH。

P2PKH

Pay-to-PubKeyHash (P2PKH) 是⼀种传统的比特币交易,其地址以数字 1 开头。只有P2PKH 地址的所有者才能通过提供公钥哈希值和私钥签名来解锁 scriptPubKey 并花费其锁定的 UTXO。其中,私钥是用来证明公钥哈希值的所有权的。

如下图所示,发送交易时,发送方需要在交易中包含 scriptPubKey。当接收方想要解锁这笔 UTXO 时,需要执行下图中的比特币脚本,如果 PubKHash 相等,且签名验证通过,就可以成功解锁交易。P2PKH 的脚本会增加交易的体积,产⽣的交易费比普通交易⾼出 5 倍左右,且该成本由发送方承担。P2SH 可以帮助发送方免去这⼀额外成本。

图2 P2PKH

P2SH

Pay-to-Script-Hash (P2SH) 可以帮助发送方免去额外成本,并将这⼀成本转移到真正需要使用锁定脚本中规定条件的接收方身上。P2SH 的比特币地址以数字 3 开头。

发送交易时,发送方不再需要将 scriptPubKey 放在交易中,而是将赎回脚本 (Redeem Script) 哈希值放在交易中。赎回脚本哈希值由赎回脚本计算得到,赎回脚本与 scriptPubKey 类似,包含接收方在花费 UTXO 之前必须满足的条件。

如下表所示,发送方只需在交易中注明赎回脚本的哈希值即可。而接收方想要解锁 UTXO 时,需要⽣成具有相同哈希值的赎回脚本并将其包含到交易内。因此,接收方用来解锁 UTXO 的交易大小会增加,执行交易的成本也会增加。

表1 P2SH复杂脚本
Item Value
Redeem Script 2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 CHECKMULTISIG
Locking Script HASH160 <20-byte hash of redeem script> EQUAL
Unlocking Script Sig1 Sig2 < redeem script >

1.2 比特币脚本

比特币中的脚本 (Script) 是一种简单的基于栈的、非图灵完备的语言。这里以 Pay-to-Public-Key-Hash (P2PKH) 类型的脚本为例进行说明。

1
2
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>

为了解释得更清楚,原始的 scriptPubKey如下:

1
2
3
4
5
  76       A9             14
OP_DUP OP_HASH160    Bytes to push

89 AB CD EF AB BA AB BA AB BA AB BA AB BA AB BA AB BA AB BA   88         AC
                      Data to push                     OP_EQUALVERIFY OP_CHECKSIG

注意:scriptSig 在花费交易的输入中,主要包含转账的目标地址(公钥的 Hash)。而 scriptPubKey 在先前未花费交易(即“可用”交易)的输出中,主要包含签名和公钥(由此,我们可以利用公钥验证签名,从而确定用户身份)。

脚本处理过程如下:

表2 P2PKH流程说明
脚本 说明
<sig> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG 组合 scriptSig 和 scriptPubKey
<sig> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG 常量入栈
<sig> <pubKey> <pubKey> OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG 栈顶元素被复制
<sig> <pubKey> <pubHashA> <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG 计算栈顶元素的哈希
<sig> <pubKey> <pubHashA> <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG 常量入栈
<sig> <pubKey> OP_CHECKSIG 检查确认栈顶两元素相等
TRUE 使用栈顶两元素验证签名合法

交易验证时,在栈上执行脚本,先执行交易输入中的 解锁脚本 (scriptSig),再执行这个输入所引用的 UTXO 中的锁定脚本(scriptPubKey),如果最后栈中内容为 TRUE,则认为这个输入是合法的,如果所有的输入合法则整个交易通过验证。

2 从历史出发:Colored Coins

概述

2012 年 12 ⽉ 4 ⽇,为了在比特币区块链上体现股票、房地产等实物资产,密码学家、数学家、以色列比特币协会主席 Meni Rosenfeld 发布了彩色币白皮书 Colored Coins whitepaper

比特币⾃设计之初就是同质的、可替代的,是⼀种中立的交换媒介。如果仔细追踪特定比特币的来源,可以将⼀组比特币 “上色” 成为彩色币,使其与其他比特币区分开来。这样,这些比特币就具备了非同质化特性,可以具有由发行机构或公共协议支持的特殊属性,并包含了独立于基础比特币面值的价值。这种彩色比特币可用于替代货币、商品证书、智能财产以及股票和债券等其他金融⼯具。

例如,假设有⼀家汽车租赁公司,通过发布⼀枚彩色币来代表⼀辆汽车,然后将汽车配置为只有在收到用当前拥有该彩色币的私钥签署的信息时才会解锁。然后,该公司可以发布⼀个智能⼿机应用程序,任何人都可以用它来广播⼀条用⾃己的私人密钥签名的信息,并将彩色币放到⼀个交易平台上。基于此,任何人都可以购买彩色币,使用智能⼿机应用程序作为“汽车钥匙”,在任何时间内使用汽车,并在闲暇时再次出售彩色币。

实现

从技术角度来说,彩色币是在创世交易(不同于创世区块中的创世交易)里面被转移过的比特币。要发行⼀种新颜色的彩色币,必须创建 “彩色地址” 并将其存储在由颜色感知客户端(例如 Coinprism、Coloredcoins、Colu 或CoinSpark)控制的 “彩色钱包” 中。彩色币创世交易的输入和输出必须遵循特定的规则。输出包括⼀组将彩色币发送给原始所有者的输出、⼀个 OP_RETURN 数据输出、⼀个或多个“找零”输出(即将多余的未着色比特币发送回发行者)。发行者可以选择发行 Non-reissuable colors 或者 Reissuable colors

OP_RETURN 输出允许有 40 字节(后来改为 80 字节)作为标准交易的⼀部分。所有标识为彩色比特币交易的数据都将包含在该数据字段中。彩色币本身就是比特币,存储和转移的逻辑与比特币⼀致。EPOBC 是彩色币的第⼀个实现。

1
2
3
4
5
# 彩色币的 OP_RETURN 数据定义
[0...4]: [0,67,67,80,0] (that’s “CCP” padded with a zero-byte on both sides)
[5...6]: protocol version number (currently 1)
[7...8]: reissuance policy (0 for non-reissuable, 65535 for infinitely reissuable from the genesis address)
[9..39]: optional (data about the color)

优缺点

彩色币第⼀次为比特币引入了创新概念并扩大了比特币的用例,使比特币可被用于表示资产的数字化形式、开展去中心化交易以及作为资产管理和点对点交易的创新解决方案,并且仍然保持着透明度、可追踪性、去中心化等多个特性。

然而彩色币相对来说具有⼀定程度的复杂性,并且功能有限,无法很好地为现实世界的很多金融活动提供便利。例如,每笔交易都是可见的,可能并不适合所有类型的资产转移。另外,彩色币也面临着发行人不遵守相关义务的风险。

Colored Coins 的更多思考

虽然 OP_RETURN 是⼀个非常直接的用以存储信息至比特币区块链的⼿段,也是⼀个潜在的铭文方式。但是 OP_RETURN 的限制使得其在处理元数据存储时面临⼀些挑战。

  • OP_RETURN 只能存储非常有限的数据,对于需要存储更大量数据的情况来说,这种限制显然是无法满足的;
  • OP_RETURN 数据被存储在交易输出部分,虽然这种数据不存储在 UTXO 集中,但是它们占用了区块链的存储空间,导致区块链规模的增加。
  • 使用 OP_RETURN 会导致交易费用的提⾼,因为它需要支付更多的费用来发布这些交易。

Colored Coins 的出现说明人们对比特币有着更丰富的需求,但是受限于当时的比特币基础设施不够完善,Colored Coins 并没有取得成功。为了让比特币具有更多的用法,需要提升比特币的效率、灵活性,并且赋予比特币更⾼级的脚本能力。

3 比特币的两次升级

3.1 SegWit

“隔离见证”(Segregated Witness,SegWit)是比特币的一个重要协议升级,由比特币核心开发者 Pieter Wuille 在 2015 年提出,最终在 2017 年的 0.16.0 版本中被正式采纳。

在密码学中,术语“见证” (Witness) 用于描述解决密码难题的方案。在比特币语境中,见证是指能够满足对 UTXO 施加的条件并解锁该 UTXO 以供花费的解决方案。“见证”是 “Unlocking Script” 或 “scriptSig” 更一般化的术语。

隔离见证,指的是把见证数据(即 scriptSig 中的内容)从交易信息里抽离出来,单独存放。 如图 3 所示。

图3 SegWit 区块说明

不使用隔离见证时,交易中包含了见证数据 (scriptSig),也就是说见证数据 (scriptSig) 会影响 txid(txid 是 交易信息进行哈希运算后得到的一个唯一 id);使用隔离见证后,交易中不再包含见证数据(scriptSig 总是为空),见证数据在另外的字段 (witness) 中(该字段不参与 txid 的计算)

SegWit 升级消除了比特币网络中的“交易延展性” (Transaction Malleability) 问题,同时优化了网络和存储,增加了比特币区块中能容纳的交易数量。

  • 交易延展性问题:是指交易在被比特币网络确认之前,txid 可能被攻击者修改导致的问题,其根本原因是比特币交易中的签名数据是与交易的其余部分相关联的,⼀起进行哈希以产⽣交易的整体签名。这使得即使交易中的签名数据被更改,交易的有效性仍然可能保持不变。举例来说,Alice 提交了一个交易,转移一个 BTC 给 Bob,记为 tx1,这个交易的输入中 scriptSig 字段中包含了 Alice 的签名。在交易打包确认前,攻击者稍微调整 scriptSig,(比如在脚本末尾添加 OP_PUSHOP_DROP,或者把签名换个 S 值)这些调整不会影响交易信息的签名验证,但会得到一个新 txid,记为 tx2。现在 tx1 和 tx2 都在等待打包确认状态。如果恰好 tx2 被先打包(这很少出现,但可以伪造更多的 tx3,tx4 来增加被先打包的概率),那么 tx1 在验证时就会失败,因为交易输入中引用的 UXTO 已经被 tx2 花费了。这样,Alice 成功转移了一个 BTC 给 Bob,但 txid 却不是 tx1 了。

    那么交易延展性带来的问题为什么不可接受呢?例如,假设 Alice 是交易所,而 Bob 是该交易所的用户。Bob 以前存入了 100 个 BTC,现在向 Alice 提出提币申请,Alice 向 Bob 转移 100 个 BTC,记下 txid 为 tx1,B 利用交易延展性,伪造了另外一个交易 tx2。这时恰好 tx2 被先打包了,tx1 失败。B 对 A 说“我没有收到 100 个 BTC”,A 去查询当时提交的 txid(即 tx1),发现确实 tx1 没有打包上链,然后再发起一个新交易,向 B 转移 100 BTC。这里,其实 A 已经向 B 转移了 200 BTC。

  • 优化网络和存储:见证数据通常在交易的总大小中占了很大比重。更复杂的脚本,如用于多签或支付通道的脚本体积会非常大。在某些情况下,这些脚本会占到交易数据的大多数(超过 75%)。通过将见证数据从交易中移出,隔离见证提高了比特币的可扩展性。节点可以在验证签名后删减见证数据。见证数据不再需要发送到所有节点,也不需要被所有节点存储在磁盘上。同时,SetWit 升级还改变了区块大小的衡量方式,引入了“区块权重” (weight) 的概念,规定了见证数据的权重仅为交易数据权重的 25% 。这实际上意味着比特币区块大小增加了,并且在交易的 Witness 部分中存储数据变得更加便宜。例如,假设有⼀笔传统类型的交易,数据量大小为 200 Bytes。SegWit 升级前,1MB 的区块里面可以放进 5000 笔这样的交易。而⼀笔等效的 SegWit 交易有 120 Bytes 是放在 见证区域的,因此其加权大小为 80 + 0.25 *120 = 110 字节,所以区块可以放入 9090 笔这样的交易,容量几乎翻倍。

此外,SegWit 升级还有引入了两类支付脚本类型:P2WPKH 和 P2WSH 。

  • P2WPKH (Pay to Witness Public Key Hash):

    P2WPKH 的交易输出脚本是⼀个包含公钥哈希的锁定脚本,公钥哈希是见证程序的哈希值。P2WPKH 的交易输出以 bc1 开头。

    前文 Alice 买咖啡的例子中,价值 0.015BTC 的 P2PKH 输出的锁定脚本如下:

    1
    
    OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG
    

    而通过隔离见证,Alice 会创建一个“支付给见证公钥哈希” (P2WPKH) 脚本,如下:

    1
    
    0 bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
    

    显然,隔离见证输出的锁定脚本比 P2PKH 的要简单得多。它包含两个值,第一个数字(0)是一个版本号,第二部分(20 字节)相当于一个锁定脚本,被称为见证程序(witness program)。这 20 字节的见证程序就像是 P2PKH 脚本中的公钥哈希值一样。

    主网上 P2WPKH 交易的实例,可参考:ec9f03d79de1b408a2880e77b7be67c149ddb5e89c5b8c5a648fe29f4524d959

  • P2WSH(Pay to Witness Script Hash):

    P2WSH 对应 P2SH 脚本。P2WSH 的交易输出脚本是⼀个包含脚本哈希的锁定脚本,其中脚本哈希是一个由多个操作码组成的脚本的哈希值。

    一个这样的锁定脚本:

    1
    
    OP_HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e EQUAL
    

    使用隔离见证,可以创建一个如下的 P2WSH 输出进行付款:

    1
    
    0 9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73
    

    显然,隔离见证等效脚本要简单得多,省略了 P2SH 脚本中的各种脚本操作符。而且,隔离见证程序仅包含两个推送到堆栈的值:一个见证版本(0),另一个为 32 字节的兑换脚本(Redeem Script)的哈希值。

缺点:因为 SegWit 是⼀个软分叉,许多客户端可能不会升级,因此两种类型的 UTXO 会在网络中同时存在。SegWit 会降低网络的安全性,执行完全验证的节点会大幅减少,因为只有那些升级了的节点才有能力验证交易的 witness 部分。

总结来说,SegWit 升级把脚本签名(scriptSig)信息从区块中提取出来,放在⼀个新的数据结构当中。虽然见证数据不是为了数据存储而设计的,但实际上却给了用户⼀个存储其他类型数据内容的机会。

3.2 Taproot

2021 年 11 月,比特币进行了 Taproot 软分叉升级,在区块 709632 处(2021 年 11 月 12 日)被激活。Taproot 升级由三个不同的比特币改进提案(BIP)组成:BIP 340、BIP 341 和 BIP 342 ,提升了比特币网络的可扩展性、隐私性和灵活性。而 Taproot 升级对后续铭文的影响主要体现在两个方面:更低的费用、更大的空间

  • BIP 340 主要引入了 Schnorr 签名方案。相较于比特币使用的椭圆曲线数字签名算法(ECDSA),Schnorr 签名的主要优势在于,多重签名交易在链上呈现为普通的单一签名交易。使用Schnorr签名,多个签名者可以生成一个联合公钥,然后用一个签名共同签名,无需分别在区块链上发布每个公钥和每个签名。这就意味着 Schnorr 签名可实现显著的空间节省和验证时间节省,随着传统多重签名交易上签名者数量的增加,其比较优势变得更大。

  • BIP 341 包括两个技术升级:MAST(Merklized Abstract Syntax Tree,默克尔抽象语法树)和 P2TR(Pay-to-Taproot)。

    • MAST 是比特币协议开发者 Dr. Johnson Lau 在2016年提出的一个概念。MAST 的理念是,交易可以包含多个花费条件,例如一个 2 对 2 的多重签名条件,以及一个时间锁条件。为了避免将所有这些条件和脚本都放入区块链,花费脚本可以被组织在一个 Merkle 树内,由此只需在使用时和必要的Merkle分支哈希一起被揭示即可。例如下图所示,要花费输出,签名者需要做的就是提供一个 Schnorr 多签和 Merkle 树右侧顶部的 Hash(1 & 2)。因此,尽管存在Merkle树,在大多数情况下,只需要一个签名和 32 字节的哈希。

      图4 MAST树

      然而,这种结构的缺点是,即使在正常的最佳情况下,当Merkle树左上方提供单个密钥和脚本时,仍然需要将另一个哈希发布到区块链(在上图中为Hash(1 & 2),使用了32字节的数据)。这同时也降低了隐私性,因为第三方可以据此确定是否存在更复杂的花费条件。

      图5 Taproot

      Taproot 在结构上与 MAST 相似,只是在 Merkle 树的顶部有所不同。在 Taproot 中,用户通过发布公钥签名或满足默克尔树中包含的脚本之⼀来花费,前者称为密钥路径花费(Key Path),后者则是 脚本路径花费(Script Path)。用户可以选择只公布单个公钥和单个签名,而无需公布 Merkle 树的存在。如图 5 所示,左侧调整后的公钥可以从原始公钥和 Merkel 根哈希计算得出。在正常情况下,赎回时不需要在链上保留原始公钥,也不需要揭示 Merkle 树的存在,只需要发布一个单一的签名。与原始 MAST 结构相比,Taproot无需在区块链或脚本本身中包含额外的 32 字节哈希,提高了效率。除此之外,Taproot 使交易看起来很正常,只是一个带有公钥和签名的支付,其他花费条件的存在不会被公布,因此能更好地保护隐私。

    • P2TR,即 Taproot Output ,是版本为 1 的隔离见证输出。P2TR 统一了 P2WPKH 和 P2WSH 这两类版本为 0 的隔离见证输出,也就是说其输出 的 scriptPubKey 字段是一样的,更有利于隐私保护。下表 是 P2WPKH/P2WSH/P2TR 的 scriptPubKey 字段及花费它们时的 Witness 字段的总结。

      表3 P2WPKH/P2WSH/P2TR对比
      Type scriptPubKey(锁定时使用) Witness(花费时使用)
      P2WPKH 0x0014{20-byte-key-hash} <signature> <pubkey>
      P2WSH 0x0020{32-byte-hash} ……
      P2TR (Key Path) 0x5120{32-byte-tweaked-public-key} <schnorr-signature>
      P2TR (Script Path) 0x5120{32-byte-tweaked-public-key} …… <script> <control-blok>

      从表中,可以看到创建一个 P2TR (Key Path) 输出时,要比创建 P2WPKH 输出要多占用更大的空间,因为 P2TR (Key Path) 的 scriptPubKey 直接含有 tweaked public key(32 字节),而 P2WPKH 则是公钥哈希(20 字节)。也就是说, 往 P2TR 转账比往 P2WPKH 地址转账要略微贵一点。

      不过, 花费 P2TR (Key Path) 比花费 P2WPKH 要省更多的费用, 原因有:

      • 花费 P2TR (Key Path) 的 Witness 中不再包含公钥;
      • P2TR (Key Path) 采用的 Schnorr 签名比 P2WPKH 采用的 DER 格式的 ECDSA 签名要更小。

      综合考虑创建输出和花费输出两方面,P2TR (Key Path) 比 P2WPKH 更省费用。直观对比 P2WPKH 和 P2TR(Key Path)的 Witness:

      • P2WPKH 的 Witness 由“signature”和“pubkey”两个元素组成。

        Tx 9d86b83297aaf232446e5ab41b603027fb37ad85f5259b78d6ff6fefe7cada9d 是花费 P2WPKH 的例子,它的 Witness 为:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        
        0070: 02 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. vin0 Witness Count: 2
        0070: .. 48 .. .. .. .. .. .. .. .. .. .. .. .. .. .. DER vin0 Witness 0 Length:72
        0070: .. .. 30 .. .. .. .. .. .. .. .. .. .. .. .. .. DER start
        0070: .. .. .. 45 .. .. .. .. .. .. .. .. .. .. .. .. DER length: 69
        0070: .. .. .. .. 02 .. .. .. .. .. .. .. .. .. .. .. DER int
        0070: .. .. .. .. .. 21 .. .. .. .. .. .. .. .. .. .. DER R length: 33
        0070: .. .. .. .. .. .. 00 f1 62 2d 41 47 f1 85 6c ad
        0080: c3 12 df 06 6e 5a 19 b3 82 b2 0a 45 d6 a1 6e fb
        0090: f9 12 b9 4e ac 5e bb .. .. .. .. .. .. .. .. .. DER R: 00f1622d4147f1856cadc312df066e5a19b382b20a45d6a16efbf912b94eac5ebb
        0090: .. .. .. .. .. .. .. 02 .. .. .. .. .. .. .. .. DER int
        0090: .. .. .. .. .. .. .. .. 20 .. .. .. .. .. .. .. DER S length: 32
        0090: .. .. .. .. .. .. .. .. .. 36 cf e4 f3 a1 e2 34
        00a0: 2c 18 5a a0 16 8d be 0e 38 8c 31 99 d6 d0 d7 4d
        00b0: ed 41 4b c3 78 7e 41 66 9f .. .. .. .. .. .. .. DER S: 36cfe4f3a1e2342c185aa0168dbe0e388c3199d6d0d74ded414bc3787e41669f
        00b0: .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. .. DER sighash type byte: 1
        00b0: .. .. .. .. .. .. .. .. .. .. 21 02 cd cf e7 b2
        00c0: fa cd 6a 06 8f a0 fb 0a c5 aa 02 fe e4 09 95 ef
        00d0: 6a 7b d0 6a 54 d6 c7 58 98 8a d8 fa
        
      • P2TR(Key Path)的 Witness 只包含一个元素

        Tx dbef583962e13e365a2069d451937a6de3c2a86149dc6a4ac0d84ab450509c91 是花费 P2TR (Key Path) 的例子,它的 Witness 为:

        1
        2
        3
        4
        5
        6
        7
        8
        
        0050: .. 01 .. .. .. .. .. .. .. .. .. .. .. .. .. .. vin0 Witness Count: 1
        0050: .. .. 41 .. .. .. .. .. .. .. .. .. .. .. .. .. vin0 Witness 0 Length:65, schnorr_sig (64 bytes) + sig_hash (1 bytes)
        0050: .. .. .. e6 e1 fe 41 52 4e 65 e3 04 0b c3 d0 80 schnorr_sig
        0060: a1 36 34 5c 2c 80 6e b7 f3 36 dd 6a 7a 79 e9 05
        0070: 4b 0d 1f c6 a8 d8 36 66 7e f6 e9 f2 18 8c d1 27
        0080: 0a b2 8e 5e 0e b6 42 ea c8 9f 2e c5 0a 32 ca 54
        0090: aa f9 d6
        0090: .. .. .. 01                                     sig_hash: SIGHASH_ALL (0x01)
        

        *上面例子中 signature 占 65 字节。当 sig_hash 为 SIGHASH_DEFAULT(0x00)时,sig_hash 可以省略,这时 signature 只占 64 字节,比如37777defed8717c581b4c0509329550e344bdc14ac38f71fc050096887e535c8 首个输入就是 signature 只占 64 字节的例子。

      • 如果在花费 P2TR UTXO 时,Witness 至少包含两个元素,则是 P2TR (Script Path),即通过 Witness 中元素的个数来决定使用 Key Path(Witness 元素个数为 1)还是 Script Path(Witness 元素个数大于等于 2)。

        Tx 905ecdf95a84804b192f4dc221cfed4d77959b81ed66013a7e41a6e61e7ed530 是花费 P2TR (Script Path) 的例子(它是一个 2-of-2 多签脚本),它的 Witness 为:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        
        0070: .. .. .. .. .. .. 04 .. .. .. .. .. .. .. .. .. vin0 Witness Count: 4
        0070: .. .. .. .. .. .. .. 41 23 b1 d4 ff 27 b1 6a f4 vin0 Witness 0 Length:65 (0x41)
        0080: b0 fc b9 67 2d f6 71 70 1a 1a 7f 5a 6b b7 35 2b
        0090: 05 1f 46 1e db c6 14 aa 60 68 b3 e5 31 3a 17 4f
        00a0: 90 f3 d9 5d c4 e0 6f 69 be bd 9c f5 a3 09 8f de
        00b0: 03 4b 01 e6 9e 8e 78 89 01 .. .. .. .. .. .. ..
        00b0: .. .. .. .. .. .. .. .. .. 40 0f d4 a0 d3 f3 6a vin0 Witness 1 Length:64 (0x40)
        00c0: 1f 10 74 cb 15 83 8a 48 f5 72 dc 18 d4 12 d0 f0
        00d0: f0 fc 1e ed a9 fa 48 20 c9 42 ab b7 7e 4d 1a 3c
        00e0: 2b 99 cc f4 ad 29 d9 18 9e 6e 04 a0 17 fe 61 17
        00f0: 48 46 44 49 f6 81 bc 38 cf 39 .. .. .. .. .. ..
        00f0: .. .. .. .. .. .. .. .. .. .. 44 20 fe be 58 3f vin0 Witness 2 Length:68 (0x44)
        0100: a7 7e 49 08 9f 89 b7 8f a8 c1 16 71 07 15 d6 e4
        0110: 0c c5 f5 a0 75 ef 16 81 55 0d d3 c4 ad 20 d0 fa
        0120: 46 cb 88 3e 94 0a c3 dc 54 21 f0 5b 03 85 99 72
        0130: 63 9f 51 ed 2e cc bf 3d c5 a6 2e 2e 1b 15 ac ..
        0130: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 41 vin0 Witness 3 Length:65 (0x41)
        0140: c0 2e 44 c9 e4 7e ae b4 bb 31 3a de cd 11 01 2d
        0150: fa d4 35 cd 72 ce 71 f5 25 32 9f 24 d7 5c 5b 94
        0160: 32 77 4e 14 8e 92 09 ba f3 f1 65 6a 46 98 6d 5f
        0170: 38 dd f4 e2 09 12 c6 ac 28 f4 8d 6b f7 47 46 9f
        0180: b1
        

        这个 Witness 中一共有 4 个元素。Witness 最后一个元素是 control block:

        1
        2
        3
        
        c0                                                               # leaf version and parity bit
        2e44c9e47eaeb4bb313adecd11012dfad435cd72ce71f525329f24d75c5b9432 # internal key P
        774e148e9209baf3f1656a46986d5f38ddf4e20912c6ac28f48d6bf747469fb1 # hash e
        

        Witness 倒数第二个元素是 Script:

        1
        2
        3
        4
        
        20febe583fa77e49089f89b78fa8c116710715d6e40cc5f5a075ef1681550dd3c4ad20d0fa46cb883e940ac3dc5421f05b03859972639f51ed2eccbf3dc5a62e2e1b15ac
              
        # 对应 Script:
        febe583fa77e49089f89b78fa8c116710715d6e40cc5f5a075ef1681550dd3c4 OP_CHECKSIGVERIFY d0fa46cb883e940ac3dc5421f05b03859972639f51ed2eccbf3dc5a62e2e1b15 OP_CHECKSIG
        

        Witness 倒数第二个元素之前的所有元素都是“Script 的参数”,在这个 2-of-2 多签的例子中,是两个 Schnorr 签名。

        如何校验这个 Witness 是合法的呢?具体规则在 BIP341 中,简单地总结有两点:

        1. 检查 Script 确实在 MAST 上;
        2. 脚本 Script 执行完成后,检查栈上留下 True。

        这个 2-of-2 多签例子中,脚本为 <P1> OP_CHECKSIGVERIFY <P2> OP_CHECKSIG,输入参数是 [sig(P2), sig(P1)],只要签名是正确的,则执行完成后,栈上留下的就是 True。

        Control Block 下面再举例说明一下 Control Block。对于下图所示的 MAST,其中一共有 5 个叶子节点(即 5 个脚本),如果花费这个 P2TR 时,想使用脚本 D,除公开脚本 D 源码外,只用提供 C/E/AB 三个哈希值就可以证明脚本 D 确实在 MAST 上了。我们并不需要公开其它脚本(即 A/B/C/E)的源码。 完整的 Control Block 如下:
         
            <control byte with leaf version and parity bit> <internal key P> <C> <E> <AB>
            

        铭文数据实际上存储在 P2TR(Script Path)的 Witness 中,后文会详细讲解。

  • BIP 342 对比特币的脚本语言进行了修改,使比特币的脚本系统与 BIP 340 和 BIP 341 中的所有更新兼容,能够读取 Schnorr 签名。此外,在升级前,比特币脚本的大小被限制为 10000 字节,可以在比特币代码中看到:参考1 参考2

    1
    2
    3
    4
    5
    
    // Maximum script length in bytes
    static const int MAX_SCRIPT_SIZE = 10000;
    ...
        if (script.size() > MAX_SCRIPT_SIZE)
            return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
    

    BIP 342 中将这一限制移除了,脚本长度仅隐式地受区块权重大小限制,相当于约 4 MB 的大小。

SegWit 与 Taproot 两次升级,让比特币具有了更好的可扩展性和隐私性,同时,升级带来的限制较少、价格低廉的链上数据存储空间也使铭文的诞生成为可能。

4 Ordinal Theory

2022 年 12 ⽉,Casey Rodarmor 提出了序数理论(Ordinal Theory),包括序数和铭文两个部分。

4.1 序数

比特币以“聪”(satoshi)为最小计价单位,1 比特币等于 $10^8$ 聪。比特币是同质、可互换的,也就是说比特币之间是没有任何区别的。而序数理论,就是通过一套额外定义的编号方案,对从创世区块开始,网络上所有被创建和转移的“聪”进行编号,赋予每个“聪”一个编号,使其被唯一标识出来,该编号由聪的挖掘顺序确定,在转账过程中,该编号遵循“先进先出”的顺序。由于编号和转移方案都依赖于顺序,因此得名 Ordinal “序数”。

以上描述使用了序数理论中的说法,但值得注意的是,实际的比特币实现中,并不存在“聪”这一实体,“聪”仅是比特币最小计价单位的名称,不应当认为是聪“构成”了比特币,或比特币“包含”聪。因此,序数理论及其拥护者使用的“一个聪”、“每个聪”等说法是不准确的,正如我们不会对长度单位用“每个米”、或者对质量单位用“一个克”这样的说法一样。另外,每一笔比特币交易本质上都只是对 UTXO 的销毁与创建,这一过程中并不存在一个不变的“聪”的转移,序数理论仅仅是在其独立于比特币协议的方案层面“规定”了销毁和新建的 UTXO 存在序号上的联系,比特币协议并没有正式承认这种编号方式。

序数理论不需要单独的代币、另一个区块链或对比特币的任何更改。它现在就可以工作。

比特币总量是 2100 万个,每个比特币包含 $10^8$ 个聪。因此,比特币网络上⼀共有 2100 万亿个聪。序数将这些聪区分出来,为每个聪进行唯⼀编号,编号根据它们被开采的顺序而定。

表示

  • 整数符号:例如 2099994106992659 。表示该聪按照挖掘顺序所分配的序号。
  • ⼗进制符号:例如 3891094.16797 。第⼀个数字表示挖掘该聪的区块⾼度,第⼆个数字表示聪在区块中的偏移量。
  • 度数符号:例如 3°111094′214″16797‴ 。第⼀个数字是周期,从0开始编号;第⼆个数字是减半纪元的区块索引;第三个数字是难度调整期间的区块索引;最后⼀个数字是聪在区块中的偏移量。
  • 百分比符号:例如 99.99971949060254% 。表示该聪在比特币供应量中的位置,以百分比表示。
  • 名称:例如 Satoshi 。使用字符 a 到 z 对序号进行编码的名称。

转移

假设用户 A 通过挖矿获得了第 100-109 个聪,这 10 个聪存放在同⼀个 id 为 abc123 的 UTXO 中。当 A 要支付给用户 B 5 个聪时,使用 abc123 作为交易输入,其中 5 个聪发送给 B,5 个聪作为找零返回给 A。这两份 “5个聪”都是⼀个整体,分别存放在 id 为 abc456 和 abc789 的 UTXO 中。在上述交易中,聪的流转路径为:

  1. 挖矿产⽣ 10 个聪,编号是 [100, 110),存放在 id 为 abc123 的 UTXO 中。

  2. A 进行转账,10 个聪分成两份,每份 5 个聪。根据序数“先进先出”的原则,聪的编号排序是按照它们在交易输出中的索引决定的。假设输出的顺序先是 A,然后是 B,那么:
    • A 剩余5个聪的序号是 [100, 105),存放在 id为 abc456 的 UTXO 中;
    • B 的 5 个聪的序号是 [105, 110),存放在 id 为 abc789 的 UTXO 中。
  3. 如果后续 A 要再进行转账,比如转账给 C,流程也和上述过程类似。

    图6 聪的转账过程

    稀有度

聪的稀有度可以根据挖掘顺序来定义。以下是不同聪的稀有程度:

表4 聪的稀有度说明
稀有度 含义
common 除区块第⼀个聪外的任何聪(总供应量为 2100 万亿)
uncommon 每个区块的第⼀个聪(总供应量为 6929999)
rare 每个难度调整期的第⼀个聪(总供应量为3437)
epic 每次减半后的第⼀个聪(总供应量为 32)
legendary 每个周期的第⼀个聪(总供应量为 5)
mythic 创世区块的第⼀个聪(总供应量为 1)

不同稀有度的聪在市场上具有不同的价值,能吸引潜在的收藏者和投资者。

4.2 铭文

单个聪可以刻有任意内容,创建独特的比特币原⽣的数字文物(Digital Artifact),也称为铭文(Inscription)。铭文可以保存在比特币钱包中并使用比特币交易进行传输,与比特币本身⼀样持久、安全。

铭文内容模型类似于网络内容模型。一条铭文由内容类型(也称为 MIME 类型)和内容本身组成,后者是一个字节串。这使得铭文内容可以从Web服务器返回,并用于创建 HTML 铭文,这些铭文可以使用其他铭文的内容。

铭文内容完全存储在链上,在 Taproot 脚本路径花费脚本中存储。Taproot 脚本对其内容的限制非常少,而且还可以获得见证折扣,使得铭文内容存储相对经济。

创建

Taproot 升级中 MAST 的⼀个重要特性是脚本在它被花费之前不会在链上显示。因此,为了让铭文显示在链上,通常需要创建两笔交易:⼀笔 commit 交易用来创建铭文;另⼀笔 reveal 交易花费第⼀笔交易的输出,从而在链上显示脚本信息。具体而言:

  1. ⾸先,在 commit 交易中创建⼀个 commit 到包含铭文内容的脚本的 Taproot 输出;存储的格式是Taproot,即前⼀笔交易的输出是 P2TR。
  2. 在 reveal 交易中消费 commit 创建的输出,即通过将那笔铭文对应的 UTXO 作为输入,发起交易。随后,其对应的铭文内容被公开至网络。

铭文内容存储在被称为“信封”(Envelope)的结构中,即用OP_FALSEOP_IFOP_ENDIF等操作包裹任意数量的铭文数据。由于信封实际上是无操作的,因此不会改变包含脚本的语义,也不会影响正常的交易,且可以与任何其他锁定脚本结合使用。

例如,包含字符串“ Hello, world! ”的文本铭文的序列化如下:

1
2
3
4
5
6
7
8
OP_FALSE
OP_IF
  OP_PUSH "ord"
  OP_PUSH 1
  OP_PUSH "text/plain;charset=utf-8"
  OP_PUSH 0
  OP_PUSH "Hello, world!"
OP_ENDIF

首先,将字符串 “ord” 入栈,以避免铭文与信封的其他用途的混淆。OP_PUSH 1 表示下一个压栈操作包含内容类型,而 OP_PUSH 0 表示随后的压栈操作包含内容本身。前文提到 Taproot 升级修改了部分脚本资源限制,但升级中保留了脚本元素大小的限制条件,即初始栈和压栈操作符的元素最大为 520 字节:(参考 比特币源码BIP 342

1
2
// Maximum number of bytes pushable to the stack
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;

因此,对于大型铭文,必须进行多次压栈操作。

铭文底层解析

为更加清楚地阐释铭文原理,这里以一个实际的铭文交易为例进行说明:[1c5435cd882e98ec5532a5006a8afe313207f18dd54042219ac57587080a80b8]([Transaction: 1c5435cd882e98ec5532a5006a8afe313207f18dd54042219ac57587080a80b8 Blockchain.com](https://www.blockchain.com/explorer/transactions/btc/1c5435cd882e98ec5532a5006a8afe313207f18dd54042219ac57587080a80b8))

交易的十六进制数据可由此获得:mempool.space (hex)

原始数据如下:

1
2
3
4
5
6
7
0100000000010163 a2877c846b01bacb b529de2d2fa45243 2620857e76df70b2 b52dc3b2b2f06300 00000000fdffffff 0110270000000000 00160014311875fd
a80db86117dc560d 43d3dfc63275e4c8 0340d25a9c030e3e f58f42e0de170681 9ae0c70967508c5a 0106d369553fd4f8 12a8565d644cbee3 ed357a4ab146aadf
e02285971e8b4fab 27743f4f85c62a44 8095cc20aa8bd547 3ac0576dfc551b8c 92832b312ad87422 235e82f614c7e66a 752b5627ac006303 6f7264010109696d
6167652f706e6700 4c9489504e470d0a 1a0a0000000d4948 4452000000180000 00180806000000e0 773df80000005b49 44415478da636018 05a30008fee3c194
1bbeae3b1127a6d4 12b841dbe637d1c4 12828653c5024278 705b400226cf7034 57627339f9166033 8caa160c5824e308 be919a4c7105cff0 0922aa95a658d23d
55ea03aaba966616 0000ab897efb3d3f f6f5000000004945 4e44ae4260826821 c1aa8bd5473ac057 6dfc551b8c92832b 312ad87422235e82 f614c7e66a752b56
2700000000

原始数据的解析如下:

表5 铭文交易原始数据解析
十六进制数据 类型 含义
01000000 uint32 版本 1
0001 2 octets 见证标识
01 varint 交易输入数量
输入 1    
63a2877c846b01ba cbb529de2d2fa452 432620857e76df70 b2b52dc3b2b2f063 32 octets 引用交易的哈希
00000000 uint32 先前输出的索引
00 varint 脚本签名长度 (Segwit 长度为0)
fdffffff 4 octets 序列号
01 varint 交易输出数
输出 1    
1027000000000000 int64 以聪为单位的数量(0.0001 BTC)
16 varint 脚本长度 (0x16 = 22)
0014311875fda80d b86117dc560d43d3 ` dfc63275e4c8` 22 octets 锁定脚本
见证数据    
03 varint 见证数
见证部分 1    
40 varint 见证部分长度 (0x40 = 64)
d25a9c030e3ef58f 42e0de1706819ae0 c70967508c5a0106 d369553fd4f812a8
565d644cbee3ed35 7a4ab146aadfe022 85971e8b4fab2774 3f4f85c62a448095
64 octets 见证数据,从长度可以看出是签名
见证部分 2    
cc varint 见证部分长度 (0xcc = 204)
20aa8bd5473ac057 6dfc551b8c92832b 312ad87422235e82 f614c7e66a752b56
27ac0063036f7264 010109696d616765 2f706e67004c9489 504e470d0a1a0a00
00000d4948445200 0000180000001808 06000000e0773df8 0000005b49444154
78da63601805a300 08fee3c1941bbeae 3b1127a6d412b841 dbe637d1c4128286
53c5024278705b40 0226cf7034576273 39f91660338caa16 0c5824e308be919a
4c7105cff00922aa 95a658d23d55ea03 aaba9666160000ab 897efb3d3ff6f500
00000049454e44ae 42608268
204 octets 见证数据,包含铭文实际数据
见证部分 3    
21 varint 见证部分长度 (0x21 = 33)
c1aa8bd5473ac057 6dfc551b8c92832b 312ad87422235e82 f614c7e66a752b56 27 33 octets 见证数据,长度与公钥一致,P2WPKH
00000000 unit32 Lock time 设为 0 表示交易立即传播和执行

该交易中,见证的第二部分包含了铭文的实际数据,铭文相关的操作码如下:

1
2
3
4
5
6
7
OP_IF          63
OP_FALSE       00
N/A            01-4b
OP_PUSHDATA1   4c
OP_PUSHDATA2   4d
OP_PUSHDATA4   4e
OP_ENDIF       68

原始数据块长度标识规则:

  • 如果第一个字节小于 4c 直接用其作为长度,
  • 如果第一个字节是 4c 后一字节为长度,
  • 如果第一个字节是 4d 后两个字节为长度,
  • 如果第一个字节是 4e 后四个字节为长度。

铭文头/签名 (OP_IF + len + "ord" + 0101,可以直接搜索这一序列):

1
63 03 6f 72 64 01 01

Mime 字符串长度:

1
09

Mime 文本 (ASCII):

1
69 6d 61 67 65 2f 70 6e 67

OP_FALSE (将 Mime 和数据分开):

1
00

数据块长度 (0x94 = 148):

1
4c 94

数据块内容:

1
2
3
4
5
6
7
8
89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 18
00 00 00 18 08 06 00 00 00 e0 77 3d f8 00 00 00 5b 49 44 41
54 78 da 63 60 18 05 a3 00 08 fe e3 c1 94 1b be ae 3b 11 27
a6 d4 12 b8 41 db e6 37 d1 c4 12 82 86 53 c5 02 42 78 70 5b
40 02 26 cf 70 34 57 62 73 39 f9 16 60 33 8c aa 16 0c 58 24
e3 08 be 91 9a 4c 71 05 cf f0 09 22 aa 95 a6 58 d2 3d 55 ea
03 aa ba 96 66 16 00 00 ab 89 7e fb 3d 3f f6 f5 00 00 00 00
49 45 4e 44 ae 42 60 82

(铭文中可能有多个数据块需要拼接,此例中只有一个)

OP_ENDIF (标识铭文结束):

1
68

接下来在浏览器控制台中用几行 JS 代码即可还原铭文数据

首先创建一个用于将十六进制字符串转换为字节数组的辅助函数:

1
2
  const toBytes = (hex) =>
    Uint8Array.from(hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));

解码 Mime 类型,得到 ` image/png` :

1
2
3
  const mime = new TextDecoder()
    .decode(toBytes('696d6167652f706e67'))
  console.log(mime) 

获取文件字节流数据:

1
  const data = toBytes('89504e470d0a1a0a0000000d4948445200000018000000180806000000e0773df80000005b4944415478da63601805a30008fee3c1941bbeae3b1127a6d412b841dbe637d1c412828653c5024278705b400226cf703457627339f91660338caa160c5824e308be919a4c7105cff00922aa95a658d23d55ea03aaba9666160000ab897efb3d3ff6f50000000049454e44ae426082')

最后重建文件并在浏览器中打开:

1
2
3
  const file = new File([data], 'myFile', {type: mime})
  const url = URL.createObjectURL(file)
  open(url)

下图就是铭文中铭刻的内容了,是一张 24 x 24,大小 148 字节 的图片:

图7 铭文中的图片

5 BRC-20

BRC-20 代币标准是由匿名开发者 domo(@domodata)于 2023 年 3 月 8 日创建的。该标准借助铭文功能实验性地在比特币上创建同质化代币。“BRC-20”名字借鉴于以太坊 ERC-20 代币标准。

BRC-20 代币通过在比特币铭文里存储 JSON 代码数据进行代币记账,目前仅有部署、铸造和转帐三种功能,不具备以太坊上图灵完备的智能合约功能。BRC-20 代币每⼀次部署、铸造和转移都产⽣⼀个新的铭文,因此每次操作都需要 commit 和 reveal 两次交易。

1
2
3
4
5
6
7
{
  "p": "brc-20",     // Protocol: 帮助线下的记账系统识别和处理BRC-20事件
  "op": "deploy",    // Operation: 事件类型 (Deploy, Mint, Transfer)
  "tick": "ordi",    // Ticker: brc-20代币的标识符,⻓度为4个字⺟(可以是emoji)
  "max": "21000000", // Max supply: brc-20代币的最大供应量
  "lim": "1000"      // Mint limit: 每次brc-20代币铸造量的限制
}

尽管根据其提出者的说法,这仅是一个对可互换性的实验性标准,但 BRC-20 如今已在比特币社区内引起了极大的关注,人们纷纷开始创建自己的 BRC-20 代币。同时,像钱包服务和市场等序数基础设施提供商,已经开始集成 BRC-20,以使其用户能够铸造和交换 BRC-20 代币。

目前比较火热的 BRC-20 代币项目有:

  • $ORDI:比特币上的⾸个 BRC-20 代币,利用 Ordinals 协议在聪上刻录信息。ORDI 拥有 2100 万枚硬币的限量供应,为 NFT 和代币引入了创新的可能性,根据挖掘和转移顺序分配序数。

  • $SATS:将比特币区块链上的最小单位聪转化为⼀个可交易和可收藏的代币,总量与比特币相同,每个 SATS都有⼀个唯⼀的序号。SATS 是 BRC-20 目前拥有持币地址最多的项目。

  • $MUBI:MultiBit 是首个为 BRC-20 与 ERC-20 代币间的跨网络转移的双向跨链桥。通过促进这些代币更便捷的流动性,MultiBit 加强了跨链互操作性,目的是以安全和用户友好的方式,促进 BRC 和 ERC 代币的流动性和可访问性。

局限性

虽然 BRC-20 代币被称作同质化代币,但由于其基于铭文实现,只能以设定的增量进行交易,因此实质上更接近半同质化代币。用户需要创建铸币 JSON 铭文来定义要铸造数量,然后通过交易手续费拍卖与其他人竞争优先权,以最终完成铸币。为了在比特币网络上以原生方式交易 BRC-20 代币,卖方需要创建转账铭文,将原始铸币铭文分割成更小的块,以便能出售预定义批次的代币。如果想购买特定数量的 BRC-20 代币,买方必须找到愿意出售该数量代币的卖方。另外,要确定钱包中 BRC-20 代币的余额,仅依靠比特币全节点是不够的,用户还需要自己运行或信任第三方的链下索引器,由索引器通过规则集解析铭文。需要注意的是,这种中心化的索引方式具有极高的共识风险,若不同交易平台或交易双方使用不同的索引器,那么 BRC-20 代币的所有权可能产生分歧。

相较于 ERC-20

其实 BRC-20 与 ERC-20 之间的可比性基本仅限于名称。ERC-20 是以太坊上基于智能合约的同质化代币标准,而 BRC-20 是在比特币上基于序数铭文创建半同质化代币的一种方式。由于比特币有意限制了可编程性,目前 BRC-20 代币基本没有实际功能,比 ERC-20 简单、局限性更多。同时 BRC-20 代币的流动性也更差。

影响

序数、铭文、BRC-20 等新叙事一方面为比特币吸引了注意力,使比特币网络活跃程度明显上升,另一方面则加重了网络拥堵,交易手续费大幅提升。以下是几个关键指标:

  1. 内存池

    2023 年 2 月 至 2024 年 1 月间,比特币内存池容量显著增长,目前已接近 600 MvB。

    图8 2023.2-2024.1 比特币内存池容量变化

    目前,交易的阈值费率已经来到了 22.3 sat/vB,也就是说手续费低于该费率标准的交易将被内存池满的比特币节点直接拒绝。当前内存占用达 1.62GB,远高于 Bitcoin Core 默认分配的 300 MB 内存,未确认的交易多达 27 万笔。

    图9 交易阈值费率/内存占用/未确认交易数

  2. 平均手续费

    由下图可以看出,比特币交易平均手续费明显上升,峰值超过 30 美金,较 2023 年初提升超 30 倍。

    图10 比特币交易平均手续费变化
    1. 搜索量

      2023 年全年中“Bitcoin”的谷歌搜索量显著高于“Ethereum”、“Coinbase”、“NFT”等词条,且呈现明显的上升趋势。侧面反映了铭文和 BRC-20 为比特币生态吸引了更多关注。

    图11 "Bitcoin"词条的谷歌搜索量变化

值得一提的是,比特币社区中对序数铭文、BRC-20 等新叙事看法仍不统一,这也反映在了对上述指标的解读上:

  • 铭文、BRC-20的拥护者认为,序数和铭文能够拓展比特币的应用场景,吸引更多的开发者和用户,同时提升比特币网络的活跃度。他们倾向于正面解读交易手续费的大幅上涨,认为随着交易量增加和交易费用上升,比特币矿⼯的收益更能得到保障,从而吸引更多算力加入比特币网络,使得比特币网络更加安全、健壮和去中心化。这方认为上涨的手续费是比特币网络不可或缺的“安全预算”。另外,他们提出可以通过建设闪电网络等二层扩展方案来解决交易手续费高企的问题。

  • 而比特币原教旨主义者、铭文和 BRC-20 的反对者认为这类应用是对 Taproot 升级的滥用,随着类似的应用的增多,比特币网络可能被阻塞,影响比特币的转账甚至出块,带来“劣币驱逐良币”的效应,违背比特币最初成为“点对点电子现金”、数字硬通货的初衷,即便二层扩展能够一定程度缓解手续费的问题,也不能成为毫无价值的 BRC-20 挤占算力资源的理由。比特币常被认为是“数字黄金”,而这方认为“金子就该是纯粹的,不应掺入其他杂质”。比特币核心开发者 Luke Dash Jr.(@LukeDashjr)称铭文是在利用 Bitcoin Core 的漏洞,并提到“这个漏洞最近在 Bitcoin Knots v25.1 中得到了修复, Bitcoin Core 在即将发布的 v26 版本中仍然存在漏洞。我只能希望它将在明年的 v27 版本之前最终得到修复。”

6 总结

本文深入最底层,详细介绍了比特币序数理论、铭文和 BRC-20 代币相关的技术知识。以 Colored Coin 为先驱,经过 SegWit 和 Taproot 两次升级,比特币交易拥有了更大的存储空间、能支持更复杂的脚本。随之而来的序数理论,提出了对“聪”进行排序标记的方法,而铭文则基于此定义了一套编码规则将网络媒体内容存储在链上。BRC-20 标准基于序数理论和铭文,通过将账本铭刻在聪上实现了在比特币上发行同质化代币。当前,比特币社区中对于铭文、BRC-20 价值的讨论仍莫衷一是,这一系列新叙事究竟是颠覆比特币生态的革新者,还是昙花一现的投机客,我们仍需拭目以待。不过这样的讨论本身,倒是很好地彰显了去中心化的 Web3 世界所独有的魅力。


参考

[1] BIP 340

[2] BIP 341

[3] BIP 342

[4] Ordinal Theory

[5] BRC-20 docs

This post is licensed under CC BY 4.0 by the author.