Ejemplo de prueba de trabajo en Ruby, ¿qué estoy haciendo mal?

Dado el siguiente bloque, ¿cómo verifico la prueba de trabajo? Obtuve estos datos de bitcoin-cli getblock y los analicé en un hash de Ruby llamado datos:

{"hash"=>"00000000000000001354e21fea9c1ec9ac337c8a6c0bda736ec1096663383429",
 "confirmations"=>2, "size"=>529935, "height"=>347928, "version"=>2,
 "merkleroot"=>"14b2c974a4f9ab92a68f03a491965063d1f8a2e8b2268fdb4cbce92262bb09c0", 
"tx"=>"..removed for space convenience...", "time"=>1426554998, 
"nonce"=>3284264479, "bits"=>"18172ec0", "difficulty"=>47427554950.6483, 
"chainwork"=>"000000000000000000000000000000000000000000056f68a6406c831f16c1bd", 
"previousblockhash"=>"000000000000000007c464352935f12c3695f7de4eee8390f444233682abf8aa",     
"nextblockhash"=>"000000000000000016e3530b3a7cdaaa495e6eb70aa8f3f15d02fd078235e931"}

He probado lo siguiente:

version = "02000000"
prev = data["previousblockhash"]
merkle = data["merkleroot"]
time = data["time"].to_s(16) #convert to hex
bits = data["bits"]
nonce = data["nonce"]

hashable = version + prev + merkle + time + bits + nonce

answer = Digest::SHA256.hexdigest hashable

El problema es que mi respuesta es esta:

b7dc9db86cdf47bf1b13274f88b14211a1ce58c52ac1e41c987b4ad65cf50f4f

pero la respuesta dada (en data["hash"]) es

00000000000000001354e21fea9c1ec9ac337c8a6c0bda736ec1096663383429

¿Qué estoy haciendo mal?

Gracias por cualquier ayuda, Kevin

Respuestas (1)

Algunas cosas que deben corregirse aquí:

  1. Endianness: los datos que se le brindan en JSON están casi completamente en big endian, pero bitcoin usa little endian para serializar encabezados de bloque antes del hash.
  2. Debe duplicar el resultado con hash SHA256, lo que significa aplicarlo una vez en el encabezado y luego aplicar el algoritmo nuevamente en el resultado del primer hash.
  3. Conversión a binario antes del hash. No puede simplemente codificar los caracteres ascii, ya que son solo una codificación para el binario subyacente, que es lo que debe codificarse.

No estoy muy familiarizado con Ruby, pero hice un pequeño script en Python que puedes usar como referencia.

import hashlib
import binascii

def rev(string):
    revsed = ""
    for i in range(int(len(string)/2)):
        revsed = string[2*i : 2*i+2] + revsed
    return revsed

def DoubleHash(string):
    bin = binascii.unhexlify(string)
    hash = hashlib.sha256(hashlib.sha256(bin).digest()).digest()
    raw = str(binascii.hexlify(hash))[2:-1]
    return rev(raw)


# Straight from JSON

version = "02000000"
prev    = "000000000000000007c464352935f12c3695f7de4eee8390f444233682abf8aa"
merkle  = "14b2c974a4f9ab92a68f03a491965063d1f8a2e8b2268fdb4cbce92262bb09c0"
time    = "55078076" # hex(1426554998)
bits    = "18172ec0"
nonce   = "c3c1e61f" # hex(3284264479)

header = version + rev(prev) + rev(merkle) + rev(time) + rev(bits) + rev(nonce)

print(header)
print(DoubleHash(header))

Los resultados:

02000000aaf8ab82362344f49083ee4edef795362cf135293564c4070000000000000000c009bb6222e9bc4cdb8f26b2e8a2f8d163509691a4038fa692abf9a474c9b21476800755c02e17181fe6c1c3
00000000000000001354e21fea9c1ec9ac337c8a6c0bda736ec1096663383429
Gracias por esto, parece que tu anterior no se invirtió correctamente o no entiendo lo que estás haciendo: los últimos 5 de anterior: bf8aa tu versión anterior en el encabezado: aaf8a
Tienes que listar los bytes en orden inverso. Cada byte son dos caracteres hexadecimales. El bloque anterior es 0000...f8aa. Solo tiene que enumerar los bytes en el orden inverso como aaf8...0000. es decir, 1234 bytes invertidos son 3412.
ok, ya veo, ¿entonces es byte invertido y Endian invertido?
Endian invertido solo significa que necesita enumerar los bytes en el orden opuesto. Recuerda marcar las respuestas como correctas si respondieron a tu pregunta.
lo siento por no ser claro, entiendo lo que significaba endian invertido, estaba intentando obtener la confirmación de que se requieren dos pasos de procesamiento distintos 1) endian inverso (intercambiar los bytes hexadecimales) y 2) invertir la cadena
Invertir el endianness es lo mismo que invertir los bytes en la cadena.