Цепочка блоков: как хеши делают историю неизменяемой

Слово «блокчейн» звучит сложно, но в основе лежит одна простая идея: связать блоки данных хешами так, чтобы подделать прошлое стало невозможно незаметно.

Напоминание про хеш

Хеш (SHA-256) — это «отпечаток» данных: фиксированная строка, которая полностью меняется при малейшем изменении входа. По хешу нельзя восстановить данные, но можно проверить, что данные не трогали.

import hashlib

def h(s):
    return hashlib.sha256(s.encode()).hexdigest()

print("hash('Аня шлёт 5'):", h("Аня шлёт 5")[:24], "...")
print("hash('Аня шлёт 6'):", h("Аня шлёт 6")[:24], "...")
print("Одна цифра — совершенно другой хеш!")

Идея цепочки

Каждый блок хранит свои данные и хеш предыдущего блока. Получается цепь: блок 2 ссылается на блок 1, блок 3 — на блок 2 и так далее. Если кто-то изменит старый блок, его хеш поменяется, и ссылка в следующем блоке перестанет совпадать — подделка сразу видна.

Собираем мини-блокчейн

import hashlib

def block_hash(index, data, prev_hash):
    body = f"{index}|{data}|{prev_hash}"
    return hashlib.sha256(body.encode()).hexdigest()

# Строим цепочку из 3 блоков
chain = []
prev = "0" * 64  # генезис-блок ссылается в никуда
for i, data in enumerate(["Аня -> Боре: 5", "Боря -> Вите: 2", "Витя -> Ане: 1"]):
    hsh = block_hash(i, data, prev)
    chain.append({"index": i, "data": data, "prev": prev, "hash": hsh})
    prev = hsh

for b in chain:
    print(f"Блок {b['index']}: {b['data']}")
    print(f"   prev: {b['prev'][:16]}...")
    print(f"   hash: {b['hash'][:16]}...")

Проверка целостности

Теперь попробуем подделать средний блок и увидим, как цепь «рвётся»:

import hashlib

def block_hash(index, data, prev_hash):
    return hashlib.sha256(f"{index}|{data}|{prev_hash}".encode()).hexdigest()

def build(datas):
    chain, prev = [], "0" * 64
    for i, d in enumerate(datas):
        hsh = block_hash(i, d, prev)
        chain.append({"index": i, "data": d, "prev": prev, "hash": hsh})
        prev = hsh
    return chain

def is_valid(chain):
    for i in range(1, len(chain)):
        recomputed = block_hash(chain[i]["index"], chain[i]["data"], chain[i]["prev"])
        if chain[i]["hash"] != recomputed:
            return False, i
        if chain[i]["prev"] != chain[i-1]["hash"]:
            return False, i
    return True, None

chain = build(["Аня -> Боре: 5", "Боря -> Вите: 2", "Витя -> Ане: 1"])
print("Цепочка цела?", is_valid(chain))

# Жулик меняет сумму во 2-м блоке
chain[1]["data"] = "Боря -> Вите: 9999"
ok, where = is_valid(chain)
print("После подделки цела?", ok, "| сломалось на блоке", where)

Почему это важно

Изменить один старый блок недостаточно — придётся пересчитать хеши всех последующих блоков. А в реальной сети тысячи компьютеров хранят копию цепочки и сверяют её. Подделать прошлое незаметно становится практически невозможно. Именно так хеши дают блокчейну неизменяемость.

Вывод:

Каждый блок хранит хеш предыдущего, образуя цепь. Изменение любого старого блока меняет его хеш и рвёт связь со следующим — подделка сразу заметна. Так SHA-256 делает историю блокчейна неизменяемой.
Проверьте себя
1. Что хранит каждый блок, чтобы образовать неразрывную цепь?
AПароль владельца
BХеш предыдущего блока
CПолную копию всего интернета
DСлучайное число без всякой связи
2. Почему трудно незаметно изменить старый блок в блокчейне?
AБлоки зашифрованы паролем
BИзменение меняет хеш блока, что рвёт связь со всеми последующими блоками, и их пришлось бы пересчитать
CСтарые блоки удаляются автоматически
DБлокчейн хранится только на одном компьютере
Поддержать проект