比特币挖矿是指在区块链上添加新区块并获得区块奖励的过程。
任何人都可以尝试进行挖矿, 只要有足够的算力计算出一个低于目标值的哈希值就可以拥有交易的打包权。当新区块产生时, 会被广播到每个运行比特币的网络节点, 每个节点获取到新区块的数据后, 会进行客户端验证, 确认有效后, 将新区块添加到自己的本地区块数据的副本中。
挖矿流程
挖矿遵循以下流程:
-
构建候选区块
- 从内存池中选择交易
- 添加一个
coinbase
交易到交易列表的头部 - 构建区块头
-
挖矿: 不断改变区块头相关数据并使用
HASH256
算法进行哈希计算, 直到哈希结果小于当前目标值。
HASH256 算法
对数据进行两次 SHA256
哈希计算, 也叫 HASH256
假设区块头数据是 x
, 区块头的 HASH256(x)
就等于 SHA256(SHA256(x))
挖矿就是对 HASH256(x)
的不断尝试, 通过调整区块头的相关数据字段的值, 使得区块头的哈希值小于目标值。
当矿工成功计算出一个哈希值小于目标值的区块头时, 会将这个区块广播到网络中。
其他正在挖矿的矿工接收到新区块后会停止当前的工作, 会将新区块加入到本地的区块链上, 同时会移除内存池中冲突的交易。之后开始重新构建一个新的候选区块, 并尝试在新区块上的基础上进行挖矿。
实践
假设你现在是挖出区块 859386 的矿工。
你现在要开始进行挖矿, 首先你需要构建候选区块。
你从内存池中选择了一些手续费高的交易, 并添加了一笔 coinbase
交易到交易列表的头部
#859386
- Coinbase: 9370d2c59b890fedd7a507124cabd44854df6f3e7bf0d59c2a69310d04adb2b8
- 18c39b6e00152f58f64b24c7c1b139170b43e46175650aef93ae4efef8265a3b
- 0ed1e553c7d65d9c0afd6155ea491a8db1220e569b401fd561a80e5a992e4a6b
- 999548c568a643fa75a11b823ed5d3aa44226725d1d7b7befdcb7fd1ad190554
- c922d45822312bad62d379c064a6d58113bb4b792dc5a9458033b8e3777a1955
- b1de88a8529d4922e3905d31fd0a49d95485cd1df5a335531b79cb686386c45e
- c6cf12abd67b949c16ae24be627494707e0ded2a532676121480cf992fe92a71
接着开始构建区块头数据:
上面的 Nonce
字段是区块头中的随机数字段, 占用 4 个字节, 一开始设置为 0。
然后你开始尝试挖矿。对区块头数据不断进行 HASH256
运算, 每次将 Nonce
字段的值加 1, 试图找到一个哈希值小于目标值的随机数。
Hash256 计算器
直到 Nonce
值为 b09ba473
时, 你找到了一个哈希值小于目标值的随机数。转换为小端序为 73a49bb0
, 此时的区块头数据是:
对区块头数据进行 HASH256
运算结果为
转换为小端序后得到最终的区块哈希值
上面的示例只模拟了 nonce
的变化, 实际挖矿过程中, 会不断调整区块头的相关字段, 比如时间戳、交易列表等, 以增加哈希值的随机性。
空块
在区块浏览器有时会看到空块(只有一笔 Coinbase
交易), 如 860932
这是因为构建候选区块是一个耗时的操作, 比如从内存池选择交易, 构建交易的默克尔根等。为了更快的开始挖矿, 矿工会从先尝试一个空块, 运气好的时候, 会直接出块。
相关RPC
参数名 | 类型 | 必选 | 默认值 | 描述 |
---|---|---|---|---|
template_request | json | {} | 控制区块模板返回的内容 |
名称 | 类型 | 描述 |
---|---|---|
version | string | 区块版本号 |
previousblockhash | string | 前一个区块的哈希 |
curtime | number | 当前时间戳 |
target | string | 目标值 |
bits | string | 目标值的压缩格式 |
height | number | 区块高度 |
transactions | array | 建议包含的交易列表 |
参数名 | 类型 | 必选 | 默认值 | 描述 |
---|---|---|---|---|
hexdata | string | - | 16进制编码的区块数据 |
名称 | 类型 | 描述 |
---|---|---|
result | string | 成功返回 "null",否则返回错误信息 |
名称 | 类型 | 描述 |
---|---|---|
blocks | number | 当前区块高度 |
currentblockweight | number | 当前区块的权重 |
currentblocktx | number | 当前区块的交易数量 |
difficulty | number | 当前挖矿难度 |
networkhashps | number | 当前网络的哈希率 |
pooledtx | number | 内存池中的交易数量 |
chain | string | 当前区块链名称(main/test/regtest) |
warnings | string | 警告信息 |
参数名 | 类型 | 必选 | 默认值 | 描述 |
---|---|---|---|---|
txid | string | - | 交易 ID | |
fee_delta | number | - | 虚拟的要增加的交易费用以获得内存池更靠前的排名, 单位是聪 |
名称 | 类型 | 描述 |
---|---|---|
result | boolean | 是否成功 |
参数名 | 类型 | 必选 | 默认值 | 描述 |
---|---|---|---|---|
hash_type | string | hash_serialized_3 | UTXO集合的哈希类型 |
名称 | 类型 | 描述 |
---|---|---|
height | number | 当前区块高度 |
bestblock | string | 最新的区块哈希 |
transactions | number | UTXO 集合中的交易数量 |
txouts | number | UTXO 数量 |
bogosize | number | UTXO 集合的大小, 单位是字节 |
hash_serialized_3 | string | UTXO 集合的哈希值 |
disk_size | number | UTXO 集合的磁盘大小, 单位是字节 |
total_amount | number | UTXO 集合的总金额, 单位是 BTC |