随着Ordinals协议的诞生,其为比特币提供了编号和铭文的功能,从而拓宽了比特币生态系统的产品范围,并为比特币生态带来了新的活力。在本文中,我们将深入探讨Ordinal协议的细节,包括如何对每个比特币进行编号和追踪,以及铭文与编号之间的关系。但在深入探讨这个主题之前,我们需要首先了解一些比特币的基本背景,以帮助我们更好地理解后续内容。
完成本文的阅读后,你将掌握比特币的交易机制和支付模型,了解Ordinals如何为每个聪实现编号和追踪,以及铭文是如何创建和交易的。此外,你还将了解不同类型的钱包之间的差异。
来源:Spectrum Lab
一、比特币背景
比特币采用了一个类似于现金的交易模型(cash system),其支付方式基于一种称为UTXO的模型,这与传统的基于账户余额的模型有所不同。举例而言:在银行的账户记账模型流程中,当A向B转账100元时,银行会记录三个步骤,这三个步骤构成了一个交易过程。第一步是从A的账户中扣除100元,这个步骤的记录ID为tid1。第二步是将100元存入B的账户中,这个步骤的记录ID为tid2。第三步是记录一笔转账记录,该记录将tid1和tid2关联起来,表示A账户减少100元,B账户增加100元。这样,A和B之间的转账关系就被记录下来,并且可以在未来查询与追踪。现在,我们将通过对于UTXO和支付模型的介绍,讲解比特币的支付方式。
UTXO
在比特币区块链中,所有的余额都是存储在一个名为“未花费交易输出”(Unspent Transaction Output, UTXO)的列表中。每个UTXO都包含一定数量的比特币,以及这些比特币的所有者信息,并标明是否可用。可以将其想象成一张署有持有人姓名的现金支票,只要持有人在上面签名,就可以将使用权转让给他人。对于特定的地址,其所有的UTXO金额加起来即为该地址钱包的余额。通过遍历所有的UTXO,我们可以获取每个地址的当前余额。将所有的UTXO金额加总,则为当前全部流通的比特币。
在比特币的交易结构中,每笔交易都包括若干个输入和输出,其中每个输入是对一个已有的UTXO的引用,而每个输出则指定了新的资金接收地址及相应的金额。一旦一笔交易被发起,其输入部分所引用的UTXO便会被暂时锁定,以防止在交易完成前被重复使用。只有当这笔交易成功地被矿工打包到一个区块(Block)并获得网络确认后,相关的UTXO状态才会发生变化。具体来说,用于交易输入的UTXO将从UTXO列表中移除,表示它们已经被消费,而交易的输出则会生成新的UTXO,并添加到UTXO列表中。可以理解为,旧的现金支票被使用后失效,产生了新的现金支票,其所有权属于新的持有人。
值得强调的是,每个UTXO只能在一笔交易中被使用一次。一旦它作为输入被消费,它就会永久地从UTXO列表中移除。同时,新生成的输出作为新的UTXO加入到列表中。UTXO列表是不断变化的,随着每个新区块的创建,它会相应地进行更新。并且,通过分析区块链中的交易历史,我们能够重建在任何给定时间点的UTXO列表状态。
此外,一笔交易的总输入金额通常会略微超过其总输出金额。这个差额,称为交易费用(Transaction fee)或网络费(Network fee),是作为激励给予负责将交易打包到区块的矿工的。网络费的大小与交易的复杂性成正比,因此,一笔包含更多输入和输出的交易通常需要支付更高的网络费。
现在,为了更加形象地理解比特币的交易结构,我们将通过一个具体的示例进行深入分析。比特币的交易结构如下,其中vin和vout这两个变量分别代表着比特币交易的 “输入” 与 “输出”。比特币的交易并不像传统的账户余额模型记录账户形的数据变化,而是通过输入和输出来表示。
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
const int32_t nVersion;
const uint32_t nLockTime;
我们可以在blockchain.com随机选一个交易记录来分析,下图展示了 Hash ID为0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2 的交易。其包含了一个输入和两个输出。
通过使用 bitcoin-cli 的命令getrawtransaction
和decoderawtransaction
,我们可以查看上述交易的底层结构:
{
"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",
}
]
}
在比特币网络中,交易输出包含两个重要信息:地址(公钥哈希)和 金额(以比特币为单位)。如果一个交易的输出没有在其他交易的输入中使用,那么这个交易输出就被称为未消费交易输出(UTXO)。谁拥有 UTXO 中公钥对应的私钥,谁就有权使用(即花费)这个 UTXO。
我们观察一下上面代码中的“vin”中的信息,它表示这个交易所花费的 UTXO 来自于另外一个交易(其 id 为7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18)的第 0 个输出(一个交易的输出可以有多个,索引从 0 开始编号),我们可以从历史交易中查找出这个 UTXO 的金额(比如为 0.1),所以这个交易中这个用户花费了 0.1 BTC,数值 0.1 不需要显式地写在 交易中,而是通过查找 UTXO 信息来得到的。这个交易的“vout”有两个输出,这两个输出为两个新的UTXO,对应了新的余额以及持有人,直到有另外的交易把它们作为输入消费掉。
支付模型
为了更好地理解比特币网络的支付模型,我们通过一个例子介绍由A支付给B金额为n的比特币的支付流程。下图展示了用户A发送3个比特币给用户B的过程。
- 对于用户A,首先需要确定其拥有的所有UTXO集合,即用户A可以支配的所有比特币;
- A从这个集合中选取一个或者多个UTXO作为交易的输入,这些输入的金额之和为m(2+0.8+0.5=3.3 BTC)要大于需要支付的金额n(3 BTC);
- 用户A为交易设置两个输出,一个输出支付给B的地址,金额是n(3 BTC),另一个输出支付给A自己的一个找零地址,金额为m-n-fee(3.3-3-0.001=0.299 BTC)。用户的钱包通常由多个地址组成,一般情况下每个地址只使用一次,找零默认返回给一个新的地址;
- 等矿工将这笔交易打包上链进行确认后,B就可以收到这笔交易信息。因为区块的大小有上限(约1 MB),所以矿工会优先确认交易费率(
fee_rate=fee/size
)高的交易,以获取最高的手续费回报。我们可以在mempool看到实时的挖矿 transaction fee 的情况。如果我们在转账过程中如果想要最快进行确认,就可以选择高优先权(High Priority)或者自定义(custom)一个合适的交易费率;
二、聪的编号与追踪
比特币总量是2100万个,每个比特币包含10^8个聪(Satoshi, Sat)。因此,比特币网络上一共有2100万*10^8个聪。Ordinals协议将这些聪区分出来,为每个聪进行唯一编号。本节将介绍这个协议是如何做到为每一个聪进行唯一编号,并且如何追踪其所在的账户。此外,还会简介对于聪的稀有度份分类。
聪的编号
根据 Ordinals 协议,聪的编号是根据它们被开采的顺序而定。下图展示了第0个区块挖出的第0个聪的表示方式。
对于聪的表达方式有多种:
- 整数符号:例如2099994106992659,表示该聪按照挖掘顺序所分配的序号。
- 十进制符号:例如3891094.16797,第一个数字表示挖掘该聪的区块高度,第二个数字表示聪在区块中的编号。
- 度数符号:例如3°111094′214″16797‴,第一个数字是周期,从0开始编号,第二个数字是减半纪元的区块索引,第三个数字是难度调整期间的区块索引,最后一个数字是区块中sat的索引。
- 百分比符号:例如99.99971949060254%,表示该聪在比特币供应量中的位置,以百分比表示。
- 名称:例如Satoshi。使用字符a到z对序号进行编码的名称。
我们将通过一个例子来讲解如何对新挖出的比特币进行编号。观察比特币区块链的第 795952 个区块,我们可以看到其中第一笔交易Tx 3a1f…b177记录了矿工的奖励(coinbase transaction)。这笔交易包含了新挖出的比特币,这些比特币是作为矿工的打包奖励,以及交易发起者付给矿工的手续费。通过查看下图的输入,我们可以发现其UTXO的id由一串0和区块高度组成。输出的地址则是矿工的钱包地址,金额则是上述的奖励和手续费的总和。
若我们进一步查看输出给矿工的部分,可以看到地址、金额以及所包含的聪的分布情况。如前所述,这些包含了挖矿奖励和手续费。其中,绿色的 sats 编号信息1941220000000000–1941220625000000是挖矿奖励产生的新聪,其余的 712 条聪的记录则对应了该区块中的所有手续费。
我们可以验证一下Sat 1941220000000000这个编号。它的block编号为795952,十进制符号(decimal)为795952.0,意味着挖掘该聪的区块高度为795952,聪在此区块中的编号为0,后面的稀有度(rarity)标记为uncommon,我们将在后面的部分进行详细介绍。
聪的流转
因为每个BTC都是通过挖矿奖励产生的,所以他们都是可溯源的。比特币账户使用UTXO模型。假设用户A通过挖矿获得了第100-110个聪(10个聪是一个整体存放在同一个id为adc123的UTXO中)。当用户A要支付给用户B 5个聪时,他选择使用id为abc123作为交易的输入,其中5个聪给到用户B,5个聪作为找零返回给用户A。这两份5个聪都是一个整体,分别存放在两个id为abc456和abc789的UTXO中。上述UTXO id和聪的数量仅作为例子展示,在实际情况下发送的聪的数量最小限制为546个以及UTXO id也并非以此形式表达。
在上述的交易中,用户A的10个聪的流转路径为:
-
挖矿产生10个聪,编号是[100 *, 110)。*其表示编号为第100到第109个聪存放在id为abc123的UTXO中,其所有者为用户A。
-
在A进行转账时,10个聪分成两份,每份5个聪。这里采用“先进先出”的原则,即聪的编号排序是按照它们在交易输出中的索引决定的。假设输出的顺序先是用户A,然后是用户B,那么用户A剩余5个聪的序号是[100, 105),存放在id为abc456的UTXO中,而用户B的5个聪的序号是[105, 110),存放在id为abc789的UTXO中。
稀有度(Rare Satoshi)
作为Ordinals协议的衍生玩法,聪的稀有度可以根据它们的挖掘顺序来定义。这将导致一些特殊的聪具有不同的稀有度。以下是不同聪的稀有程度:
common
普通级: 除区块第一个聪外的任何聪(总供应量为2100万亿)uncommon
优良级: 每个区块的第一个聪(总供应量为6929999)rare
稀有级: 每个难度调整期的第一个聪(总供应量为3437)epic
史诗级: 每次减半后的第一个聪(总供应量为32)legendary
传奇级:每个周期的第一个聪(总供应量为5)mythic
神话级: 创世区块的第一个聪(总供应量为1)
这种稀有聪的概念可以为比特币生态增加更多的趣味性和价值。不同稀有度的聪可能在市场上具有不同的价值,吸引收藏家和投资者。
三、铭文方式
Ordinals与其他非比特币链上的NFT显著不同。其中,最主要的差异在于,Ordinals的元数据并没有存储在一个特定的位置上。相反,这些元数据被嵌入到交易的见证数据(witness data, witness field)中,这就是为何我们称之为 "铭文(inscription)" 的原因,因为这些数据被像铭文一样“刻”在比特币交易的特定部分上,而这些数据正是附着在特定聪上的。这一铭文过程通过隔离见证(Segregated Witness, SegWit)和“向Taproot支付”(Pay-to-Taproot, P2TR)的方式实现,其中包含了提交(commit)和揭露(reveal)两个阶段,能够将任何形式的内容(如文本、图像或视频)铭刻在指定的聪上。我们将在下文介绍另一种更加直接的存储方式OP_RETURN并阐述其为何没被作为铭文的手段。同时,我们会介绍隔离见证与Pay-to-Taproot是什么,以及他们在铭文中扮演什么角色。最后我们会介绍铭文的方式。
OP_RETURE
在 Bitcoin Core 客户端 0.9 版中,通过采用 RETURN 操作符最终实现了妥协。**RETURN 允许开发者在交易输出上增加 80 字节的非支付数据。**与伪支付不同,RETURN 创造了一种明确的可验证不可消费型输出,此类数据无需存储于 UTXO 集。RETURN 输出被记录在区块链上,它们会消耗磁盘空间,也会导致区块链规模的增加,但它们不存储在 UTXO 集中,因此也不会使得 UTXO 内存池膨胀,更不会增加全节点昂贵的内存代价。
虽然OP_RETURN是一个非常直接的用以存储信息至比特币区块链的手段,它也是一个潜在的铭文方式。但是OP_RETURN的限制使得其在处理元数据存储时面临一些挑战。首先,OP_RETURN只能存储80字节的数据,对于需要存储更大量数据的情况来说,这种限制显然是无法满足的。其次,OP_RETURN数据被存储在交易输出部分,虽然这种数据不存储在UTXO集中,但是它们占用了区块链的存储空间,导致区块链规模的增加。最后,使用OP_RETURN会导致交易费用的提高,因为它需要支付更多的费用来发布这些交易。
隔离见证
相比之下,SegWit提供的新方法则可以克服上述问题。SegWit是比特币的一个重要协议升级,由比特币核心开发者 Pieter Wuille 在 2015 年提出,最终在 2017 年的 0.16.0 版本中被正式采纳。Segregated Witness中的Segregated是分离、隔离的意思,Witness是与交易相关的签名事物。因此,SegWit是将某些交易签名数据(见证数据)与交易分开。
将签名与交易相关数据分离的主要好处是减少了存储在一个比特币块中的数据的大小。这样每个块具有额外的容量来存储更多的交易,也意味着网络可以处理更多的交易,并且发送者支付更低的手续费。从技术上来说就是把脚本签名(scriptSig)信息从基本结构 (base block) 里拿出来,放在一个新的数据结构当中。做验证工作的节点和矿工也会验证这个新的数据结构里的脚本签名,以确保交易有效。Segwit 升级在交易输出中引入了一个新的见证字段,以确保隐私和性能。虽然见证数据不是为了数据存储而设计的,但它实际上给了我们一个存储铭文元数据等内容的机会。我们通过下图来更加形象地理解隔离见证:
Taproot
P2TR是比特币的一种交易输出类型,它是在2021年进行的Taproot升级中引入的,它使得不同的交易条件可以更加隐私地存储在区块链中。在Ordinals的铭文中,P2TR 扮演着至关重要的角色。铭文本质上是将特定的数据内容嵌入到比特币交易中,而Taproot升级,尤其是P2TR,使得这种嵌入数据变得更加灵活和经济。
首先,由于Taproot脚本的存储方式,我们可以在Taproot脚本路径支出脚本中存储铭文内容,这些脚本在内容方面几乎没有任何限制,同时还能获得见证数据的折扣,使得存储铭文内容相对经济。由于Taproot脚本的消费只能从已经存在的Taproot输出中进行,因此,铭文采用了两阶段的提交/揭示流程。首先,在提交交易中,创建了一个承诺包含铭文内容的脚本的Taproot输出。然后,在揭示交易中,消费了由提交交易创建的输出,从而在链上揭示了铭文内容。
这种做法大大降低了对资源的消耗。如果不使用P2TR,见证信息会存储在交易的输出中。这样,只要这笔输出未被消费,见证信息就会一直存储在UTXO集中。相反,如果使用了P2TR,见证信息不会出现在提交阶段生成的交易中,因此它不会被写入UTXO集。只有当这笔UTXO被消费时,见证信息才会在揭示阶段的交易输入中出现。P2TR让元数据能够写入比特币区块链,但却从未出现在UTXO集中。由于维护/修改UTXO集需要更多的资源,因此这种做法可以节省大量资源。
铭文
Ordinals 协议利用了SegWit 放宽了对写入比特币网络内容的大小限制,将铭文内容存储在见证数据中。使其可以存储最大4MB的元数据。Taproot 使得在比特币交易中存储任意见证数据变得更加容易,允许 Ordinals 开发人员 Casey Rodarmor 将旧操作码(OP_FALSE、OP_IF、OP_PUSH)重新用于他所描述的「信封」为被称为「铭文」存储任意数据。
铸造铭文的流程包含以下两个步骤:
- 首先,需要在提交交易中创建一个承诺到包含铭文内容的脚本的Taproot输出。存储的格式是Taproot,即前一笔交易的输出是P2TR (Pay-To-Taproot),后一笔交易的输入,在见证的Taproot script中嵌入特定格式的内容;首先将字符串
ord
入栈,以消除铭文有其他用途的歧义。OP_PUSH 1
指示下一次推送包含内容类型,并OP_PUSH 0
指示后续数据推送包含内容本身。大型铭文必须使用多次数据推送,因为 taproot 的少数限制之一是单个数据推送不得大于 520 字节。此时铭文的数据已对应到交易输出的UTXO上,但是未被公开。 - 其次,需要在揭示交易中消费提交交易创建的那个输出。在这个阶段,通过将那笔铭文对应的UTXO作为输入,发起交易。此时,其对应的铭文内容被公开至全网。
通过上述两个步骤,铭文内容已与被铭刻的UTXO进行绑定。再根据上文介绍的对于聪的定位,铭刻是在其输入的UTXO对应的第一个聪上进行,铭文内容包含在显示交易的输入中。根据上文介绍的对于聪的流转、跟踪的介绍,这个被铭刻上特殊内容的聪可以被转移、购买、出售、丢失和恢复。需要注意的是,不可以重复铭刻,否则后面的铭文是无效的。
我们将通过铭刻一个BTC NFT小图片的例子来详细说明这个过程,这个过程主要包括之前提到的提交(commit)和揭露(reveal)两个阶段。首先,我们看到第一笔交易的Hash ID是2ddf9…f585c。可以注意到,这笔交易的输出不包含见证数据,网页中也没有相关的铭文信息。
接着,我们查看第二阶段的记录,其Hash ID是e7454…7c0e1。在这里,我们可以看到Ordinals inscription 的信息,也就是见证的铭文内容。这笔交易的输入地址是前一个交易的输出地址,而输出的0.00000546BTC(546聪)则是将这个NFT发送到自己的地址。同时,我们也可以在Sat 1893640468329373中找到这个铭文所在的聪。
在比特币钱包中,我们可以看到这个资产。如果我们想要交易这个NFT,可以直接将其发送给其他人的地址,也就是将这笔UTXO发送出去,这样就完成了铭文的流转。
四、 比特币钱包
在我们了解了什么是 Ordinals 生态、聪的流转以及铭文的相关知识后,目前有许多应用场景,无论是 BRC-20,ORC-20,BRC-721,GBRC-721等相关衍生协议的出现,需要我们有对应的钱包来支持和显示出代币信息或者 NFT 小图片。本节我们会介绍一下不同比特币钱包地址的概念和特点。
比特币地址以 1、3 或 bc1 开头。就像电子邮件地址一样,它们可以与其他比特币用户共享,这些用户可以使用它们将比特币直接发送到自己的钱包。从安全角度来看,比特币地址没有任何敏感内容。它可以在任何地方发布,而不会危及帐户的安全。与电子邮件地址不同,我们可以根据需要随时创建新地址,所有这些地址都会将资金直接存入您的钱包。事实上,许多现代钱包会自动为每笔交易创建一个新地址,以最大限度地保护隐私。钱包只是地址和解锁其中资金的钥匙的集合。首先我们要知道比特币钱包的地址是怎么产生的。
比特币私钥和公钥
比特币采用椭圆曲线Secp256k1,“私钥”是1到n−1之间的随机数,n是个很大的数(256 个比特位),n 用科学计数法表示约为:
这个范围是极大的,我们是几乎无法猜出其他人的私钥的。这个随机整数私钥可以用 256 比特位表示,存在多种编码方式。如果使用WIF、WIF-compressed 形式的私钥是没有加密的,可以解码得到原始的那个“随机整数”。另一种方式是BIP38,提议用 AES 算法对私钥进行加密,这种方案得到的私钥以字符 6P 开头,这种私钥必须输入密码才能导入到各种比特币钱包中,这就是我们平时常用的私钥。
随后我们会利用椭圆曲线公式 K = kG,由私钥 k 来生成比特币的公钥 K,G为 Base Point,它是 secp256k1 的一个参数。可以得到 K 的两个坐标,就是公钥的两种表达方式,分别为“Uncompressed format”和“Compressed format”。
- Uncompressed 形式,就是把两个坐标 x 和 y 直接连接在一起,再在前面加个 0x04 前缀即可;
- Compressed 形式,就是当 y 为偶数时,编码为 02 x,当 y 为奇数时,编码为 03 x;
比特币地址
比特币各种类型的地址如下图可示,共有四种表示方法:
Reference: https://en.bitcoin.it/wiki/Invoice_address
1. Legacy (P2PKH)格式
范例:1Fh7ajXabJBpZPZw8bjD3QU4CuQ3pRty9u
地址以“1”开头,是比特币最初的地址格式,至今仍在使用。由公钥通过 Hash 计算后得到,也被称为P2PKH 是 Pay To PubKey Hash(付款至公钥哈希)的缩写。
2. Nested SegWit (P2SH)格式
范例:3KF9nXowQ4asSGxRRzeiTpDjMuwM2nypAN
地址以"3"开头,P2SH 是Pay To Script Hash(支付至脚本哈希)的缩写,它支持比Legacy 地址更复杂的功能。Nested P2SH,获取现有的P2SH地址(以“3”开头),并与SegWit地址一起封装。
3. Native SegWit (Bech32)格式
范例:bc1qf3uwcxaz779nxedw0wry89v9cjh9w2xylnmqc3
在BIP0173中提出了 bc1 开头的地址,它们是原生的隔离见证地址。Bech32编码的地址,是专为SegWit开发的地址格式。Bech32在2017年底在BIP173被定义,该格式的主要特点之一是它不区分大小写(地址中只包含0-9,az),因此在输入时可有效避免混淆且更加易读。由于地址中需要的字符更少,地址使用Base32编码而不是传统的Base58,计算更方便、高效。数据可以更紧密地存储在二维码中。Bech32提供更高的安全性,更好地优化校验和错误检测代码,将出现无效地址的机会降到最低。
Bech32地址本身与SegWit兼容。不需要额外的空间来将SegWit地址放入P2SH地址,因此使用Bech32格式地址,手续费会更低。Bech32地址比旧的Base58(Base58Check编码用于将比特币中的字节数组编码为人类可编码的字符串)地址有几个优点:QR码更小;更好地防错;更加安全;不区分大小写;只由小写字母组成,所以在阅读、输入和理解时更容易。
4. Taproot格式(P2TR)
Bech32 有个缺点:如果地址的最后一个字符是 p,则在紧接着 p 之前的位置插入或者删除任意数量的字符 q 都不会使其 checksum 失效。
为了缓解 Bech32 的上述缺点,在BIP0350中提出了 Bech32m 地址:
- 对于版本为 0 的原生隔离见证地址,使用以前的 Bech32;
- 对于版本为 1(或者更高)的原生隔离见证地址,则使用新的 Bech32m。
对于 Bech32m 地址,当版本为 1 时,它们总是以bc1p开头(即 Taproot 地址)。具体来说,就像本地隔离见证一样,钱包可以由种子短语和密码短语组成。这些用于生成扩展的公钥和私钥,用于在分层确定性钱包中派生任意路径的地址。主要是储存BRC-20以及BTC的NFT等。