Ein kurzes Programm, um einen Block abzubauen

Jeder kann den folgenden Code Schritt für Schritt erklären (wenn möglich mit ac/c++-Äquivalent)?

import hashlib, struct

ver = 2
prev_block = "000000000000000117c80378b8da0e33559b5997f2ad55e2f7d18ec1975b9717"
mrkl_root = "871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a"
time_ = 0x53058b35 # 2014-02-20 04:57:25
bits = 0x19015f53

# https://en.bitcoin.it/wiki/Difficulty
exp = bits >> 24
mant = bits & 0xffffff
target_hexstr = '%064x' % (mant * (1<<(8*(exp - 3))))
target_str = target_hexstr.decode('hex')

nonce = 0
while nonce < 0x100000000:
    header = ( struct.pack("<L", ver) + prev_block.decode('hex')[::-1] +
          mrkl_root.decode('hex')[::-1] + struct.pack("<LLL", time_, bits, nonce))
    hash = hashlib.sha256(hashlib.sha256(header).digest()).digest()
    print nonce, hash[::-1].encode('hex')
    if hash[::-1] < target_str:
        print 'success'
        break
    nonce += 1

Ich versuche, meine eigene Implementierung zu erstellen; Ich habe die Blockdaten bereits mit json-rpc gelesen und in dieser Struktur gespeichert:

struct block {
  unsigned char* hash;
  int confirmations;
  long strippedsize;
  long size;
  long weight;
  long height;
  long version;
  unsigned char* versionHex;
  unsigned char* merkleroot;
  long blocktime;
  long mediantime;
  long nonce;
  unsigned char* bits;
  double difficulty;
  unsigned char* chainwork;
  unsigned char* previousblockhash;
};

Jetzt möchte ich die Daten aus dieser Struktur extrahieren und verwenden, um dieselben Berechnungen in diesem Code auszuführen, aber ich muss verstehen, was der Code mit mehr Details macht.

Antworten (1)

Zuerst definieren wir einige Informationen, die in den Block gehen, nämlich welche Version der Block ist, was der vorherige Block-Hash war (da jeder Block auf den vorherigen verweist, um die Kette zu erstellen), was die Merkle-Root aller Transaktionen in diesem Block ist (siehe Wikipedia , wenn Sie nicht wissen, was das ist), der aktuelle Zeitstempel und die aktuelle Schwierigkeit, die in der bitsVariablen codiert ist:

import hashlib, struct

ver = 2
prev_block = "000000000000000117c80378b8da0e33559b5997f2ad55e2f7d18ec1975b9717"
mrkl_root = "871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a"
time_ = 0x53058b35 # 2014-02-20 04:57:25
bits = 0x19015f53

Dann nehmen wir den bitsWert und wandeln ihn in ein Schwierigkeitsziel um, basierend auf den Schritten, die auf der verlinkten Wiki-Seite zum Schwierigkeitsgrad aufgeführt sind. Das Ziel ist im Grunde eine Zahl, für die wir einen Hash unten finden möchten (z. B. wenn das Ziel 10 wäre, wären nur Hashes kleiner als 10 gültig):

# https://en.bitcoin.it/wiki/Difficulty
exp = bits >> 24
mant = bits & 0xffffff
target_hexstr = '%064x' % (mant * (1<<(8*(exp - 3))))
target_str = target_hexstr.decode('hex')

Jetzt starten wir eine Schleife und hashen den Block viele Male mit unterschiedlichen Nonce-Werten, bis wir einen Hash finden, der kleiner als das Ziel ist. Wir beginnen die Nonce bei 0 und erhöhen sie bei jeder Schleife um 1, sodass wir jedes Mal einen anderen Hash erhalten:

nonce = 0
while nonce < 0x100000000:

Dies ist nur das Zusammenfügen der Daten, die wir zuvor definiert haben (einschließlich der Nonce), in den serialisierten Block, der bereit ist, gehasht zu werden:

    header = ( struct.pack("<L", ver) + prev_block.decode('hex')[::-1] +
          mrkl_root.decode('hex')[::-1] + struct.pack("<LLL", time_, bits, nonce))

Hier hashen wir tatsächlich die serialisierten Blockdaten und erhalten einen Hash, den wir (als hexadezimale Zeichenfolge codiert) mit der Nonce für Protokollierungszwecke ausdrucken:

    hash = hashlib.sha256(hashlib.sha256(header).digest()).digest()
    print nonce, hash[::-1].encode('hex')

Schließlich vergleichen wir den Hash-Wert mit dem Ziel, und wenn er niedriger als das Ziel ist, haben wir erfolgreich einen gültigen Block gefunden, andernfalls versuchen wir die nächste Nonce:

    if hash[::-1] < target_str:
        print 'success'
        break
    nonce += 1

Beachten Sie, dass dies ein sehr einfaches Programm ist, das gut zum Verständnis ist, aber im echten Bergbau nicht wirklich funktionieren würde, da das Ändern der Nonce allein nicht mehr ausreicht, um einen Block zu finden. Die Daten variieren auch in der Coinbase-Transaktion, um die Merkle-Root zu ändern sowie. Das liegt nur daran, dass das Ziel so niedrig ist (Schwierigkeit so hoch), dass die Chance, es zu treffen, ziemlich gering ist, um die massive Mining-Power im Netzwerk zu bekämpfen. Das Programm berechnet auch nicht die Merkle-Wurzel selbst, was getan werden muss, wenn Sie direkt mit Transaktionen beginnen.

Wie bekomme ich die Daten, die auf den Block gehen? Wenn ich einen Block aus dem Bitcoin-Netzwerk bekomme (zum Beispiel mit getbestblokchashdem Befehl json-rpc), kann ich den Datenextrakt aus diesem Block als Basis für den generierten Header verwenden? Oder muss ich nur alle neuen Daten für einen komplett neuen Block erstellen? Wie erhalte ich in diesem letzten Fall diese Transaktionen, um den Merkle-Root zu generieren? Oder wird es nur mit der Coinbase-Transaktion generiert?
getbestblockhashwird dir geben prev_block. Die Schwierigkeit wird mithilfe des Schwierigkeits-Retargeting-Algorithmus gefunden. Transaktionen werden im Laufe der Zeit von mit dem Netzwerk verbundenen Knoten im Mempool erfasst. Bitte stellen Sie nicht mehrere Fragen als Kommentare, bearbeiten Sie entweder Ihre ursprüngliche Frage oder posten Sie eine neue.