Skip to content

p2p: scale block-count thresholds by the live slot length for HF16 - #183

Merged
On1x merged 3 commits into
masterfrom
fix/hf16-p2p-thresholds
Oct 25, 2026
Merged

On1x merged 3 commits into
masterfrom
fix/hf16-p2p-thresholds

Conversation

@chiliec

@chiliec chiliec commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

What

HF16 switches slots from 3 s to 1 s. Three P2P thresholds are block counts written for 3 s slots and were not rescaled:

Constant Blocks Before HF16 After HF16 (unpatched)
FORWARD_FALLBEHIND_THRESHOLD 2 6 s 2 s
FORK_RESOLUTION_BLOCK_THRESHOLD 42 126 s 42 s
WEDGE_BEHIND_THRESHOLD 200 600 s 200 s

A node 3 blocks behind a peer enters SYNC mode and stops producing through is_syncing(). At 1 s slots that is a 3 s lag.

Change

  • dlt_p2p_delegate::block_interval() (default CHAIN_BLOCK_INTERVAL), implemented in p2p_plugin.cpp with a guarded chain read and an atomic last-known interval. Temporary lock/resize/recovery failures retain the cache and retry on the next call, without unwinding P2P.
  • dlt_p2p_node::slot_scale() = CHAIN_BLOCK_INTERVAL / interval (1 before HF16, 3 after). The three thresholds are multiplied at their use sites. Constants and log output unchanged otherwise.
  • is_wedged() takes behind_threshold as a defaulted parameter; test_wedge_predicate.cpp gains the scaled boundary.
  • Docs: snapshot.md (en/ru/zh-CN) notes that block-count options cover one third of the time after HF16 and that dlt-block-log-max-blocks = 100000 serves peer sync for ~28 h (300000 keeps 3.5 days). hf16.md (en/ru) gets the operator paragraph.
  • validator.cpp:344 stale comment "21 blocks = 63s" fixed. Default fork-collision-timeout-blocks stays 21 (one round).

Verification

  • dlt_p2p_node.cpp and p2p_plugin.cpp syntax-checked with the recorded compile flags (arm64 host, no link).
  • test_wedge_predicate runs in CI (consensus_sim).

Not changed

  • dlt-block-log-max-blocks default stays 100000; raising it triples disk use for existing operators. Documented instead.
  • Snapshot plugin does not dump the four PM seed flags in dgp; re-seed after restore is idempotent and display-only.

Maintainer acceptance follow-up

Merged current master (including #182) into this branch. Removed the unguarded hardfork-state read from the delegate. Added tests/p2p/test_slot_interval.py to CI: it compiles the actual delegate/scale/predicate methods against a guarded DB fixture and verifies 3→1→3, initial/read failure fallback, invalid interval and all three threshold boundaries. Independently repeated this and vote-ingress, signing-cache, snapshot-restore, production-safety and archive-merge regressions inside Docker; all passed. Full native CI on the updated head is required before merge.

chiliec and others added 3 commits October 25, 2026 13:28
FORWARD_FALLBEHIND_THRESHOLD (2), FORK_RESOLUTION_BLOCK_THRESHOLD (42) and
WEDGE_BEHIND_THRESHOLD (200) were written for 3 s slots. After HF16 the same
block counts cover one third of the time: a node 3 blocks (3 s) behind a peer
dropped into SYNC and stopped producing via is_syncing().

The delegate now exposes database::block_interval(); dlt_p2p_node multiplies
the three thresholds by CHAIN_BLOCK_INTERVAL / interval (1 before HF16, 3
after). is_wedged() takes the threshold as a defaulted parameter so the
truth-table test keeps its symbolic boundaries and gains the scaled case.

Docs: snapshot.md notes that block-count options cover 1/3 of the time after
HF16 and that dlt-block-log-max-blocks 100000 serves peer sync for ~28 h
(300000 keeps 3.5 days); hf16.md gets the operator paragraph. Stale "21 blocks
= 63s" comment in validator.cpp fixed.
@web3blind

Copy link
Copy Markdown

Compatibility follow-up with #182, rechecked at c36d6429.

The updated branch includes merged #182. The threshold scaling complements the finality, production and vote-cache fixes; I found no conflicting change in the reviewed paths.

The previously noted unguarded hardfork-state read is addressed: block_interval() now reads under with_weak_read_lock(), retains an atomic last-known interval and avoids propagating temporary read failures into P2P. The new test_slot_interval.py also exercises the actual extracted delegate/scale methods for 3 -> 1 -> 3, unavailable-DB fallback and the watchdog boundary. I ran that test on this head; it passed.

One remaining test improvement: the SYNC/fork boundary assertions in the fixture embed 2 and 42 rather than executing the production handlers. Consider an integration regression that drives those handlers (and the watchdog call site) with a switchable delegate, so removing slot_scale() from a real call site cannot leave the test green.

This is a scoped source/fixture recheck, not a concurrent remap or whole-node recovery stress test. Please use the complete native CI results for the updated, #182-inclusive head as the merge gate.

@On1x On1x left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the complete change against master, including PR #182. The live-slot scaling preserves the intended wall-clock P2P thresholds across HF16. The delegate now reads the interval under the database read guard and retains the last valid atomic cached value during transient database unavailability. Added regression coverage exercises the actual delegate and threshold methods across 3s/1s transitions, failed reads, invalid values, and boundary conditions.

Own isolated Docker regressions passed. GitHub Tests run 40170943020 and Docker run 40170942979 passed for exact head c36d642, including the full single-validator simulator, targeted two-validator suites, and PM unit tests. This review does not claim a production rollout or a full 21-validator adversarial campaign.

@On1x
On1x merged commit 918a95a into master Oct 25, 2026
6 checks passed
@chiliec

chiliec commented Oct 25, 2026

Copy link
Copy Markdown
Member Author

Pushed 607ca80 on top of c36d642, two unrelated-to-P2P HF16 items from the same audit:

  • plugins/snapshot/plugin.cpp import_dynamic_global_properties: reads the four PM seed flags (pm_frozen_counters_seeded, pm_frozen_counters_reseeded_v1, pm_active_markets_seeded, pm_oracle_gauges_seeded). Export already carried them; import dropped them, so a restored node re-ran the seeds on its first block and its later snapshots differed from the network. Absent in the file = false, same pattern as round_anchor_*.
  • docs/consensus/hf16.md + ru: "Verify readiness" section. 17 of 21 validators must vote 4.2.0 @ 1793404800 before 2026-10-31 00:00 UTC; shows get_next_scheduled_hardfork and get_validators_by_vote ["", 21] and what to count.

Snapshot TU syntax-checked locally with the recorded flags. Nothing changed in the P2P paths.

@chiliec

chiliec commented Oct 25, 2026

Copy link
Copy Markdown
Member Author

Note: 607ca80 landed on this branch minutes after the merge and is not part of #183. It is re-based on master as #184; this branch is reset to the merged tip c36d642.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants