Python - Abfrage des Blockheaders von Bitcoin mit leveldb

ich stehe vor einem blöden Problem. Ich versuche, bitcoin/blocks/index leveldb mit plyvel zu lesen. Ich habe einen Regtest eingerichtet und weiß, dass es einen Block mit dem Hash gibt:

27ce8199dee22f96e4f392dec29ef207fcd8a3c9e43b7d58cb40a5ba01af674b

Ich versuche es mit Plyvel abzufragen.

Beachten Sie, dass ich die Themen bereits gelesen habe:

Wie liest/schreibt Bitcoin LevelDB?

Welche Schlüssel werden in der Blockchain-LevelDB verwendet (dh was sind die Schlüssel:Wert-Paare)?

https://en.bitcoin.it/wiki/Protocol_documentation

Dann weiß ich, dass ich die Endianness austauschen muss, damit es wird:

MYVAR = "4b67af01baa540cb587d3be4c9a3d8fc07f29ec2de92f3e4962fe2de9981ce27"

Daher sollte ich so etwas abfragen:

b + (byte) MYVAR 

Allerdings bekomme ich nicht wie. Ich glaube, ich habe etwas in der Codierung missverstanden. Ich habe es versucht :

db.get(b'b4b67af01baa540cb587d3be4c9a3d8fc07f29ec2de92f3e4962fe2de9981ce27')
db.get(b'b'+b'4b67af01baa540cb587d3be4c9a3d8fc07f29ec2de92f3e4962fe2de9981ce27')

..

Dann habe ich die bitcoin/blocks/index leveldb mit einem GUI-Explorer geöffnet und festgestellt, dass der Schlüssel für diesen Block lautet:

\x62\x4b\x67\xaf\x01\xba\xa5\x40\xcb\x58\x7d\x3b\xe4\xc9\xa3\xd8\xfc\x07\xf2\x9e\xc2\xde\x92\xf3\xe4\x96\x2f\xe2\xde\x99\x81\xce\x27

was \x62 entspricht dem "b" + dem Hash mit \x (Escape-Zeichen? Ich weiß, hier ist mein Missverständnis bei der Hex-Codierung)

und offensichtlich

db.get(b'\x62\x4b\x67\xaf\x01\xba\xa5\x40\xcb\x58\x7d\x3b\xe4\xc9\xa3\xd8\xfc\x07\xf2\x9e\xc2\xde\x92\xf3\xe4\x96\x2f\xe2\xde\x99\x81\xce\x27')

funktioniert einwandfrei

Ich habe auch diese Methoden ausprobiert:

https://stackoverflow.com/questions/5649407/hexadecimal-string-to-byte-array-in-python

Keiner von ihnen funktioniert und ich verstehe wirklich nicht warum:

bytes.fromhex(hash)
bytearray.fromhex(hash)

Vielen Dank im Voraus

Antworten (2)

Diese Antwort ist etwas veraltet. Aber hier ist es trotzdem.

Sie müssen auf die Endianness der Bytes achten. Wie wir die Block-ID (Block-Header-Hash) betrachten, ist Bigendian, das höchstwertige Bit zuerst, und wie Bitcoin-Core alles hinter den Kulissen verwaltet, ist Littleendian, das niedrigstwertige Bit zuerst.

Hier ist ein einfaches Skript, um auf den gesamten leveldb-Blockindex zuzugreifen.

import re
from plyvel import DB

# Note for POSIX users, typically we have to escape spaces, 
# e.g. "Application\ Support". However this is not needed here so you 
# can write "Application Support" instead.
BITCOIN_DATADIR: str ="/absolute/path/to/your/bitcoin/datadir/"
db = DB(BITCOIN_DATADIR + "blocks/index")
keys = list(db.iterator(include_value=False))
regtest = re.compile(br"^b")
block_id_keys = list(filter(regtest.search, keys))

Wir können auf die Datenstruktur zugreifen und Folgendes sehen:

>>> bytes.hex(block_id_keys[-1][::-1][:-1])
'0000000000429f3501d60512df277b97f539becd18a7541b433e5110b2feffff'

https://blockstream.info/block/0000000000429f3501d60512df277b97f539becd18a7541b433e5110b2feffff

Wenn Sie die durchlaufen [-1][::-1][:-1], ist die [-1]das letzte Element in der Liste, die [::-1]ändert die Byte-Reihenfolge von Littleendian zu Bigendian und die [:-1]löscht die b"b".

Um den Rohschlüssel zu sehen, können wir die gesamte Struktur sehen:

>>> block_id_keys[-1]
b"b\xff\xff\xfe\xb2\x10Q>C\x1bT\xa7\x18\xcd\xbe9\xf5\x97{'\xdf\x12\x05\xd6\x015\x9fB\x00\x00\x00\x00\x00"

Beachten Sie, dass der Schlüssel mit beginnt b"b".

Um den Leveldb-Schlüssel von einer Bigendian-Hex-Block-ID zu erhalten, könnten Sie Folgendes tun:

>>> hex_data = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
>>> test_key = b"b" + bytes.fromhex(hex_data)[::-1]
>>> db.get(test_key)
b'\x8b\x99@\x00\x0b\x01\x00\x08\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\xa3\xed\xfdz{\x12\xb2z\xc7,>gv\x8fa\x7f\xc8\x1b\xc3\x88\x8aQ2:\x9f\xb8\xaaK\x1e^J)\xab_I\xff\xff\x00\x1d\x1d\xac+|'

Siehe auch https://bitcoin.stackexchange.com/a/29418/124452

Die leveldb-Datenbanken werden zur Optimierung serialisiert und funktionieren nicht gut mit dem Versuch, die Daten manuell zu parsen. Mit der integrierten JSON-RPC-API können Sie einfacher Details zu einem bestimmten Blockhash abrufen und den getblockAufruf verwenden.

Vielen Dank für Ihre Antwort, und ich werde sie tun. Was ich jedoch versuche, ist, auf Waisenblöcke zu verweisen. Ich bin mir nicht sicher, ob ich diese verwaisten Blöcke durch die API-Aufrufe sehen könnte. Ich meine, wenn ich weiß, dass Block O ein verwaister Block ist, kann ich Block O erhalten. Aber wenn ich nach verwaisten Blöcken suche, nicht Wenn ich ihren Hash kenne, werde ich wahrscheinlich auf einige Probleme stoßen. Das Iterieren über alle Schlüssel der Leveldb würde es mir ermöglichen, verwaiste Blöcke und "Haupt" -Blöcke zu unterscheiden.
Ich weiß, dass ich meine eigene Frage nicht beantworten sollte, aber ich habe einen Weg gefunden, dies zu tun: Ich bekomme alle Schlüssel mit db.iterator() und dann mit binascii.hexlify / unhexlify habe ich meine Probleme gelöst. Mein Arbeitsplatz war ein bisschen chaotisch und deshalb war mir nicht einmal klar, dass dieser einfache Trick funktioniert (ich bin mir sicher, dass ich es versucht hatte)