Wie funktioniert der Ethereum Homestead-Schwierigkeitsanpassungsalgorithmus?

Ab From EIP 2 lautet der Homestead-Schwierigkeitsanpassungsalgorithmus:

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

wobei // der ganzzahlige Divisionsoperator ist, z. 6 // 2 = 3, 7 // 2 = 3, 8 // 2 = 4.

Wie funktioniert das?

(Diese Frage wurde durch die Frage Was war der erste Block, der mit Homestead abgebaut wurde? )


Andere verwandte Fragen und Antworten:

Antworten (2)

Zusammenfassung

Wenn die Zeitstempeldifferenz (block_timestamp - parent_timestamp):

  • < 10 Sekunden, der Schwierigkeitsgrad wird um nach oben angepasstparent_diff // 2048 * 1
  • 10 bis 19 Sekunden, die Schwierigkeit bleibt unverändert
  • >= 20 Sekunden, die Schwierigkeit wird proportional zur Zeitstempeldifferenz nach unten angepasst, von parent_diff // 2048 * -1bis zu einer maximalen Abwärtsanpassung vonparent_diff // 2048 * -99

Dies stimmt mit der Aussage von ethdocs.org - Ethereum Homestead - The Homestead Release überein :

EIP-2/4 eliminiert den übermäßigen Anreiz, die Zeitstempeldifferenz auf genau 1 zu setzen, um einen Block zu erstellen, der einen etwas höheren Schwierigkeitsgrad hat und der somit garantiert alle möglichen Forks schlägt. Dies garantiert, dass die Blockzeit im Bereich von 10 bis 20 Sekunden bleibt, und stellt laut Simulationen die angestrebte Blockzeit von 15 Sekunden wieder her (statt der aktuellen effektiven 17 Sekunden).

Und laut Ethereum Network Status beträgt die durchschnittliche Blockzeit derzeit 13,86 Sekunden.



Einzelheiten

Die Schwierigkeitsanpassungsformel:

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

wobei // der ganzzahlige Divisionsoperator ist, z. 6 // 2 = 3, 7 // 2 = 3, 8 // 2 = 4.

kann in folgende Teile zerlegt werden:


Unterformel B - Der Schwierigkeitsbombenteil, der die Schwierigkeit alle 100.000 Blöcke exponentiell erhöht.

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

Die Schwierigkeitsbombe wird hier nicht besprochen, da sie bereits in den folgenden Fragen und Antworten behandelt wird:


Teilformel A – Der Schwierigkeitsanpassungsteil, der die Blockschwierigkeit abhängig von der Zeit zwischen dem Zeitstempel des aktuellen Blocks und dem Zeitstempel des übergeordneten Blocks erhöht oder verringert:

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

Teilformel A1 - Lassen Sie uns einen Teil der Teilformel A heraustrennen

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

und überlegen Sie, was der Anpassungseffekt aufgrund der Zeitstempeldifferenz zwischen dem aktuellen Block und dem übergeordneten Block ist:

Wann (block_timestamp - parent_timestamp)ist

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


Also, wenn die Zeitstempeldifferenz (block_timestamp - parent_timestamp)ist:

  • < 10 Sekunden, der Schwierigkeitsgrad wird um nach oben angepasstparent_diff // 2048 * 1
  • 10 bis 19 Sekunden, die Schwierigkeit bleibt unverändert
  • >= 20 Sekunden, die Schwierigkeit wird proportional zur Zeitstempeldifferenz nach unten angepasst, von parent_diff // 2048 * -1bis zu einer maximalen Abwärtsanpassung vonparent_diff // 2048 * -99



Der Quellcode

Von Go Ethereum - core/block_validator.go, Zeilen 264-311 :

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
}
@BookyPooBah Danke für eine ausführliche Anleitung. Ist in Ihrer Erklärung für die Teilformeln A und A1 für 20-29Sekunden und 30-39Sekunden nicht das Ergebnis von A1 -1bzw. -2?
Okay, das macht Sinn, im Wesentlichen betrachten Sie den Zeitstempelunterschied von den letzten 2 Blöcken und extrahieren die 2. signifikante Ziffer. Diese Ziffer ist der entscheidende Faktor, ob Blöcke zu langsam, zu schnell oder genau richtig sind. 2048Können Sie die magische Zahl erklären ? Was ist die Idee hinter der Division durch 2048und warum diese Zahl?
@BokkyPooBah Ich finde es toll, dass du dir die Zeit genommen hast, diesen ausführlichen Bericht zu schreiben: Ich habe daraus gelernt. Ich möchte Folgendes hinzufügen: github.com/ethereum/go-ethereum/blob/… Egal wie schlecht Ihre Hashrate ist, es gibt ein Minimum, das Sie nicht unterschreiten können. github.com/ethereum/go-ethereum/blob/…
Die in der Zusammenfassung verwendeten Bereiche enthalten keinen (19,20)Bereich.
@greatwolf es ist ein schwierigkeitsgebundener Divisor, wäre er kleiner gewesen, würden die Anreize nicht funktionieren

Der Algorithmus von Ethereum wäre besser gewesen, wenn max() nicht verwendet worden wäre. parent_diff/2048*(1-t/10) hätte erweitert werden können, um die Null zu verhindern, die sich aus der Ganzzahldivision ergibt. Dies hätte zur Folge gehabt

diff = parent_diff + parent_diff/N – parent_diff*t/T/N

wobei t = übergeordnete Lösungszeit T = Ziellösungszeit N = Auslöschungskoeffizient, auch bekannt als "mittlere Lebensdauer", auch bekannt als Anzahl der Blöcke, um die Größe der Antwort zu "temperieren" oder zu "puffern". Er darf nicht zu klein sein oder eine negative Schwierigkeit kann durch lange Solvetimes entstehen.

Dies kommt dem theoretisch besten Algorithmus sehr nahe, der ein exponentieller gleitender Durchschnitt (EMA) ist, den ich und andere untersucht haben. Es ist eine Annäherung des EMA durch die Taylor-Reihenerweiterung der Exponentialfunktion:

e^x = 1 + x + x^2/2! + ...

Wobei Sie die Näherung e^x = 1 + x im EMA-Algorithmus verwenden:

diff = parent_diff*( 1 - A + A*T/t )

wobei A = alpha = 1-e^(-t/T/N)

Siehe https://github.com/zawy12/difficulty-algorithms/issues/17

Dieser Algorithmus wurde von Jacob Eliosoff entdeckt, der bereits sehr vertraut mit EMAs für Aktienkurse war. Er musste es an den Schwierigkeitsgrad anpassen, und das Ergebnis stellt sich als bekannte Version heraus, die in Wikipedia in Bezug auf die Schätzung der Computerleistung erwähnt wird:

https://en.wikipedia.org/wiki/Moving_average#Application_to_measuring_computer_performance

Ich sage, es ist theoretisch am besten, weil Sie N bis auf "1" reduzieren können und die mittleren und mittleren Lösungszeiten nahe an den erwarteten T und ln (2) * T liegen. Es ist also der beste Schätzer (den ich kenne), um die aktuelle Hashrate nur auf der Grundlage des vorherigen Blocks zu erraten.