Skip to content

Харфорки

Харфорк — это обновление сети, изменяющее правила консенсуса. Все узлы должны обновиться до запланированной временной метки активации; узлы, работающие на старом программном обеспечении, разойдутся с сетью после активации.


Механизм активации

Каждый харфорк имеет:

  • Уникальный номер (N).
  • Unix-временную метку — самое раннее время по системным часам, когда харфорк может активироваться.
  • Суперквалифицированное большинство голосов валидаторов — >80% текущего набора валидаторов должны подать сигнал новой версии харфорка через validator_update_operation.

Оба условия должны выполняться одновременно. Валидаторы могут заблокировать нежелательный харфорк, удерживая свой голос за версию даже после наступления запланированной временной метки.


История харфорков

#ВерсияКлючевые изменения
1–101.x – 2.xФундамент, социальный граф, система энергии, комитет, подписки
113.0.0
123.1.0Метрики коллизий форков, сравнение форков с весом голосов, режим экстренного консенсуса, улучшения NTP
133.2.0Совместное использование наград валидаторов с распределением пропорционально голосам

Краткое описание HF12

HF12 (версия 3.1.0) ввёл:

  1. Счётчик коллизий форковfork_collision_count и last_fork_collision_block_num добавлены в dynamic_global_property_object. Доступно через get_dynamic_global_properties.
  2. Сравнение форков с весом голосов (compare_fork_branches()) — выбор форка использует общий делегированный SHARES по ветви валидатора + 10% бонус за более длинную цепочку.
  3. Режим экстренного консенсуса — активируется автоматически через 1 час без блоков; аккаунт "committee" занимает все 21 слот. См. Экстренный консенсус.
  4. Авто-ресинхронизация minority fork — плагин validator обнаруживает изоляцию узла (21 последовательный собственный блок) и откатывается до LIB.
  5. Улучшения NTP — выделенный NTP-клиент с настраиваемыми серверами, интервалом и порогом времени туда-обратно.

Краткое описание HF13

HF13 (версия 3.2.0) ввёл:

Совместное использование наград валидаторов: часть награды валидатора каждого блока перераспределяется пропорционально аккаунтам, проголосовавшим за этого валидатора (по их весу голосов в SHARES).

  • Новое поле в validator_object: reward_percent — доля награды за блок, делимая с голосующими (0–10000 базисных пунктов).
  • Новая виртуальная операция: validator_reward_virtual_operation — срабатывает один раз при каждом распределении наград.
  • Устанавливается через validator_update_operation.

Реализация нового харфорка

Шаг 1: Создать файл определения харфорка

libraries/chain/hardfork.d/N.hf:

cpp
#ifndef CHAIN_HARDFORK_N
#define CHAIN_HARDFORK_N N
#define CHAIN_HARDFORK_N_TIME  1234567890  // Unix-временная метка — должна быть в будущем
#define CHAIN_HARDFORK_N_VERSION hardfork_version(3, N, 0)
#endif

Шаг 2: Увеличить константы

libraries/chain/hardfork.d/0-preamble.hf:

cpp
#define CHAIN_NUM_HARDFORKS N

libraries/protocol/include/graphene/protocol/config.hpp (если видимо протоколу):

cpp
#define CHAIN_VERSION  (version(3, N, 0))

Шаг 3: Версия схемы

Если изменяется какая-либо разметка объекта chainbase (новые поля, удалённые поля, изменённые типы), увеличьте CHAIN_SCHEMA_VERSION в config.hpp:

cpp
#define CHAIN_SCHEMA_VERSION  uint32_t(N)

Плагин chain проверяет это при запуске. Несоответствие очищает shared_memory.bin перед открытием, предотвращая некорректное чтение из старых разметок.

Новые поля всегда должны иметь нулевые значения по умолчанию, чтобы избежать кода миграции:

cpp
uint16_t my_new_field = 0;

Шаг 4: Подключить в database.cpp

init_hardforks():

cpp
FC_ASSERT(CHAIN_HARDFORK_N == N);
_hardfork_times[N]    = fc::time_point_sec(CHAIN_HARDFORK_N_TIME);
_hardfork_versions[N] = hardfork_version(CHAIN_HARDFORK_N_VERSION);

Случай в apply_hardfork():

cpp
case CHAIN_HARDFORK_N: {
    // Миграция при необходимости. Оставить пустым с комментарием, если нулевые значения по умолчанию покрывают это.
    break;
}

Шаг 5: Операция и evaluator (при наличии новой операции)

  1. Добавить структуру в chain_operations.hpp с validate() и геттерами авторизации.
  2. Добавить в static_variant в operations.hpp.
  3. Объявить DEFINE_EVALUATOR(my_new_op) в chain_evaluator.hpp.
  4. Реализовать do_apply() в .cpp файле evaluator — всегда сначала проверять ASSERT_REQ_HF(CHAIN_HARDFORK_N, ...).
  5. Зарегистрировать в initialize_evaluators() в database.cpp.

Шаг 6: Обновление плагинов

ПлагинЧто обновить
account_historyДобавить экстрактор воздействия для любой новой виртуальной операции
validator_apiДобавить новые поля из validator_object в validator_api_object
snapshotДобавить новые объекты chainbase в serialize_state / load_snapshot

Жизненный цикл версии схемы

Новый узел (без существующих данных):
  stored = 0, compiled = N → несоответствие
  очистить shared_memory (нет операций при отсутствии)
  записать schema_version = N
  genesis → нормальный запуск

Обновление (старый бинарный файл имел версию M < N):
  stored = M, compiled = N → несоответствие
  очистить shared_memory.bin
  записать schema_version = N
  db.open() → исключение несоответствия ревизии
  → авто-восстановление: импорт снимка + воспроизведение dlt_block_log

Нормальный перезапуск:
  stored = N, compiled = N → совпадение
  db.open() продолжается нормально

Ключевые файлы:

  • config.hppCHAIN_SCHEMA_VERSION
  • plugins/chain/plugin.cpp — логика проверки схемы и очистки
  • <data_dir>/schema_version — текстовый файл с текущей версией

Чеклист развёртывания

  • [ ] CHAIN_NUM_HARDFORKS увеличен
  • [ ] CHAIN_VERSION обновлён (если видимо протоколу)
  • [ ] CHAIN_SCHEMA_VERSION увеличен (если изменилась разметка объекта chainbase)
  • [ ] Файл харфорка .hf создан с будущей временной меткой активации
  • [ ] Все новые поля имеют нулевые значения по умолчанию; комментарий в apply_hardfork объясняет, почему миграция не нужна
  • [ ] Новый evaluator зарегистрирован в initialize_evaluators()
  • [ ] Новая виртуальная операция зарегистрирована в плагине account_history
  • [ ] validator_api_object обновлён если изменился validator_object
  • [ ] Плагин snapshot обновлён если добавлены новые объекты chainbase

См. также: Fair-DPOS, Экстренный консенсус, Снимки.