Elea Notes.

词条 · 加密与分布式 · 核心

难度与目标值

一个门槛数字:区块头哈希必须比它小才过关,越低越难

也称:难度、目标值、难度目标、difficulty、target、nBits、difficulty target

一句话

目标值是一个数。把区块头的哈希当成一个 256 位的大整数,它必须小于目标值才算合规。目标值越小,合规的哈希越稀少,就越难找。难度是目标值的倒数换算,方便人读。

先看为什么这个门槛必须能动。

先看一个麻烦:一场比赛,选手人数天天变

假设有个规则:谁先摇出三个六,谁就获得记账权。

一开始十个人玩,平均每十分钟出一个赢家,节奏刚好。

后来来了一千个人,还都换了自动摇骰机。同样的规则,现在每几秒就冒出一个赢家。赢家太多,大家同时宣布”我先摇到的”,谁也说不清谁在前。

再后来一大半人走了,剩下三个人,于是几小时都没人摇出三个六,什么事都办不成。

麻烦的形状是这样的:规则是死的,参与者的总力气是活的,而你想要的产出节奏是固定的。三者不可能同时不变。

朴素尝试为什么都不够

招数一:定个固定的、很难的门槛,比如要摇十个六。 现在人多的时候节奏合适。但硬件每年都在变快——白皮书原话里的理由就是 “to compensate for increasing hardware speed”。今年合适的门槛,明年就太松,五年后每秒出几十个赢家。任何写死的常数都会被时间淘汰。

招数二:限制人数或限制每人的机器速度。 要执行这条规则,就得有人核实谁参赛、每人几台机器。而在一个谁都能匿名加入的网络里,没有任何办法数清人数——一个人可以假装一千个人。这条路直接撞在女巫攻击上。

招数三:让大家投票决定门槛。 投票要先解决”谁有投票权”,那又需要先有共识;而共识正是这套机制要产出的东西。循环了。

招数四:按时钟调整——赢家出得太快就调难,太慢就调松。 方向对了,这正是最终答案。但”太快""太慢”要有个客观基准,而且这个基准必须是每台机器各自独立算出来、结果还完全一致的,不能靠谁通知谁。

招数五:让门槛在”摇几个六”这种整数上跳。 每加一个六,难度乘以 6 倍。粒度太粗了:现在偏快 1.3 倍,你只能选择”不动”或者”一次性变难 6 倍”。需要的是能连续微调的旋钮。

四条要求:

  1. 门槛必须可变,否则被硬件进步淘汰;
  2. 调整规则必须是纯函数——输入是链上已有的数据,任何人独立计算得同一结果;
  3. 调整依据不能依赖人数或身份
  4. 粒度要细,可以按任意比例微调。

机制:门槛不是”几个零”,是一个数

第 5 条要求把”数零的个数”否决了。真正的做法是给出一个 256 位整数 T,规则是:

把区块头的 SHA-256 结果读成一个 0 到 2²⁵⁶-1 之间的整数 h
合规条件:h < T

因为哈希输出可以看成在这个区间里均匀随机,所以命中概率就是 T 占整个区间的比例:

P = T / 2²⁵⁶            平均需要尝试 1/P = 2²⁵⁶/T 次

先用小数字体会。假设哈希输出只有 0–999 这一千种可能:

T = 500 → 概率 500/1000 = 1/2    平均试 2 次
T = 100 → 概率 100/1000 = 1/10   平均试 10 次
T =  50 → 概率  50/1000 = 1/20   平均试 20 次
T =  10 → 概率  10/1000 = 1/100  平均试 100 次
T =   1 → 概率   1/1000 = 1/1000 平均试 1000 次

T 可以取 1 到 1000 之间任意整数,所以想让难度精确变成现在的 1.1667 倍,只要把 T 乘以 12/14 即可。这就是招数五要的细粒度:门槛是连续的刻度,不是台阶。

比特币把最容易的那档定为难度 1,对应的目标值写出来是:

T₁ = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
      ↑ 开头 8 个十六进制 0(即 32 个二进制 0)

概率 T₁ / 2²⁵⁶ ≈ 2.33 × 10⁻¹⁰,平均需要 2²⁵⁶ / T₁ ≈ 4.295 × 10⁹ 次尝试,也就是约 2³² 次。难度的定义就是拿它当尺子:

难度 D = T₁ / T          平均尝试次数 ≈ D × 2³²

所以”难度 一百万亿”这种说法,含义是”比最容易那档难一百万亿倍”,换算成尝试次数就是 D × 2³²。

再算调整规则。目标是十分钟一个块,取 2016 个块为一个周期:

2016 × 10 分钟 = 20,160 分钟 = 336 小时 = 14 天

到第 2016 个块时,每台机器各自读链上的时间戳,算出这一批实际花了多久,然后:

新目标值 = 旧目标值 × 实际耗时 / 期望耗时(14 天)

若实际只用了 12 天,说明算力涨了:新目标值 = 旧值 × 12/14 ≈ 旧值 × 0.8571,门槛变小、更难,难度相应上调 14/12 ≈ 1.1667 倍。若实际用了 28 天,目标值放大一倍,难度减半。为防极端情况,单次调整幅度被限制在 4 倍以内。

注意这个式子里没有任何”人数”或”身份”,只有链上已经写死的时间戳和块数——满足第 2、3 条要求。每个节点各算各的,结果必然一致,不需要任何人宣布。

回头看:这是那个”1000 种可能”的老问题换了个立场

哈希函数那一条讲小号哈希时说过:% 1000 只有一千种输出,所以碰撞必然存在——当时这是缺点,是必须靠 256 位来缓解的东西。

这里同一个事实被当成资源来用。输出空间大而均匀,才使得”落在前 1/N 区间”这件事有精确已知的概率,成本才能被定价到任意精度。同一条数学性质,在安全语境里是威胁,在计价语境里是刻度。

另外,算力那一条说”算力涨十倍并不会让出块变快”,原因就在这里:目标值是个反向的配重。难度不是为了让挖矿变难,是为了让出块节奏不变。 出块节奏之所以要稳,是因为它同时决定了分叉的频率和确认的时间刻度。

边界与常见误解

白皮书里没有 2016 这个数字,也没有”两周”。 原文只说难度由一个 moving average 决定,目标是每小时平均出块数达标,并且只写了 “if they’re generated too fast, the difficulty increases” ——只提了上调方向。2016 个块、两周周期、4 倍上限、乃至具体公式,全都是后来实现里的工程决定,不是论文的一部分。把它们当成论文内容是常见的记忆错误。

难度和目标值方向相反。 难度上升 = 目标值下降。中文里两个词都常被说成”变高”,容易搞混:说”目标值变高”通常是想说”更难”,但字面意思恰好是更容易。

“前面几个零”只是目标值的近似说法。 数零个数只能表达 16 的整数次幂那些档位,真实的目标值落在两档之间。写代码时若按”数零”判断,会算错难度。

区块头里那 4 字节不是目标值本身。 256 位的 T 被压缩成 4 字节存储(俗称 nBits,一种浮点式编码),是压缩表示,精度有限。

调整依据是链上时间戳,而时间戳是打包者填的。 这留下一个已知的操纵空间:矿工在允许范围内微调时间戳,可以轻微影响难度计算。实际影响很小,但它是真实存在的边界,不是理论洁癖。