5

比特币区块哈希算法

 3 years ago
source link: https://arminli.com/bitcoin-hash/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

比特币区块哈希算法

February 07, 2018

本文主要介绍比特币区块链上的每个区块的地址是如何产生的。

区块头部(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

Reference


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK