第十一章. 区块链

  • berry
  • 发布于 2025-02-09 22:26
  • 阅读 19

综合介绍

区块链是每一笔已确认比特币交易的历史记录。它使得每个完整节点能够独立确定哪些密钥和脚本控制着哪些比特币。在本章中,我们将探讨区块链的结构,以及它如何利用密码学承诺和其他巧妙的技巧使得每个部分都易于完整节点(有时甚至是轻量级客户端)进行验证。

区块链数据结构是一个有序的、反向链接的交易块列表。区块链可以存储为一个平面文件或简单的数据库。区块通过“反向链接”方式相互关联,每个区块都指向链中的前一个区块。区块链通常被视为一个垂直堆栈,每个区块都叠加在其他区块之上,而第一个区块则作为堆栈的基础。区块叠加在一起的可视化结果导致了使用诸如“高度”来指代距离第一个区块的距离,以及“顶部”或“尖端”来指代最近添加的区块等术语。

区块链中的每个区块都由哈希标识,使用 SHA256 密码哈希算法对区块的标头生成。每个区块还通过区块标头中的“上一个区块哈希”字段提交给前一个区块,即父区块。将每个区块与其父区块链接起来的哈希序列创建了一条链,一直回溯到创世区块。

尽管一个区块只有一个父区块,但它可以有多个子区块。每个子区块都提交给同一个父区块。在区块链“分叉”时会出现多个子区块,这是由于不同的矿工几乎同时发现了不同的区块。最终,只有一个子区块会成为被所有完整节点接受的区块链的一部分,从而解决了“分叉”。

“上一个区块哈希”字段位于区块标头内部,从而影响当前区块的哈希。对父区块的任何更改都需要子区块的哈希发生变化,这又需要更改孙区块的指针,进而改变孙区块,依此类推。这个序列确保了一旦一个区块有了许多后代,它就不能在不强制重新计算所有后续区块的情况下进行更改。由于这样的重新计算需要大量的计算(因此需要大量能源消耗),因此存在着一个长链条的区块链深层历史不容易更改的特性,这是比特币安全的一个关键特征。

一个理解区块链的方式类似于地质形成中的地层或冰川核心样品。表层可能会随着季节变化,甚至在沉淀之前就被吹走。但是一旦你深入到几英寸深度,地层就会变得越来越稳定。当你看到数百英尺深时,你看到的是一个保持不变数百万年的过去的快照。在区块链中,最近的几个区块可能会根据分叉而进行修改。前六个区块就像几英寸的表土一样。但是一旦你深入到区块链的更深处,超过六个区块,区块就越来越不可能改变。在回溯到 100 个区块之后,稳定性已经非常高,以至于 coinbase 交易(包含创建新区块的比特币奖励的交易)可以被花费。尽管协议始终允许通过更长的链来撤消链,并且任何区块被撤消的可能性始终存在,但是随着时间的推移,这种事件的概率会减小,直到变得微不足道。

区块的结构

一个区块是一个容器数据结构,用于聚合交易以便包含在区块链中。区块由一个包含元数据的头部组成,后面跟着一个包含大部分数据的交易列表。区块头部通常为 80 字节,而一个区块中所有交易的总大小可以达到约 4,000,000 字节。因此,一个完整的区块,包含所有交易,几乎可以比区块头部大约 50,000 倍。表 11-1 描述了比特币核心如何存储一个区块的结构。

表 11-1. 区块的结构

大小 字段 描述
4 字节 区块大小(Block Size) 该字段后面跟着区块的大小,以字节为单位
80字节 区块头(Block Header) 几个字段形成了区块头部
1-3字节(compactSize) 交易计数器(Transaction Counter) 接下来有多少个交易
可变字节 交易(Transactions) 记录在此区块中的交易

区块头

区块头部由如下表11-2所示的区块元数据组成。

Table 11-2. 区块头部的结构

大小 字段 描述
4字节 版本(Version) 最初是一个版本字段;随着时间的推移,它的用途已经发展
32字节 之前的块哈希(Previous Block Hash) 链中前一个(父)块的哈希
32字节 默克尔根(Merkle Root) 该块交易的默克尔树根哈希
4字节 时间戳(Timestamp) 该区块的大致创建时间(Unix纪元时间)
4字节 目标(Target) 该区块的工作量证明目标的紧凑编码
4字节 只用一次的随机数 (Nonce) 工作证明算法使用的任意数据

nonce(随机数)、目标值和时间戳在挖矿过程中使用,并将在第12章中进行更详细的讨论。

区块标识符:区块头哈希和区块高度

一个区块的主要标识符是其加密哈希,这是通过SHA256算法对区块头进行两次哈希计算得到的。生成的32字节哈希称为区块哈希,但更准确地说是区块头哈希,因为只有区块头用于计算它。例如,比特币区块链上的第一个区块的区块哈希是000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f。区块哈希唯一而明确地标识一个区块,并且可以由任何节点独立地通过对区块头进行哈希计算来派生出来。

请注意,区块哈希实际上并未包含在区块的数据结构中。相反,每个节点在从网络接收到区块时计算区块哈希。为了便于索引和更快地从磁盘检索区块,区块哈希可能会存储在单独的数据库表中作为区块的元数据的一部分。

第二种识别区块的方式是通过其在区块链中的位置,称为区块高度。创世区块位于区块高度0(零),之前被以下区块哈希引用:000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f。因此,一个区块可以通过引用区块哈希或引用区块高度来进行识别。每个添加到该创世区块“之上”的后续区块都在区块链中处于一个“更高”的位置,就像箱子一样一层叠一层堆叠。在撰写本书时,即2023年中期,区块高度已经达到了800,000,这意味着在2009年1月创建的第一个区块之上堆叠了800,000个区块。

与区块哈希不同,区块高度不是唯一的标识符。虽然单个区块始终具有特定且不变的区块高度,但反之并非如此——区块高度并不总是唯一地标识单个区块。两个或多个区块可能具有相同的区块高度,竞争同一位置在区块链中。这种情况在第282页的“组装和选择区块链”部分中有详细讨论。在早期的区块中,区块高度也不是区块的数据结构的一部分;它未存储在区块内。每个节点在从比特币网络接收到区块时会动态地确定区块在区块链中的位置(高度)。后来的协议更改(BIP34)开始将区块高度包含在coinbase交易中,尽管其目的是确保每个区块具有不同的coinbase交易。节点仍然需要动态地确定区块的高度以验证coinbase字段。区块高度也可能作为元数据存储在索引数据库表中,以便更快地检索。

注意:一个区块的区块哈希始终唯一地标识一个区块。一个区块也总是具有特定的区块高度。然而,并不总是情况下特定的区块高度标识单个区块。相反,两个或多个区块可能竞争区块链中的一个位置。

创世区块

区块链中的第一个区块称为创世区块,创建于2009年。它是区块链中所有区块的共同祖先,这意味着如果你从任何一个区块开始,沿着时间的倒序链向后跟踪,最终会到达创世区块。

每个节点始终以至少一个区块的区块链开始,因为创世区块被静态编码在比特币核心中,因此无法更改。每个节点始终“知道”创世区块的哈希和结构,以及创建的固定时间,甚至包括其中的单个交易。因此,每个节点都有一个区块链的起点,一个安全的“根”,用于构建一个可信的区块链。

在Bitcoin Core客户端的chainparams.cpp中,可以看到静态编码的创世区块。

以下标识哈希属于创世区块:

000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

你可以在几乎任何区块浏览器网站上搜索该区块哈希,比如blockstream.info,你会找到一个页面描述该区块的内容,其中包含该哈希的URL链接。

https://blockstream.info/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

或者,你可以在命令行上使用Bitcoin Core获取该区块:

$ bitcoin-cli getblock \
 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
{
"hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"confirmations": 790496,
"height": 0,
"version": 1,
"versionHex": "00000001",
"merkleroot": "4a5e1e4baab89f3a32518a88c3[...]76673e2cc77ab2127b7afdeda33b",
"time": 1231006505,
"mediantime": 1231006505,
"nonce": 2083236893,
"bits": "1d00ffff",
"difficulty": 1,
"chainwork": "[...]000000000000000000000000000000000000000000000100010001",
"nTx": 1,
"nextblockhash": "00000000839a8e6886ab5951d7[...]fc90947ee320161bbf18eb6048",
"strippedsize": 285,
"size": 285,
"weight": 1140,
"tx": [
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
] }

创世区块中包含一条信息。Coinbase 交易输入包含文本:“The Times 03/Jan/2009 Chancellor on brink of second bailout for banks.” 这条信息旨在通过引用英国报纸《泰晤士报》的头条,提供该区块可能被创建的最早日期的证明。它还作为一种戏谑的提醒,强调了独立货币系统的重要性,因为比特币的推出恰逢前所未有的全球金融危机。这条信息是比特币的创始人中本聪嵌入到第一个区块中的。

区块链中的区块链接

图比特币全节点会验证从创世区块之后的每个区块。它们对区块链的本地视图会随着新的区块被发现并用于扩展链条而不断更新。当节点从网络中接收到新的区块时,它会验证这些区块,然后将它们链接到现有区块链的视图中。为了建立链接,节点会检查接收到的区块头,并查找“上一个区块哈希”。

例如,假设一个节点在本地拷贝的区块链中有277,314个区块。节点所知道的最后一个区块是第277,314块,其区块头哈希为:

00000000000000027e7ba6fe7bad39faf3b5a83daed765f05f7d1b71a1632249

然后比特币节点从网络中接收到一个新的区块,它解析如下:

{
"size" : 43560,
"version" : 2,
"previousblockhash" :
"00000000000000027e7ba6fe7bad39faf3b5a83daed765f05f7d1b71a1632249",
"merkleroot" :
"5e049f4030e0ab2debb92378f53c0a6e09548aea083f3ab25e1d94ea1155e29d",
"time" : 1388185038,
"difficulty" : 1180923195.25802612,
"nonce" : 4215469401,
"tx" : [
"257e7497fb8bc68421eb2c7b699dbab234831600e7352f0d9e6522c7cf3f6c77",
"[... many more transactions omitted ...]",
"05cfd38f6ae6aa83674cc99e4d75a1458c165b7ab84725eda41d018a09176634"
] }

查看这个新区块,节点发现了 previousblockhash 字段,其中包含其父区块的哈希值。这个哈希值是节点已知的,即链上高度为 277,314 的最后一个区块的哈希值。因此,这个新区块是链上最后一个区块的子区块,并扩展了现有的区块链。节点将这个新区块添加到链的末尾,使得区块链变得更长,高度为 277,315。图 11-1 显示了由 previousblockhash 字段中的引用链接起来的三个区块的链条。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/11.1.png" alt=""><figcaption><p> 11-1. 区块通过每个引用前一个区块头哈希值来链接成链</p></figcaption></figure>

默克尔树

比特币区块链中的每个区块都包含了对该区块中所有交易的摘要,使用了默克尔树。

默克尔树,也称为二叉哈希树,是一种用于高效总结和验证大型数据集完整性的数据结构。默克尔树是包含了加密哈希的二叉树。计算机科学中的“树”一词用于描述分支数据结构,但这些树通常在图表中是倒置的,顶部是“根”,底部是“叶子”,正如你将在后面的示例中看到的那样。

比特币中使用默克尔树来总结一个区块中的所有交易,产生对整个交易集合的整体承诺,并允许非常有效地验证一个交易是否包含在区块中。默克尔树是通过递归地对元素成对进行哈希处理构建的,直到只剩下一个哈希,称为根,或默克尔根。比特币中用于默克尔树的加密哈希算法是SHA256应用两次,也称为双SHA256。

当N个数据元素被哈希并在默克尔树中进行总结时,你可以通过大约log2(N)次计算来检查其中是否包含任何一个数据元素,使得这成为一种非常高效的数据结构。

默克尔树是自底向上构建的。在下面的例子中,我们从四个交易A、B、C和D开始,它们形成了默克尔树的叶子节点,如图11-2所示。交易并不存储在默克尔树中;相反,它们的数据被哈希处理,产生的哈希结果存储在每个叶子节点中,分别为HA、HB、HC和HD:

HA = SHA256(SHA256(Transaction A))

然后,将相邻的叶子节点成对合并到一个父节点中,方法是将这两个哈希连接在一起,然后将它们一起进行哈希处理。例如,要构建父节点HAB,将两个子节点的32字节哈希连接起来,形成一个64字节的字符串。然后对该字符串进行双重哈希处理,以生成父节点的哈希值:

HAB = SHA256(SHA256(HA || HB))

这个过程持续进行,直到顶部只剩下一个节点,即被称为 Merkle 根的节点。这个 32 字节的哈希值存储在区块头中,总结了所有四笔交易中的所有数据。图 11-2 展示了通过节点的成对哈希计算根节点的过程。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/11.2.png" alt=""><figcaption><p>图 11-2. 计算 Merkle 树中的节点</p></figcaption></figure>

因为 Merkle 树是一个二叉树,所以需要有偶数个叶子节点。如果要总结的交易数量为奇数,则最后一个交易的哈希将被复制,以创建一个偶数个叶子节点,也称为平衡树。如图 11-3 所示,交易 C 被复制。同样地,如果在任何层级中要处理的哈希数量为奇数,则最后一个哈希将被复制。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/11.3.png" alt=""><figcaption><p>图 11-3. 复制一个数据元素可以实现有偶数个数据元素</p></figcaption></figure>

比特币的默克尔树设计中存在一个缺陷

比特币核心代码中的一段扩展注释,稍作修改后再次呈现,描述了比特币的默克尔树中一个重要问题:

警告!如果你正在阅读这篇文章,因为你正在学习加密货币和/或设计一个将使用默克尔树的新系统,请记住以下默克尔树算法存在一个严重的缺陷,与重复的交易ID相关,导致一个漏洞(CVE-2012-2459)。

原因是,如果在给定级别的列表中哈希的数量是奇数,那么在计算下一个级别之前,最后一个会被复制一次(这在默克尔树中是不寻常的)。 这会导致某些交易序列导致相同的默克尔根。例如,图11-4中的两棵树:

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/11.4.png" alt=""><figcaption><p>图 11-4. 两棵类比特币的默克尔树,根相同但叶节点数量不同</p></figcaption></figure>

交易列表[1,2,3,4,5,6]和[1,2,3,4,5,6,5,6](其中5和6重复出现)导致相同的根哈希A(因为(F)和(F,F)的哈希值均为C)。 这个漏洞的原因在于可以发送一个具有相同默克尔根和与原始交易列表不重复的块,导致验证失败。如果接收节点继续将该块标记为永久无效,那么它将无法接受进一步的未修改(因此可能有效)的相同块的版本。我们通过检测在列表末尾将两个相同的哈希值进行哈希处理的情况来防范这种情况,并将其视为块具有无效的默克尔根。假设没有双SHA256碰撞,这将检测到所有已知的在不影响默克尔根的情况下更改交易的方法。

——Bitcoin Core src/consensus/merkle.cpp

构建树的相同方法可以推广到构建任何大小的树。在比特币中,一个区块中常常有数千个交易,它们以完全相同的方式进行汇总,产生的只是 32 字节的数据作为单一的 Merkle 根。在图 11-5 中,你将看到一个由 16 个交易构建的树。请注意,尽管在图中根节点看起来比叶子节点大,但它们的大小是完全相同的,都是 32 字节。无论在区块中有一个交易还是一万个交易,Merkle 根始终将它们汇总为 32 字节。

为了证明特定交易包含在一个区块中,一个节点只需要产生大约 log2(N) 个 32 字节的哈希,构成了一个连接特定交易与树根的认证路径或 Merkle 路径。随着交易数量的增加,这一点尤其重要,因为交易数量的底数对数增长得非常缓慢。这使得比特币节点能够高效地产生由 10 到 12 个哈希(320–384 字节)组成的路径,这可以提供对多兆字节区块中一千多个交易的单个交易的证明。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/11.5.png" alt=""><figcaption><p>图 11-5. 总结许多数据元素的 Merkle 树</p></figcaption></figure>

在图 11-6 中,节点可以通过生成一个只有四个 32 字节哈希值长的 Merkle 路径(总共 128 字节)来证明交易 K 包含在区块中。该路径由四个哈希值组成(带有阴影背景显示)HL,HIJ,HMNOP 和 HABCDEFGH。通过提供这四个哈希作为认证路径,任何节点都可以证明 HK(在图的底部具有黑色背景)包含在 Merkle 根中,方法是计算四个额外的逐对哈希值 HKL,HIJKL,HIJKLMNOP 和 Merkle 树根(在图中用虚线轮廓显示)。

<figure><img src="https://img.learnblockchain.cn/masterbitcoin3/assets/11.6.png" alt=""><figcaption><p>图 11-6. 用于证明数据元素包含在内的 Merkle 路径</p></figcaption></figure>

当规模增加时,Merkle 树的效率变得明显。最大可能的区块可以容纳近 16,000 笔交易,占用 4,000,000 字节,但证明其中的任何一笔交易是该区块的一部分只需要交易的副本、80 字节区块头的副本和 448 字节的 Merkle 证明。这使得最大可能的证明几乎比最大可能的比特币区块小了 10,000 倍。

补充说明下,这里为什么需要448字节的Merkle证明。

构造16000笔交易的Merkle树过程如下(只包含当前层数,节点当前数量):

<pre><code><strong>1.16000 </strong>2.8000 3.4000 4.2000 5.1000 6.500 7.250 8.125->126 (这里125为奇数,需要复制最后一个节点) 9.64 10.32 11.16 12.8 13.4 14.2 15.1 </code></pre>

可以看出整颗树高为15,而构造出Merkle path只需要前14层各一个hash即可,root可直接计算出。由于每个hash是32个字节,所以一共需要14*32=448字节。

Merkle 树与轻量级客户端

默克尔树在轻量级客户端中被广泛使用。轻量级客户端不具备所有交易数据,也不下载完整的区块,仅下载区块头。为了验证某笔交易是否包含在一个区块中,而不必下载该区块中的所有交易数据,它们使用了默克尔路径。

举个例子,考虑一个对其钱包中包含的地址的收款感兴趣的轻量级客户端。轻量级客户端将在与对等节点的连接上建立一个布隆过滤器(参见“布隆过滤器”第231页),以限制接收的交易仅包含感兴趣的地址。当对等节点看到与布隆过滤器匹配的交易时,它将使用 merkleblock 消息发送该区块。merkleblock 消息包含区块头以及将感兴趣的交易链接到区块中的默克尔根的默克尔路径。 轻量级客户端可以使用这个默克尔路径将交易连接到区块头,并验证该交易是否包含在区块中。轻量级客户端还使用区块头将区块链接到区块链的其余部分。这两个链接的组合,交易和区块之间的链接以及区块和区块链之间的链接,证明了该交易已记录在区块链中。总的来说,轻量级客户端仅需要接收区块头和默克尔路径的不到1千字节的数据量,这比完整区块的数据量要小上千倍(目前约为2 MB)。

比特币的测试区块链

你可能会感到惊讶,原来比特币使用的不止是一个区块链。由中本聪于2009年1月3日创建的“主”比特币区块链,也就是我们在本章中研究的具有创世区块的那个,被称为主网(mainnet)。除了主网外,还有其他用于测试目的的比特币区块链:目前有测试网(testnet)、签名测试网(signet)和回归测试网(regtest)。我们逐一来看一下每一个。

Testnet:比特币的测试场地

Testnet(测试网)是用于测试目的的测试区块链、网络和货币的名称。测试网是一个完整的实时P2P网络,具有钱包、测试比特币(测试网币)、挖矿以及主网的所有其他功能。最重要的区别是测试网币是没有价值的。

任何打算在比特币主网上投入生产使用的软件开发都可以先在测试网上使用测试币进行测试。这既可以保护开发人员免受由于错误而造成的货币损失,也可以保护网络免受由于错误而导致的意外行为。

当前的测试网被称为testnet3,这是测试网的第三个版本,于2011年2月重新启动,以重置先前测试网的难度。Testnet3是一个庞大的区块链,在2023年超过30 GB。它需要一段时间才能完全同步,并消耗你计算机上的资源。虽然不像主网那样,但也不完全是“轻量级”的

注意:本书中描述的测试网和其他测试区块链不使用与主网地址相同的地址前缀,以防止某人意外地向测试地址发送真正的比特币。主网地址以1、3或bc1开头。本书提到的测试网络的地址以m、n或tb1开头。其他测试网络或在测试网络上开发的新协议可能会使用其他地址前缀或进行修改。

在tesetnet上使用Bitcoin Core

像许多其他比特币程序一样,Bitcoin Core 完全支持在 testnet 上的操作,作为替代主网。Bitcoin Core 的所有功能都可以在 testnet 上使用,包括钱包、挖掘 testnet 币和同步完整的 testnet 节点。 要在 testnet 上启动 Bitcoin Core 而不是主网,你可以使用 testnet 开关:

$ bitcoind -testnet

在日志中,你应该看到 bitcoind 正在默认的 bitcoind 目录的 testnet3 子目录中构建一个新的区块链:

bitcoind: Using data directory /home/username/.bitcoin/testnet3

要连接到 bitcoind,你可以使用 bitcoin-cli 命令行工具,但你还必须将其切换到 testnet 模式:

$ bitcoin-cli -testnet getblockchaininfo
{
 "chain": "test",
 "blocks": 1088,
 "headers": 139999,
 "bestblockhash": "0000000063d29909d475a1c[...]368e56cce5d925097bf3a2084370128",
 "difficulty": 1,
 "mediantime": 1337966158,
 "verificationprogress": 0.001644065914099759,
 "chainwork": "[...]000000000000000000000000000000000000000000044104410441",
 "pruned": false,
 "softforks": [
 [...]

你也可以在其他完整节点实现上运行 testnet3,例如用 Go 编写的 btcd 和用 JavaScript 编写的 bcoin,以在其他编程语言和框架中进行实验和学习。

Testnet3 支持 mainnet 的所有功能,包括隔离见证 v0 和 v1(参见“隔离见证”第 137 页和“Taproot”第 178 页)。因此,testnet3 也可以用于测试隔离见证功能。

测试网络存在一些问题

testnet 不仅使用与比特币几乎完全相同的数据结构,而且它几乎使用与比特币完全相同的工作量证明安全机制。testnet 的显着差异在于,它的最低难度是比特币的一半,而且允许在最低难度下包含一个块,如果该块的时间戳比上一个块晚超过 20 分钟。

不幸的是,比特币的 PoW 安全机制是设计依赖于经济激励,而在禁止具有价值的测试区块链中不存在这种激励。在主网上,矿工被激励将用户交易包含在他们的区块中,因为这些交易支付费用。在测试网上,交易仍然包含一种称为费用的东西,但是这些费用没有任何经济价值。这意味着测试网矿工包含交易的唯一动机是因为他们希望帮助用户和开发人员测试他们的软件。

可悲的是,喜欢破坏系统的人通常会感受到更强烈的激励,至少在短期内是如此。由于PoW挖矿旨在无需许可地进行,任何人都可以进行挖矿,无论他们的意图是好是坏。这意味着恶意的挖矿者可以在测试网络上连续创建许多区块而不包含任何用户交易。当发生这些攻击时,测试网络对用户和开发者来说就变得无法使用。

Signet:权威测试网络

没有已知的方法可以在没有引入经济激励的情况下提供一个高度可用的基于无许可 PoW 的系统,因此比特币协议开发者开始考虑替代方案。主要目标是尽可能保留比特币的结构,以便软件可以在测试网络上运行,而不需要进行太多的更改,但同时也要提供一个有用的环境。次要目标是制定一个可重复使用的设计,以便新软件的开发人员可以轻松创建自己的测试网络。

比特币核心和其他软件中实现的解决方案被称为“signet”,由 BIP325 定义。signet 是一个测试网络,每个区块都必须包含证据(例如签名),证明该区块的创建是由可信任的权威机构批准的。

在比特币上进行挖矿是无许可的——任何人都可以做——而在 signet 上进行挖矿是完全许可的。只有获得许可的人才能这样做。这对于比特币的主网来说是完全不能接受的改变——没有人会使用那种软件——但对于一个测试网络来说是合理的,其中的币没有价值,唯一的目的是测试软件和系统。

BIP325 的 signet 设计旨在非常容易创建自己的 signet。如果你不同意别人如何运行他们的 signet,你可以启动自己的 signet 并连接你的软件到它上面。

默认的signet 和自定义 signet

比特币核心支持一个默认的 signet,我们相信这是目前撰写时最广泛使用的 signet。它目前由该项目的两名贡献者运营。如果你启动比特币核心并使用 signet 参数而没有其他与 signet 相关的参数,那么你将使用这个 signet。

截至撰写本文时,默认的 signet 有大约 150,000 个区块,大小约为一千兆字节。它支持与比特币主网相同的所有功能,并且还用于通过比特币审判项目测试提议的升级,该项目是比特币核心的软件分支,仅设计用于在 signet 上运行。

如果你想使用不同的 signet,称为自定义 signet,你需要了解确定区块何时被授权的脚本,称为挑战脚本。这是一个标准的比特币脚本,因此它可以使用多重签名等功能,允许多人授权区块。你可能还需要连接到一个种子节点,该节点将为你提供自定义 signet 上对等节点的地址。例如:

bitcoind -signet -signetchallenge=0123...cdef -signetseednode=example.com:1234

截至撰写本文时,我们通常建议将挖矿软件的公开测试放在 testnet3 上进行,将所有其他比特币软件的公开测试放在默认 signet 上进行。

要与你选择的 signet 进行交互,你可以使用 bitcoin-cli 的 -signet 参数,类似于你使用 testnet 的方式。例如:

$ bitcoin-cli -signet getblockchaininfo
{
 "chain": "signet",
 "blocks": 143619,
 "headers": 143619,
 "bestblockhash": "000000c46cb3505ddd296537[...]ad1c5768e2908439382447572a93",
 "difficulty": 0.003020638517858618,
 "time": 1684530244,
 "mediantime": 1684526116,
 "verificationprogress": 0.999997961940662,
 "initialblockdownload": false,
 "chainwork": "[...]000000000000000000000000000000000000000000019ab37d2194",
 "size_on_disk": 769525915,
 "pruned": false,
 "warnings": ""
}// Some code

Regtest:本地区块链

Regtest,全称“回归测试”,是比特币核心功能之一,允许你创建一个用于测试目的的本地区块链。与signet和testnet3不同,它们是公共的、共享的测试区块链,regtest区块链旨在作为本地测试的封闭系统运行。你可以从头开始启动一个regtest区块链。你可以向网络添加其他节点,也可以只运行一个节点,用于测试比特币核心软件。

要启动比特币核心进入regtest模式,你可以使用regtest标志:

$ bitcoind -regtest

与testnet一样,比特币核心将在bitcoind默认目录的regtest子目录下初始化一个新的区块链:

bitcoind: Using data directory /home/username/.bitcoin/regtest

要使用命令行工具,你也需要指定regtest标志。让我们尝试使用getblockchaininfo命令来检查regtest区块链:

$ bitcoin-cli -regtest getblockchaininfo
{
 "chain": "regtest",
 "blocks": 0,
 "headers": 0,
 "bestblockhash": "0f9188f13cb7b2c71f2a335e3[...]b436012afca590b1a11466e2206",
 "difficulty": 4.656542373906925e-10,
 "mediantime": 1296688602,
 "verificationprogress": 1,
 "chainwork": "[...]000000000000000000000000000000000000000000000000000002",
 "pruned": false,
 [...]

你可以看到,目前还没有区块。让我们创建一个默认钱包,获取一个地址,然后挖一些(500个区块)以获取奖励:

$ bitcoin-cli -regtest createwallet ""
$ bitcoin-cli -regtest getnewaddress
bcrt1qwvfhw8pf79kw6tvpmtxyxwcfnd2t4e8v6qfv4a
$ bitcoin-cli -regtest generatetoaddress 500 \
 bcrt1qwvfhw8pf79kw6tvpmtxyxwcfnd2t4e8v6qfv4a
[
 "3153518205e4630d2800a4cb65b9d2691ac68eea99afa7fd36289cb266b9c2c0",
 "621330dd5bdabcc03582b0e49993702a8d4c41df60f729cc81d94b6e3a5b1556",
 "32d3d83538ba128be3ba7f9dbb8d1ef03e1b536f65e8701893f70dcc1fe2dbf2",
 ...,
 "32d55180d010ffebabf1c3231e1666e9eeed02c905195f2568c987c2751623c7"
]

挖掘这些区块只需要几秒钟时间,这确实很容易进行测试。如果你检查钱包余额,你会看到你获得了前400个区块的奖励(coinbase 奖励必须在你能够支配之前有100个区块的深度):

$ bitcoin-cli -regtest getbalance
12462.50000000

使用测试区块链进行开发

比特币的各种区块链(regtest、signet、testnet3、mainnet)为比特币开发提供了一系列测试环境。不论你是为比特币核心开发或其他完整节点共识客户端开发;为钱包、交易所、电子商务网站等应用程序开发;甚至是开发新颖的智能合约和复杂脚本,都可以使用测试区块链。

你可以利用测试区块链建立一个开发流程。在开发过程中,在本地的 regtest 上测试你的代码。一旦准备好在公共网络上尝试,切换到 signet 或 testnet,将你的代码暴露在一个更加动态、具有更多代码和应用程序多样性的环境中。最后,一旦你对代码的功能有信心,切换到 mainnet 在生产环境中部署。在进行更改、改进、修复错误等操作时,重新启动流水线,先在 regtest 上部署每个变更,然后在 signet 或 testnet 上部署,最后再部署到生产环境中。

现在我们了解了区块链包含的数据以及加密承诺如何安全地将各个部分紧密地联系在一起,接下来我们将看看提供计算安全性并确保没有一个区块可以在不使所有其他区块失效的情况下进行更改的特殊承诺:比特币的挖矿功能。

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

0 条评论

请先 登录 后评论