# 以太坊(Ethereum ETH)是如何计算难度的

8 篇文章 1 订阅

## 什么是难度

• 没有比穷举法更有效的求解方法
• 解在空间中均匀分布，从而使每一次穷举尝试找到一个解的概率基本一致
• 解的空间足够大，保证一定能够找到解

## 以太坊是如何计算难度的

Geth的开发者对“共识”的理解相当深入，代码也很容易阅读。关于难度的代码在consensus/ethash/consensus.go中。

func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
switch {
case config.IsMetropolis(next):
return calcDifficultyMetropolis(time, parent)
default:
return calcDifficultyFrontier(time, parent)
}
}

// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
// algorithm:
// diff = (parent_diff +
//         (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
//        ) + 2^(periodCount - 2)

bigTime := new(big.Int).SetUint64(time)
bigParentTime := new(big.Int).Set(parent.Time)

// holds intermediate values to make the algo easier to read & audit
x := new(big.Int)
y := new(big.Int)

// 1 - (block_timestamp - parent_timestamp) // 10
x.Sub(bigTime, bigParentTime)
x.Div(x, big10)
x.Sub(big1, x)

// max(1 - (block_timestamp - parent_timestamp) // 10, -99)
if x.Cmp(bigMinus99) < 0 {
x.Set(bigMinus99)
}
// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
y.Div(parent.Difficulty, params.DifficultyBoundDivisor)
x.Mul(y, x)

// minimum difficulty can ever be (before exponential factor)
if x.Cmp(params.MinimumDifficulty) < 0 {
x.Set(params.MinimumDifficulty)
}
// for the exponential factor
periodCount.Div(periodCount, expDiffPeriod)

// the exponential factor, commonly referred to as "the bomb"
// diff = diff + 2^(periodCount - 2)
if periodCount.Cmp(big1) > 0 {
y.Sub(periodCount, big2)
y.Exp(big2, y, nil)
}
return x
}

• 整数除法，符号//

-11.3 // 5 = -3

11.3 // 5 = 2

• 取整，符号INT

INT(3.7) = 3

INT(-3.7) = -3

• 最大值，符号MAX

MAX(-1,0) = 0

MAX(7,10) = 10

parent_timestamp：上一个区块产生的时间

parent_diff：上一个区块的难度

block_timestamp：当前区块产生的时间

block_number：当前区块的序号

block_diff = parent_diff + 难度调整 + 难度炸弹

## 实践一下

parent_timestamp = 2017-08-28 11:24:23

parent_diff = 2,117,963,098,883,076

block_timestamp = 2017-08-28 11:25:43

block_number = 4212372

INT(2**((4212372 // 100000) - 2)) =

INT(2**(42 - 2)) = INT(2**40) = 2**40 = 1099511627776

2117963098883076 // 2048 * MAX(1 - (2017-08-28 11:25:43 - 2017-08-28 11:24:23) // 10, -99) =

2117963098883076 // 2048 * MAX(1 - (2017-08-28 11:25:43 - 2017-08-28 11:24:23) // 10, -99) =

2117963098883076 // 2048 * MAX(1 - 80 // 10, -99) =

2117963098883076 // 2048 * MAX(1 - 8, -99) =

2117963098883076 // 2048 * MAX(-7, -99) =

2117963098883076 // 2048 * -7 =

1034161669376 * -7 = -7239131685632

block_diff = 2117963098883076 - 7239131685632 + 1099511627776 = 2,111,823,478,825,220

## 关于难度炸弹

INT(2**((block_number // 100000) - 2))

12-24 9031
05-22 9486
06-03 599
01-09 1145
03-04 907
03-31 1万+
08-26 1894
06-01 259
07-11 249
03-10 688
04-15 699

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助