Un registro donde cambiar algo se nota
Una cadena de bloques es una lista de bloques de datos en la que cada bloque lleva el hash del bloque anterior. Si alguien cambia un dato antiguo, la cadena deja de encajar y el cambio se detecta.
Piensa en el cuaderno de gastos de un piso compartido. Si alguien tacha un apunte de hace un mes, quieres notarlo. Esta lección te enseña a construir ese aviso con hashes.
Al final de esta lección
Nota
Puedo enlazar bloques con hashes para que cualquier cambio en un bloque antiguo se detecte.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Bloque | un grupo de datos con su propio hash |
| Hash | la huella de longitud fija de unos datos |
| Hash anterior | el hash del bloque que va justo antes |
| Cadena | los bloques en orden, cada uno unido al anterior |
| Validar | recorrer la cadena y comprobar cada bloque |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un bloque guarda datos y el hash previo
Un bloque tiene cuatro partes: su posición, los datos, el hash del bloque anterior y su propio hash. El hash propio se calcula con las tres primeras.
El primer bloque no tiene anterior. Se le pone un anterior de 64 ceros, que es una convención.
Ejemplo: tres bloques enlazados
| Bloque | Datos | Hash anterior | Hash propio |
|---|---|---|---|
| 0 | Asha pays Ben 5 | 0000000000 | 000e13dc51 |
| 1 | Ben pays Cara 2 | 000e13dc51 | 0007118fa7 |
| 2 | Cara pays Asha 1 | 0007118fa7 | 000c5aaf76 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Qué imprime el laboratorio y en qué idioma
El laboratorio es una cadena de juguete escrita en Python. Sus scripts imprimen en inglés, con nombres como Asha y Ben.
El tuyo mostrará "block", "previous" y "hash". Solo se enseñan los diez primeros caracteres de cada hash. Fíjate en que la columna del hash anterior repite la del hash propio de la fila de arriba.
Construye tres bloques enlazados
docker exec jupyter python3 steps/link.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Cambiar un bloque rompe el enlace del siguiente
Si cambias los datos del bloque 1 sin tocar su hash, el hash ya no coincide con su contenido. Eso se ve enseguida.
Si recalculas ese hash, el bloque 1 queda bien. Pero el bloque 2 guardó el hash viejo. Su enlace falla, y para arreglarlo tendrías que rehacer también el bloque 2 y todos los siguientes.
Cambia un bloque y mira qué falla
import hashlib
CEROS = "0" * 64
def calcular_hash(indice, anterior, datos):
texto = str(indice) + "|" + anterior + "|" + datos
return hashlib.sha256(texto.encode()).hexdigest()
pagos = ["Ana paga 5 a Beto", "Beto paga 2 a Carla", "Carla paga 1 a Ana"]
cadena = []
anterior = CEROS
for n in range(3):
h = calcular_hash(n, anterior, pagos[n])
cadena.append({"index": n, "previous": anterior, "data": pagos[n], "hash": h})
anterior = h
# Cambia un importe del bloque 1, pero deja su hash como estaba.
cadena[1]["data"] = "Beto paga 20 a Carla"
# Prueba después a quitar el # de la línea siguiente.
# cadena[1]["hash"] = calcular_hash(1, cadena[1]["previous"], cadena[1]["data"])
for n in range(3):
b = cadena[n]
hash_propio = b["hash"] == calcular_hash(b["index"], b["previous"], b["data"])
if n == 0:
enlace = b["previous"] == CEROS
else:
enlace = b["previous"] == cadena[n - 1]["hash"]
print("bloque", n, "hash propio:", hash_propio, "enlace:", enlace)
Un error frecuente
Advertencia
Mucha gente cree que una cadena de bloques impide cambiar los datos. No es así. Cambiarlos es fácil. Lo que hace la cadena es que el cambio se note, porque todos los bloques siguientes dejan de encajar.
Validar es recorrer la cadena entera
Para validar una cadena miras cada bloque con dos preguntas. ¿Su hash coincide con su contenido? ¿Su hash anterior es el hash del bloque previo?
Si las dos respuestas son sí en todos los bloques, la cadena es válida. Si no, el primer bloque que falla te dice dónde empieza el problema.
Para ir más lejos
Abre el cuaderno start.ipynb del laboratorio y cambia solo el importe del bloque 0. Antes de ejecutar, di qué bloque será el primero que falle.
Después cambia solo el hash propio de un bloque a mano. ¿Dónde falla ahora?