以太坊難度調(diào)整算法

關(guān)于以太坊的難度調(diào)整算法拦赠,從源代碼里的block_validator.go文件中可以找到相關(guān)表述巍沙。算法主要是讓挖礦時(shí)間保持在10-19s這個(gè)區(qū)間內(nèi),如果挖礦時(shí)間在0到9s內(nèi)荷鼠,Geth會(huì)增大挖礦難度句携;如果挖礦時(shí)間大于20s,Geth會(huì)減小難度允乐。

block_validator.go文件中务甥,函數(shù)CalcDifficulty用來(lái)調(diào)整挖礦難度,函數(shù)輸入是以太坊的版本號(hào)喳篇、父區(qū)塊的難度值、父區(qū)塊的時(shí)間态辛、當(dāng)前時(shí)間以及父區(qū)塊編號(hào)麸澜,函數(shù)返回的是將要被創(chuàng)建的下一個(gè)區(qū)塊的難度值。

下表為一些相應(yīng)的input parameters奏黑。

Input Parameters Descriptions
time Proposed time of formation of new block.
parentTime Time of formation of parent Block.
parentNumber Parent block, block number.
parentDiff Difficulty of parent block

先根據(jù)版本號(hào)選擇相應(yīng)的難度計(jì)算函數(shù)炊邦,若為Frontier,則調(diào)用calcDifficultyFrontier熟史;若為Homestead馁害,則調(diào)用calcDifficultyHomestead

在以太坊硬分叉時(shí)難度調(diào)整算法有變動(dòng)蹂匹。

  1. Change the difficulty adjustment algorithm from the current formula: block_diff = parent_diff + parent_diff // 2048 * (1 if block_timestamp - parent_timestamp < 13 else -1) + int(2**((block.number // 100000) - 2)) (where the + int(2**((block.number // 100000) - 2)) represents the exponential difficulty adjustment component) to block_diff = parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99) + int(2**((block.number // 100000) - 2)), where // is the integer division operator, eg. 6 // 2 = 3, 7 // 2 = 3, 8 // 2 = 4. The minDifficulty still defines the minimum difficulty allowed and no adjustment may take it below this.
  2. The problem with the frontier formula and the reason for the change was that the frontier version doesn't take into account how far off from 13 seconds the block time was. A block mined 1 second after the previous one has the same effect on the difficulty as one mined after 12 seconds. This causes block difficulty to adjust to a median block time rather than a mean.

calcDifficultyHomestead函數(shù):

func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
    // 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).SetUint64(parentTime)

    // 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(common.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(parentDiff, params.DifficultyBoundDivisor)
    x.Mul(y, x)
    x.Add(parentDiff, x)

    // minimum difficulty can ever be (before exponential factor)
    if x.Cmp(params.MinimumDifficulty) < 0 {
        x.Set(params.MinimumDifficulty)
    }

    // for the exponential factor
    periodCount := new(big.Int).Add(parentNumber, common.Big1)
    periodCount.Div(periodCount, ExpDiffPeriod)

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

    return x
}

calcDifficultyFrontier函數(shù):

func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
    diff := new(big.Int)
    adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
    bigTime := new(big.Int)
    bigParentTime := new(big.Int)

    bigTime.SetUint64(time)
    bigParentTime.SetUint64(parentTime)

    if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
        diff.Add(parentDiff, adjust)
    } else {
        diff.Sub(parentDiff, adjust)
    }
    if diff.Cmp(params.MinimumDifficulty) < 0 {
        diff.Set(params.MinimumDifficulty)
    }

    periodCount := new(big.Int).Add(parentNumber, common.Big1)
    periodCount.Div(periodCount, ExpDiffPeriod)
    if periodCount.Cmp(common.Big1) > 0 {
        // diff = diff + 2^(periodCount - 2)
        expDiff := periodCount.Sub(periodCount, common.Big2)
        expDiff.Exp(common.Big2, expDiff, nil)
        diff.Add(diff, expDiff)
        diff = math.BigMax(diff, params.MinimumDifficulty)
    }

    return diff
}

Below is step by step process how difficulty of new block gets created.

  1. First, difference between time of formation of parent block and new block is calculated.

  2. Output of step 1 is then divided by 10 and integer of it is stored. This is done to create ranges. If output of step 1 is between 1 – 9 then output of this step will be 0. If output of step 1 is between 10 – 19 then output of this step will be 1. If output of step 1 is between 20 – 29 then output of this step will be 2 and so on.

  3. From step above various ranges gets created. Now in order to create three ranges we will subtract 1 from output of step 2. The three ranges will be either +ve, zero or –ve. If you see it carefully then output of this step will be +ve when output of step 1 is between 0 – 9, zero when output of step 1 is between 10 – 19 and –ve when output of step 1 is anything more than 20.

  4. Now compare output of previous step with -99 and if it is even lesser than -99 then set it as -99. This is done to limit the smallest possible value of step 3, otherwise keep the value of output of previous step as is.

  5. Next we divide the parent block difficulty by the difficulty bound divisor, whose value is 2048.

  6. Multiply output of step 4 with step 5. This will give the difference of difficulty of new block with old parent block. Depending is this value is +ve then difficulty will increase and if this value is –ve then then new difficulty will decrease.

  7. Now add output of step 6 to parent difficulty and result will be the difficulty of the new block.

  8. Once difficulty is calculated, a check is made to make sure that difficulty calculated is at least more than the minimum threshold value of 131072.

  9. Before returning the difficulty, check is done that if block number is more than 200,000 then “The Bomb” logic is applied to increase the difficulty exponentially.

  10. In order to increase the difficulty exponentially, new block number is calculated by adding one to the parent block number.

  11. Now new block number is divided by 100,000.

  12. If new block number is more than 200,000 then output of step 11 is subtracted from 2.

  13. Now exponentially increased difficulty delta is calculated by doing following calculation: 2 ^ output of step 12.

  14. And new difficulty is calculated by adding output of previous step to the difficulty calculated in step 7.


Summary

If the timestamp difference (block_timestamp - parent_timestamp) is:

  • < 10 seconds, the difficulty is adjusted upwards by parent_diff // 2048 * 1
  • 10 to 19 seconds, the difficulty is left unchanged
  • >= 20 seconds, the difficulty is adjust downwards proportional to the timestamp difference, from parent_diff // 2048 * -1 to a max downward adjustment of parent_diff // 2048 * -99

This is consistent with the statement from ethdocs.org - Ethereum Homestead - The Homestead Release:

EIP-2/4 eliminates the excess incentive to set the timestamp difference to exactly 1 in order to create a block that has slightly higher difficulty and that will thus be guaranteed to beat out any possible forks. This guarantees to keep block time in the 10-20 range and according to simulations restores the target 15 second blocktime (instead of the current effective 17s).

And from Ethereum Network Status, the average block time currently is 13.86 seconds.


Details

The difficulty adjustment formula:

    block_diff = parent_diff + parent_diff // 2048 * 
      max(1 - (block_timestamp - parent_timestamp) // 10, -99) + 
      int(2**((block.number // 100000) - 2))

where // is the integer division operator, eg. 6 // 2 = 3, 7 // 2 = 3, 8 // 2 = 4.

can be broken down into the following parts:

Sub-formula B - The difficulty bomb part, which increases the difficulty exponentially every 100,000 blocks.

+ int(2**((block.number // 100000) - 2))

The difficulty bomb won't be discussed here as it is already covered in the following Q&As:

Sub-formula A - The difficulty adjustment part, which increases or decreases the block difficulty depending on the time between the current block timestamp and the parent block timestamp:

+ parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)

Subformula A1 - Lets separate out part of Subformula A

+ max(1 - (block_timestamp - parent_timestamp) // 10, -99)

and consider what the adjustment effect is due to the timestamp difference between the current block and the parent block:

When (block_timestamp - parent_timestamp) is

  • 0, 1, 2, ..., 8, 9 seconds
    • A1 evaluates to max(1 - 0, -99) = 1
    • A evaluates to +parent_diff // 2048 * 1
  • 10, 11, 12, ..., 18, 19 seconds
    • A1 evaluates to max(1 - 1, -99) = 0
    • A evaluates to +parent_diff // 2048 * 0
  • 20, 21, 22, ..., 28, 29 seconds
    • A1 evaluates to max(1 - 2, -99) = -1
    • A evaluates to +parent_diff // 2048 * -1
  • 30, 31, 32, ..., 38, 39 seconds
    • A1 evaluates to max(1 - 3, -99) = -2
    • A evaluates to +parent_diff // 2048 * -2
  • 1000, 1001, 1002, ..., 1008, 1009 seconds
    • A1 evaluates to max(1 - 100, -99) = -99
    • A evaluates to +parent_diff // 2048 * -99
  • > 1009 seconds
    • A1 evaluates to max(1 - {number greater than 100}, -99) = -99
    • A evaluates to +parent_diff // 2048 * -99

So, if the timestamp difference (block_timestamp - parent_timestamp) is:

  • < 10 seconds, the difficulty is adjusted upwards by parent_diff // 2048 * 1
  • 10 to 19 seconds, the difficulty is left unchanged
  • >= 20 seconds, the difficulty is adjust downwards proportional to the timestamp difference, from parent_diff // 2048 * -1 to a max downward adjustment of parent_diff // 2048 * -99

So, this is basically how Ethereum tries to keep the mining time difference between 10 – 19 seconds. Now, if we carefully take a look to step 2, then we will observe that division by 10 helps to create three ranges. If the value falls in first range then difficulty is increased, if value falls in second range then difficult is kept constant and finally, if the range falls in third range then difficulty is reduced.

Now if we want to change the ranges of difficulty, we can do it by dividing it by some another number in step 2. That means, if we want to keep mining time difference in between 0 – 4 sec. then increase the difficulty, if mining time difference is between 5 – 9 sec. then keep the difficulty constant and if mining time is 10 or more sec. then try to reduce the difficulty, then instead of dividing by 10 you can divide the value by 5 in step 2. This way you can easily manage the ranges of mining difficulty.

Below is the graph showing Ethereum main network block difficulty growth.

*Source – *https://etherscan.io/chart/difficulty

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碘菜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子限寞,更是在濱河造成了極大的恐慌忍啸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件履植,死亡現(xiàn)場(chǎng)離奇詭異计雌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)玫霎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)凿滤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人庶近,你說(shuō)我怎么就攤上這事翁脆。” “怎么了拦盹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鹃祖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)恬口,這世上最難降的妖魔是什么校读? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮祖能,結(jié)果婚禮上歉秫,老公的妹妹穿的比我還像新娘。我一直安慰自己养铸,他們只是感情好雁芙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著钞螟,像睡著了一般兔甘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鳞滨,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天洞焙,我揣著相機(jī)與錄音,去河邊找鬼拯啦。 笑死澡匪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的褒链。 我是一名探鬼主播唁情,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼甫匹!你這毒婦竟也來(lái)了甸鸟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赛惩,失蹤者是張志新(化名)和其女友劉穎哀墓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喷兼,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡篮绰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了季惯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吠各。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖勉抓,靈堂內(nèi)的尸體忽然破棺而出贾漏,到底是詐尸還是另有隱情,我是刑警寧澤藕筋,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布纵散,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏伍掀。R本人自食惡果不足惜掰茶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜜笤。 院中可真熱鬧濒蒋,春花似錦、人聲如沸把兔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)县好。三九已至围橡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缕贡,已是汗流浹背某饰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留善绎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓诫尽,卻偏偏與公主長(zhǎng)得像禀酱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子牧嫉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容