· 2 мин чтения
Хэш-цепочка журнала: что она ловит и чего нет
Как ledger-core строит цепочку SHA-256 и проверяет её через /v1/verify, почему подмена в середине видна, а усечение хвоста нет.
В ledger-core (Rust, SQLite) журнал проводок неизменяем: триггеры запрещают UPDATE и DELETE. Но триггер снимается тем, у кого есть файл БД. Поэтому защитой служит проверка цепочки.
Как устроена цепочка
Каждая запись хранит prev_hash и свой hash = SHA-256(версия, prev_hash, seq, ключ, время, валюта, комментарий, проводки). Поля идут с префиксом длины: так «ab»+«c» и «a»+«bc» дают разные байты, и склейка не бывает двусмысленной.
GET /v1/verify пересчитывает всё: непрерывность нумерации, соответствие prev_hash предыдущей записи и хэш каждой записи по её полям. Если запись подменили, проверка называет именно её.
Что ловится
Property-тесты (proptest) меняют сумму, комментарий или счёт и требуют, чтобы проверка указала подменённую запись. Отдельно проверены удаление записи в середине, срабатывание триггеров, идемпотентность и переполнение.
Что не ловится
Усечение хвоста. Если удалить несколько последних записей, оставшаяся цепочка остаётся корректной: каждая запись по-прежнему ссылается на предыдущую. Изнутри журнала этого не увидеть. Нужна точка опоры снаружи: head_hash последней записи надо периодически сохранять в другом месте и сравнивать при проверке.
Тем, кто читает это как «блокчейн защитит от всего», стоит помнить: цепочка доказывает целостность того, что осталось, а не полноту.
Измеренное
Образ 11,4 МБ; 3,5 МиБ RAM в покое и 4,5 МиБ после 200 запросов (100 параллельных проводок и 100 чтений), цепочка осталась целой. Тестов 19.