Python: consultar el encabezado del bloque de bitcoin usando leveldb

Estoy frente a un problema estúpido. Estoy tratando de leer bitcoin/blocks/index leveldb usando plyvel. Configuré una prueba de registro y sé que hay un bloque con el hash:

27ce8199dee22f96e4f392dec29ef207fcd8a3c9e43b7d58cb40a5ba01af674b

Estoy tratando de consultarlo usando plyvel.

Tenga en cuenta que ya leí los temas:

¿Cómo lee/escribe Bitcoin en LevelDB?

¿Cuáles son las claves utilizadas en el levelDB de blockchain (es decir, cuáles son los pares clave:valor)?

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

Entonces, sé que tengo que cambiar el endianness para que se convierta en:

MYVAR = "4b67af01baa540cb587d3be4c9a3d8fc07f29ec2de92f3e4962fe2de9981ce27"

Por lo tanto, debería consultar algo como:

b + (byte) MYVAR 

Sin embargo no entiendo cómo. Supongo que no entiendo algo en la codificación. Lo intenté :

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

..

Luego, abrí bitcoin/blocks/index leveldb usando un explorador de interfaz gráfica de usuario y noté que la clave para este bloque es:

\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

que es \x62 correspondiente a la "b" + el hash con \x (caracter de escape? Sé que aquí está mi malentendido sobre la codificación hexadecimal)

y obviamente

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')

funciona perfectamente

También probé estos métodos:

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

Ninguno de ellos funciona y realmente no entiendo por qué:

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

gracias de antemano

Respuestas (2)

Esta respuesta es un poco obsoleta. Pero aquí está de todos modos.

Debe observar la endianidad de los bytes. La forma en que miramos la identificación del bloque (hash del encabezado del bloque) es bigendian, el bit más significativo primero, y la forma en que bitcoin-core administra todo detrás de escena es littleendian, el bit menos significativo primero.

Aquí hay una secuencia de comandos simple para acceder a todo el índice de bloques de leveldb.

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))

Podemos acceder a la estructura de datos y ver esto:

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

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

Pasando por el [-1][::-1][:-1], el [-1]es el último elemento de la lista, cambia [::-1]el orden de los bytes de littleendian a bigendian, y [:-1]suelta el b"b".

Para ver la clave sin procesar, podemos ver la estructura completa:

>>> 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"

Tenga en cuenta que la clave comienza con b"b".

Para obtener la clave leveldb de un blockid hexadecimal bigendiano, puede hacer lo siguiente:

>>> 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+|'

Consulte también https://bitcoin.stackexchange.com/a/29418/124452

Las bases de datos leveldb se serializan para la optimización y no funcionan bien al intentar analizar manualmente los datos. Puede obtener más fácilmente detalles sobre un blockhash específico utilizando la API JSON-RPC integrada y utilizar la getblockllamada.

Gracias por tu respuesta, así lo haré. Sin embargo, lo que intento hacer es hacer referencia a bloques huérfanos. No estoy seguro de poder ver estos bloques huérfanos a través de las llamadas API. Quiero decir, si sé que el bloque O es un bloque huérfano, podré obtener el bloque O. Pero si estoy buscando bloques huérfanos, no sabiendo su hash, probablemente enfrentaré algunos problemas. Iterar sobre todas las claves de leveldb me permitiría distinguir el bloque huérfano y los bloques "principales".
Sé que no debería responder a mi propia pregunta, pero encontré la manera de hacerlo: obtengo todas las claves usando db.iterator() Y luego usando binascii.hexlify / unhexlify He resuelto mis problemas. Mi espacio de trabajo estaba un poco desordenado y por eso ni me di cuenta de que ese simple truco funciona (seguro que lo había intentado)