GitHub
深入技术
区块链

区块链

区块链之所以被称为“区块链”, 是因为它有着和链表类似的结构。构成区块链的基本单位是区块, 每一个区块都保存有前一个区块的哈希值, 通过这种方式, 区块之间就形成了一个链条一样的结构。

区块

区块是区块链的基本构成单元, 构成字段如下表所示:

区块结构
字段大小格式描述
Version4 字节小端序区块版本号
Previous Block32 字节自然字节序前一个区块的区块哈希
Merkle Root32 字节自然字节序区块中包含的所有交易ID的默克尔根
Time4 字节小端序当前时间的 Unix 时间戳
Bits4 字节小端序目标值的紧凑表示
Nonce4 字节小端序随机数,用于尝试找到有效哈希
Transaction Count动态compact size区块中包含的交易数量
Transactions动态交易数据区块中包含的所有原始交易数据

区块头字段包括: VersionPrevious BlockMerkle RootTimeBitsNonce

区块数据由区块头和 Transaction CountTransactions 组成。

以下是区块高度为 1 的区块数据:

010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e362990101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000

该区块仅包含一笔交易。

字节序

  • 大端序 - 正常字节序, 是指数据的高位字节在前,低位字节在后。

  • 小端序 - 指数据的低位字节在前,高位字节在后。如 16进制大端序数据 0x1a2b3c4d, 每两个字符为一个字节, 转换成小端序为 0x4d3c2b1a

  • Compact size - 紧凑尺寸, 用于表示可变长度的数字。

    • 0xfd 开头, 表示后面的两个字节为小端序的数字
    • 0xfe 开头, 表示后面的四个字节为小端序的数字
    • 0xff 开头, 表示后面的八个字节为小端序的数字
    • 其他情况, 表示该字节本身为数字

Compact size 示例:

  • 0x2a 表示数字 42.
  • 0xfde8030xfd 开头, 后面的两个字节 0xe803, 转换为正常字节序为 0x03e8 表示十进制数字 1000.
  • 0xfe030201000xfe 开头, 后面的四个字节 0x03020100, 转换为正常字节序为 0x00010203 表示十进制数字 66051.
  • 0xff00000000000000010xff 开头, 后面的八个字节 0x0000000000000001, 转换为正常字节序为 0x0100000000000000 表示十进制数字 72057594037927936.

区块高度

区块高度表示区块在区块链中的位置, 从 0 开始计数。0 号区块也叫创世区块。

最新区块

区块高度: 866147
区块时间: 2024-10-18 03:30:58
交易数: 1850
大小: 1.99 MB
权重: 3.99 MWU
费率范围: 2-259 sat/vB
区块补贴: 3.125 BTC
总手续费: 0.078 BTC

挖矿

比特币挖矿是指在区块链上添加新区块并获得区块奖励的过程。区块奖励是唯一凭空产生比特币的方式。

挖矿的本质就是在计算区块哈希, 通过不断的调整区块头数据, 试图计算出一个低于目标值的区块哈希值, 只要有足够的算力计算出一个低于目标值的哈希值就可以拥有发布新区块的权利。

目标值是一个固定的数字, 比特币网络最初设定了一个最大目标值, 这使得挖矿非常容易, 出块时间也很短。但为了保证每10分钟出一个区块, 每 2016 个区块(约两周)会调整一次目标值。当最近的 2016 个区块内的平均出块时间小于 10 分钟时, 会减小目标值(增加难度), 反之则增加目标值。

区块哈希是一个区块的唯一标识。

链重组

随着更多矿工的加入或全网算力的提升, 有可能会出现同时挖出两个区块, 假设这两个区块分别叫 A 和 B。

矿工挖出区块向外广播后, 有些比特币节点可能会先收到 A 区块, 其次接收到 B 区块, 此时 A 区块会被加入到节点的本地区块链中, 同时会保留 B 区块。另一些节点也有可能先收到 B 区块再收到 A 区块, 此时 B 区块会被加入到本地区块链中, 同时会保留 A 区块。

因此, 网络上的节点将对这两个区块中哪个属于链的最新区块存在分歧。

但当下一个区块被挖掘时, 这种分歧将得到解决。假设成功挖出下一个区块的矿工节点先收到的是 A 区块, 则会在 A 区块的基础构建新区块。根据最长链的原则, 其他先接收到 B 区块的节点会进行链重组, 将旧活动链中的区块移除, 转而支持构成新较长链的区块。

通过 RPC 方法 getchaintips 可以查看请求的的节点是否经历了链重组。

[
  {
    "height": 860116,
    "hash": "00000000000000000002a29ca4c00f58a4192548535b6cdfdc2edc26811c393c",
    "branchlen": 0,
    "status": "active"
  },
  {
    "height": 856689,
    "hash": "0000000000000000000049ed2a8a4527f8c83192f9ab13fcd5444aed37405cc3",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 853120,
    "hash": "000000000000000000019066a8be0724175e18539db741579622738f1ce1f2ee",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 853051,
    "hash": "000000000000000000007ad9be842fdb143133a8e5353627473006f94bcc086b",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 851248,
    "hash": "00000000000000000001b302a79f8db40c150cdbaccaf43666b1ecfac9560a69",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 849233,
    "hash": "0000000000000000000020ea4b48f075a066131024c242b6f83eb20724c642d1",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 848860,
    "hash": "000000000000000000003f620e65976fc1768e6f81705cc7fdf25cfcb421825a",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 848477,
    "hash": "00000000000000000002ad15f6680bf74febab1020128641fab0da4bdfa5b4bd",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 847849,
    "hash": "0000000000000000000327cda2d3d99ac20342aaaa6986837fbfa8903a7b2196",
    "branchlen": 1,
    "status": "valid-fork"
  },
  {
    "height": 845627,
    "hash": "0000000000000000000011018adf88550ea5d3e90ed0cfba89976aebc4e7f098",
    "branchlen": 1,
    "status": "valid-headers"
  },
  {
    "height": 829613,
    "hash": "0000000000000000000357088139cba6dc295875d7d3b2dd1fd764705727e451",
    "branchlen": 1,
    "status": "valid-fork"
  }
]
  • branchlen - 表示竞争区块链中有多少个区块
  • status - 表示区块链的状态, 有以下取值:
    • active - 当前的最长链
    • valid-fork - 有效分叉, 但之后收到更长的链, 随后将其停用
    • valid-headers - 分叉有有效的区块头,但是还没有下载和验证完整的区块数据
    • headers-only - 仅有区块头信息的分叉, 节点收到了竞争链的区块头, 但没有下载完整的区块
    • invalid - 至少有一个无效区块的分叉

最长链

比特币的最长链是根据工作量证明(POW)机制来确定的, 即平均计算区块哈希最多次数构建的区块链, 而非包含区块最多的链。

最长链通过链工作量(chainwork) 的指标来衡量。chainwork 表示从创世区块到当前区块所有工作量的总和。

衡量一个区块的工作量, 根据计算区块的哈希值平均次数来确定的。

例如: 创世区块的目标值是

0x00000000ffff0000000000000000000000000000000000000000000000000000

挖矿时每次计算区块哈希值都会得到一个 0 至

0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

之间的数。

也就是说平均需要执行以下次数才能得到一个小于目标值的哈希值:

0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff /
(0x00000000ffff0000000000000000000000000000000000000000000000000000 + 1)
= 0x0100010001

挖出创世区块平均需要执行 0x0100010001 (4295032833) 次哈希才能获得低于该目标值的结果。因此, 这就是创世区块的实际链工作量。

目标值是每 2016 个区块调整一次, 所以每2016个区块内的每个区块的平均工作量是相同的。

比特币数据总览

区块数据大小: 691.75 GB
总区块数: 866,147
链工作量: 00000000000000000000000000000000000000009491f7cc6454a735447fdb7c

51%攻击

51%攻击是指一个恶意矿工或矿池控制了比特币网络的算力超过 50% 时, 理论上可以操纵区块链, 甚至可以对网络进行双花攻击。

根据最长链原则, 要实现51%攻击, 攻击者需要构建一条比现有链的链工作量(chainwork)更大的链。而在攻击者构建链的过程中, 其他诚实矿工也在不断构建新区块, 因此攻击者需要比诚实矿工更快的速度构建新区块。

假设当前的 chainwork 是 8, 诚实矿工构建新区块的速度是 1, 攻击者构建新区块的速度至少是 2 才能实现 51% 攻击。

在比特币网络中, 51% 攻击是一种理论上的攻击, 但实际上, 由于比特币网络的算力分布非常分散, 要控制 51% 的算力非常困难。

分叉

比特币分叉分为两种

  • 硬分叉
  • 软分叉

硬分叉

硬分叉发生在对比特币软件进行升级时, 某些协议或规则发生了根本性变化。

如果部分节点更新而其他节点不更新,网络会分裂成两条独立的链。这种情况被称为“硬分叉”。

矿工将分为两个阵营, 一个将继续遵循旧规则产出旧区块, 另一个将遵循新规则产出符合新规则的区块。

对于网络上的节点, 如果未更新比特币软件, 在接收到新区块时, 如果这些新区块是遵循新规则的区块, 在本地验证时会被拒绝。而更新过的节点则会接受这些新区块。这就是为什么会分裂成两条链的原因。

历史上发生过的硬分叉

  1. 比特币现金(BCH)

由于比特币的区块数据大小有 1MB 的限制, 为了扩容, 比特币开发者提出了 SegWit 方案: 将签名数据从区块中剥离出来, 从而增加区块的容量。但是, 一部分社区成员认为这种方案并不是最好的解决方案, 他们提出了另一种方案: 增加区块的大小。

因此在 2017 年 8 月 1 日, 不满于 SegWit 方案的矿工决定硬分叉, 将区块大小从 1MB 增加到 8MB, 并且移除了 SegWit。于是从区块 478,558 开始, BCH 正式从比特币主链分叉。

在 2018 年, BCH 社区内部开始出现新的分歧。BCH 的主要开发团队主张将区块大小从 8MB 增加到 32MB, 并且启用了一些脚本操作码, 以便让 BCH 网络拥有和以太坊一样的智能合约应用。但是, 自称中本聪的澳洲科学家 Craig Wright 明确反对该计划, 只主张只将区块大小增加到 128MB, 并声称 BCH 这种改变会破坏比特币的原始设计。

于是在 2018 年 11 月 15 日, 在 BCH 区块高度 556,767 处发生分叉, 产生了BSV(Bitcoin Satoshi Vision)。在之后的 2019 年, BSV 的区块大小增加到了 2GB。

  1. 比特币黄金(BTG)

创始人认为,比特币挖矿已经被 ASIC 矿机垄断,普通用户难以参与。于是在 2017 年 10 月 24 日在比特币区块高度 491,407 处分叉出了 BTG。

BTG 采用 Equihash 算法替代比特币的 SHA-256 挖矿算法, 这使得普通用户可以使用 GPU 进行挖矿。同时引入了更快速的难度调整算法。

在 2018 年 5 月 3 日, BTG 发生了一次 51% 攻击, 导致约 1800 万美元损失。这次攻击暴露了 Equihash 算法的潜在脆弱性。

在 2018 年 7 月, 将挖矿算法升级为Equihash-BTG(也称为Zhash)

  1. BerkeleyDBLevelDB 升级

在比特币从 0.7 升级到 0.8 后的 2013 年 3 月 12 日, 出现了一个旧版本(0.7)无法验证的区块, 主要是因为 BerkeleyDB 默认有 10000个锁的限制, 这些锁是用于防止多个进程同时修改某个数据。比特币在处理有大量交易的区块时, 所需要的锁可能会超过 10000 个, 导致无法处理这个区块, 为了正常挖出区块, 只能减少区块中的交易数量,也就变相了限制单个区块中可以包含的交易数量。

但 0.8 版本升级后, 数据库由 BerkeleyDB 切换到 LevelDB, 这个限制也被移除了。而那个旧版本无法验证的区块正是因为区块中包含的交易数量过多导致的。

最后社区达成共识, 运行 0.8 版本的矿工暂时回退到了 0.7 版本, 这才得以解决。

软分叉

软分叉是指对比特币软件进行的升级, 该升级与之前版本的软件兼容。

与硬分叉的区别是:

  • 未升级节点可以接收验证新区块
  • 不会造成区块链的分叉, 整个网络上仍然是一条链

历史上发生过的软分叉

  • BIP 16 (2012年)

    这是比特币的第一个软分叉,引入了 P2SH 。这使得更复杂的脚本成为可能,增强了比特币的智能合约能力。

  • BIP 34 (2013年)

    要求在 Coinbase交易中包含区块高度。避免重复的交易 ID 出现。

  • BIP 65 (2014年)

    引入了 OP_CHECKLOCKTIMEVERIFY 操作码,允许创建时间锁定的交易。

  • BIP 66 (2015年)

    强制执行严格的 DER 签名。

  • SegWit (隔离见证, 2017年)

    比特币历史上最著名的软分叉。它解决了交易延展性问题,增加了区块容量,并为闪电网络等第二层解决方案奠定了基础。

  • Taproot (2021年)

    这是比特币最近的一次重大软分叉升级。Taproot 改进了比特币的隐私性和智能合约功能,同时提高了交易效率。

Copyright © 2024 HeapUp