From 4a9a40df4c1b554915b4d6e5c116bd1de5d10044 Mon Sep 17 00:00:00 2001 From: Vladimir Babin Date: Sun, 25 Oct 2026 16:20:07 +0800 Subject: [PATCH 1/2] snapshot: restore PM seed flags; docs: HF16 readiness check import_dynamic_global_properties rebuilt dgp field by field and skipped pm_frozen_counters_seeded, pm_frozen_counters_reseeded_v1, pm_active_markets_seeded and pm_oracle_gauges_seeded. Export is reflection-based and carries them, so a restored node re-ran the one-time seeds on its first block and its later snapshots disagreed with the network. Read them with the same absent-defaults pattern as round_anchor_*. hf16.md (en/ru): "Verify readiness" section. Activation needs 17 of 21 validators voting 4.2.0 @ 1793404800; shows get_next_scheduled_hardfork and get_validators_by_vote and what to count in each. --- @l10n/ru/docs/consensus/hf16.md | 12 ++++++++++++ docs/consensus/hf16.md | 12 ++++++++++++ plugins/snapshot/plugin.cpp | 11 +++++++++++ 3 files changed, 35 insertions(+) diff --git a/@l10n/ru/docs/consensus/hf16.md b/@l10n/ru/docs/consensus/hf16.md index 9697cf80b3..e94d0cb073 100644 --- a/@l10n/ru/docs/consensus/hf16.md +++ b/@l10n/ru/docs/consensus/hf16.md @@ -6,6 +6,18 @@ HF16 назначен на **31 октября 2026, 00:00:00 UTC** (`1793404800 После сборки master перед распространением проверьте ревизию/версию конкретного образа, запуск, синхронизацию и производство блоков. Сохраните настроенный ключ валидатора и резервную копию данных. Удаление каталога данных не является процедурой обновления. +### Проверка готовности + +Для активации нужно `CHAIN_HARDFORK_REQUIRED_VALIDATORS` = 17 из 21 валидаторов расписания, производящих блоки с голосом за 4.2.0. Если к 31.10.2026 00:00 UTC обновилось меньше, форк активируется на блоке, где появится 17-й голос, без объявленного момента. До даты проверьте оба сигнала: + +```json +{ "method": "database_api.get_next_scheduled_hardfork", "params": [] } +{ "method": "validator_api.get_validators_by_vote", "params": ["", 21] } +``` + +- `get_next_scheduled_hardfork` возвращает `hf_version` 4.2.0 и `live_time` 2026-10-31T00:00:00, когда голосование набрало порог. До этого поле повторяет текущую версию. +- В `get_validators_by_vote` посчитайте записи с `hardfork_version_vote` 4.2.0 и `hardfork_time_vote` 2026-10-31T00:00:00. `running_version` показывает бинарник, с которым валидатор последний раз произвёл блок. Цель: не меньше 17 из 21 активных. + ## Слоты, QC, TC и финальность - При HF16 рабочий слот меняется с **3 секунд на 1 секунду**. Читайте текущее значение `get_config` и время блоков: прежняя константа `CHAIN_BLOCK_INTERVAL` не задаёт слот после форка. diff --git a/docs/consensus/hf16.md b/docs/consensus/hf16.md index da03e5e81d..b7dd8b3cd9 100644 --- a/docs/consensus/hf16.md +++ b/docs/consensus/hf16.md @@ -6,6 +6,18 @@ HF16 is scheduled for **2026-10-31 00:00:00 UTC** (`1793404800`), version **4.2. After the master image is built, check its revision/version, startup, synchronization and block production before distributing that exact image/digest. Keep the configured validator key and data-directory backup. Do not delete the data directory as an update procedure. +### Verify readiness + +Activation needs `CHAIN_HARDFORK_REQUIRED_VALIDATORS` = 17 of the 21 scheduled validators producing blocks with the 4.2.0 vote. If fewer have upgraded by 2026-10-31 00:00 UTC, the fork activates at the block where the 17th vote lands, with no announced moment. Check both signals before the date: + +```json +{ "method": "database_api.get_next_scheduled_hardfork", "params": [] } +{ "method": "validator_api.get_validators_by_vote", "params": ["", 21] } +``` + +- `get_next_scheduled_hardfork` returns `hf_version` 4.2.0 and `live_time` 2026-10-31T00:00:00 once the vote has locked in. Until then it mirrors the current version. +- In `get_validators_by_vote`, count entries with `hardfork_version_vote` 4.2.0 and `hardfork_time_vote` 2026-10-31T00:00:00. `running_version` shows the binary each validator last produced with. Target: at least 17 of the active 21. + ## Slots, QC, TC and finality - The runtime slot changes from **3 seconds to 1 second** at HF16. Use the node's current `get_config` value and block timestamps; the compile-time legacy `CHAIN_BLOCK_INTERVAL` is not the post-fork slot. diff --git a/plugins/snapshot/plugin.cpp b/plugins/snapshot/plugin.cpp index 69098d693f..7de2f4fdea 100644 --- a/plugins/snapshot/plugin.cpp +++ b/plugins/snapshot/plugin.cpp @@ -229,6 +229,17 @@ inline uint32_t import_dynamic_global_properties( ? v["round_anchor_time"].as() : fc::time_point_sec(); obj.round_anchor_round = v.get_object().contains("round_anchor_round") ? v["round_anchor_round"].as() : 0; + // PM one-time seed flags. Export is reflection-based and carries them; + // without these lines a restored node re-seeds on its first block and its + // own later snapshots disagree with the network. Absent = not seeded. + obj.pm_frozen_counters_seeded = v.get_object().contains("pm_frozen_counters_seeded") + && v["pm_frozen_counters_seeded"].as_bool(); + obj.pm_frozen_counters_reseeded_v1 = v.get_object().contains("pm_frozen_counters_reseeded_v1") + && v["pm_frozen_counters_reseeded_v1"].as_bool(); + obj.pm_active_markets_seeded = v.get_object().contains("pm_active_markets_seeded") + && v["pm_active_markets_seeded"].as_bool(); + obj.pm_oracle_gauges_seeded = v.get_object().contains("pm_oracle_gauges_seeded") + && v["pm_oracle_gauges_seeded"].as_bool(); }); return 1; } From 01e1fe07b1d86dc158f1cfa78245c8d835191d69 Mon Sep 17 00:00:00 2001 From: Vladimir Babin Date: Mon, 26 Oct 2026 18:17:21 +0800 Subject: [PATCH 2/2] snapshot: treat null PM seed flags as unset; docs: note scheduled-set tally in HF16 readiness check --- @l10n/ru/docs/consensus/hf16.md | 1 + docs/consensus/hf16.md | 1 + plugins/snapshot/plugin.cpp | 10 +++++----- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/@l10n/ru/docs/consensus/hf16.md b/@l10n/ru/docs/consensus/hf16.md index e94d0cb073..2c2053543b 100644 --- a/@l10n/ru/docs/consensus/hf16.md +++ b/@l10n/ru/docs/consensus/hf16.md @@ -17,6 +17,7 @@ HF16 назначен на **31 октября 2026, 00:00:00 UTC** (`1793404800 - `get_next_scheduled_hardfork` возвращает `hf_version` 4.2.0 и `live_time` 2026-10-31T00:00:00, когда голосование набрало порог. До этого поле повторяет текущую версию. - В `get_validators_by_vote` посчитайте записи с `hardfork_version_vote` 4.2.0 и `hardfork_time_vote` 2026-10-31T00:00:00. `running_version` показывает бинарник, с которым валидатор последний раз произвёл блок. Цель: не меньше 17 из 21 активных. +- Подсчёт идёт по валидаторам *расписания* (один на слот) и пропускает аварийного валидатора `committee`. `get_validators_by_vote ["", 21]` совпадает с этим набором, только пока расписание — это топ-21 по голосам; чтобы посчитать ровно то, что видит подсчёт, возьмите имена из `validator_api.get_active_validators`, уберите `committee` и проверьте каждого через `validator_api.get_validator_by_account`. ## Слоты, QC, TC и финальность diff --git a/docs/consensus/hf16.md b/docs/consensus/hf16.md index b7dd8b3cd9..e2405ab142 100644 --- a/docs/consensus/hf16.md +++ b/docs/consensus/hf16.md @@ -17,6 +17,7 @@ Activation needs `CHAIN_HARDFORK_REQUIRED_VALIDATORS` = 17 of the 21 scheduled v - `get_next_scheduled_hardfork` returns `hf_version` 4.2.0 and `live_time` 2026-10-31T00:00:00 once the vote has locked in. Until then it mirrors the current version. - In `get_validators_by_vote`, count entries with `hardfork_version_vote` 4.2.0 and `hardfork_time_vote` 2026-10-31T00:00:00. `running_version` shows the binary each validator last produced with. Target: at least 17 of the active 21. +- The tally counts the *scheduled* validators (one per slot) and skips the emergency committee validator. `get_validators_by_vote ["", 21]` matches that set only while the schedule is the top 21 by vote; to count exactly what the tally sees, take the names from `validator_api.get_active_validators`, drop `committee`, and look each one up with `validator_api.get_validator_by_account`. ## Slots, QC, TC and finality diff --git a/plugins/snapshot/plugin.cpp b/plugins/snapshot/plugin.cpp index 7de2f4fdea..6bb5c1d7e3 100644 --- a/plugins/snapshot/plugin.cpp +++ b/plugins/snapshot/plugin.cpp @@ -231,15 +231,15 @@ inline uint32_t import_dynamic_global_properties( ? v["round_anchor_round"].as() : 0; // PM one-time seed flags. Export is reflection-based and carries them; // without these lines a restored node re-seeds on its first block and its - // own later snapshots disagree with the network. Absent = not seeded. + // own later snapshots disagree with the network. Absent or null = not seeded. obj.pm_frozen_counters_seeded = v.get_object().contains("pm_frozen_counters_seeded") - && v["pm_frozen_counters_seeded"].as_bool(); + && !v["pm_frozen_counters_seeded"].is_null() && v["pm_frozen_counters_seeded"].as_bool(); obj.pm_frozen_counters_reseeded_v1 = v.get_object().contains("pm_frozen_counters_reseeded_v1") - && v["pm_frozen_counters_reseeded_v1"].as_bool(); + && !v["pm_frozen_counters_reseeded_v1"].is_null() && v["pm_frozen_counters_reseeded_v1"].as_bool(); obj.pm_active_markets_seeded = v.get_object().contains("pm_active_markets_seeded") - && v["pm_active_markets_seeded"].as_bool(); + && !v["pm_active_markets_seeded"].is_null() && v["pm_active_markets_seeded"].as_bool(); obj.pm_oracle_gauges_seeded = v.get_object().contains("pm_oracle_gauges_seeded") - && v["pm_oracle_gauges_seeded"].as_bool(); + && !v["pm_oracle_gauges_seeded"].is_null() && v["pm_oracle_gauges_seeded"].as_bool(); }); return 1; }