本文主要介绍比特币区块链上的每个区块的地址是如何产生的。
区块头部(Header)主要包括:
- Version:区块版本号,4 Bytes
- hashPrevBlock:上一区块地址,32 Bytes
- hashMerkleRoot:默克尔树,一种用来表达链上历史交易记录的数据结构,32 Bytes。
- Time:时间戳,4 Bytes
- Bits:网络难度,4 Bytes
- Nonce:随机数,也就是 PoW 要计算的数,4 Bytes。
比特币使用两次 hash 来计算:SHA256(SHA256(Block_Header))
以高度为 1 的区块为例,它的地址是 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
:
$ curl https://blockchain.info/rawblock/00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
{
"hash":"00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048",
"ver":1,
"prev_block":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"mrkl_root":"0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098",
"time":1231469665,
"bits":486604799,
"fee":0,
"nonce":2573394689,
"n_tx":1,
"size":215,
"block_index":14850,
"main_chain":true,
"height":1,
......
首先把 ver
, prev_block
, mrkl_root
, time
, bits
, nonce
拼接起来,得到 header_hex
。
在拼接之前需要先把 ver
, time
, bits
, nonce
转换为十六进制字符串,然后将这六个属性由大端序转换为小端序,最后才拼接成一个字符串。
大端序和小端序是计算机硬件存储地址排列的两个通用规则,简单来说高位字节在前就是大端序,这和人类的认知一致;低位字节在前就是小端序,这是因为电路计算都是从低位开始的,方便计算机计算,这和人类计算方式也是一致的。具体可以参考阮一峰的《理解字节序》。
# Source: https://arminli.com
import hashlib, struct
ver = 1
prev_block = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
mrkl_root = "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
time = 1231469665
bits = 486604799
nonce = 2573394689
def deal_str(big_endian):
# [::-1] 改变字节序
return big_endian.decode("hex")[::-1]
def deal_int(n):
# < 代表小端序
# L 代表 unsigned long
return struct.pack("<L", n)
header_bin = deal_int(ver) + deal_str(prev_block) + deal_str(mrkl_root) + deal_int(time) + deal_int(bits) + deal_int(nonce)
其中 deal_int(time) + deal_int(bits) + deal_int(nonce)
也可以通过 stack.pack("<LLL", time, bits, nonce)
实现。
然后做两次 sha256 计算,这一步也就是挖矿做的工作:找到一个 nonce 使得这个结果满足某个条件(比如前八位都是 0)。
hash = hashlib.sha256(hashlib.sha256(header_bin).digest()).digest()
最后将结果转回大端序,即为当前区块的地址。
cur_block = hash[::-1].encode('hex')
print(cur_block)
> 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048