Skip to content

fix(consensus): seat genesis validators in AuthorityManager so a fresh chain bootstraps DPoS#827

Merged
github-actions[bot] merged 1 commit into
mainfrom
fix/genesis-validators-seed-authority
Jun 21, 2026
Merged

fix(consensus): seat genesis validators in AuthorityManager so a fresh chain bootstraps DPoS#827
github-actions[bot] merged 1 commit into
mainfrom
fix/genesis-validators-seed-authority

Conversation

@satyakwok

@satyakwok satyakwok commented Jun 21, 2026

Copy link
Copy Markdown
Member

Problem

A fresh genesis-only chain boots with an empty authority set and never produces a block.

Blockchain::initialize_genesis credited the premine balances and seated block 0 but never seated the [[genesis.validators]] anywhere. At the Voyager DPoS fork, activate_voyager migrates the AuthorityManager validator set into the stake registry — with an empty AuthorityManager it migrates nothing, so the DPoS active_set is empty and consensus hits:

BFT activation blocked: active_set is empty — no validators registered.
This indicates a separate bug in DPoS migration; check stake_registry.

The chain then sits at height 0 forever. (Found while bootstrapping a fresh testnet from genesis — the existing testnet/mainnet were bootstrapped through the Pioneer-era admin-add path, which masked this.)

Fix

Seat the [[genesis.validators]] in the AuthorityManager during initialize_genesis (via add_validator_unchecked — genesis has no admin signature to authorise the add). activate_voyager then has a set to migrate into the stake registry at the fork, so active_set is non-empty and consensus produces blocks.

Why this is consensus-safe

  • AuthorityManager is not committed to the trie / state_root (only AccountDB + stake-registry-derived keys are), so the genesis block hash is unchanged.
  • The stake_registry is still left empty at genesis — it's populated at the Voyager fork height, consistently across nodes — so the genesis state-root identity with pre-Genesis-TOML chains is preserved.
  • Only runs on sentrix init (a fresh data dir). Running nodes restore authority from the persisted state blob (it's a serialized field, not rebuilt from genesis), so existing chains are unaffected.

Verification

  • New regression test (crates/sentrix-core/tests/genesis_validator_bootstrap.rs): asserts the genesis validators land in the AuthorityManager at init, the stake registry stays empty pre-fork, and activate_voyager migrates all of them into the stake registry's active_set.
  • End-to-end: a fresh 3-validator testnet now boots from genesis, produces blocks (0 → 26 in ~30s), and all three converge on identical block hashes.

Summary by CodeRabbit

  • Documentation

    • Clarified how genesis validator authority seating works independently of staking registry updates, including the migration timing to the staking registry during activation.
    • Updated wording to better separate authority setup, pre-activation empty staking state, and preservation of state-root identity.
  • New Features

    • Added an explicit step to seat genesis validators into the authority set.
  • Tests

    • Added a regression test covering authority initialization, pre-activation staking state, and post-activation staking registry migration.
  • Chores

    • Updated the init command to seat genesis validators during blockchain initialization.

@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dd2cd608-ceba-4304-a64e-8cf49b6939a9

📥 Commits

Reviewing files that changed from the base of the PR and between d66281d and 611c945.

📒 Files selected for processing (3)
  • bin/sentrix/src/commands/init.rs
  • crates/sentrix-core/src/blockchain.rs
  • crates/sentrix-core/tests/genesis_validator_bootstrap.rs

📝 Walkthrough

Walkthrough

A new public method seat_genesis_validators is added to Blockchain to register genesis validators into AuthorityManager by iterating the genesis validators and calling add_validator_unchecked for each with a deterministic display name of genesis-{address}. The initialize_genesis doc comment is updated to clarify that validator seating occurs outside the constructor, AuthorityManager holds validators without state-root commitment, and the staking registry remains empty until activate_voyager is invoked. The CLI init command is modified to call seat_genesis_validators(&genesis) immediately after creating the blockchain. A regression test verifies that genesis validators populate AuthorityManager after seating, the stake registry is empty before the fork, and all validators migrate into the stake registry's active set after activate_voyager.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description comprehensively covers the problem statement, solution, safety rationale, and verification approach, but does not follow the repository's required PR template structure with explicit sections and checkboxes. Restructure the description to match the required template with sections for Summary, Scope (with checkboxes), Checks, Linked issue, and Deploy impact to ensure consistency with repository standards.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: seating genesis validators in AuthorityManager to enable fresh chain bootstrapping with DPoS consensus.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/genesis-validators-seed-authority

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/sentrix-core/tests/genesis_validator_bootstrap.rs`:
- Around line 41-62: The test assertions only verify the count of validators
rather than their exact identities, which would allow regressions where
incorrect validator addresses are seated or migrated. After the initial
assertion on bc.authority.active_validators().len(), add an additional assertion
that compares the actual validator addresses from
bc.authority.active_validators() against the expected validator addresses
declared in GENESIS_TOML. Similarly, after asserting
bc.stake_registry.active_set.len() equals 3, add an assertion that compares the
actual validator addresses in bc.stake_registry.active_set against the same
expected addresses from GENESIS_TOML to ensure the exact validator set was
migrated, not just any three addresses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ec493043-9486-430c-b781-579b10005f18

📥 Commits

Reviewing files that changed from the base of the PR and between ed728a4 and d66281d.

📒 Files selected for processing (2)
  • crates/sentrix-core/src/blockchain.rs
  • crates/sentrix-core/tests/genesis_validator_bootstrap.rs

Comment thread crates/sentrix-core/tests/genesis_validator_bootstrap.rs Outdated
github-actions Bot pushed a commit that referenced this pull request Jun 21, 2026
…ng) (#828)

Scheduled + manual-dispatch workflow that boots a fresh 3-validator testnet
from genesis, produces blocks, and asserts the validators converge on the same
block hash — covering real BFT + libp2p + block production, which the in-process
cargo tests can't. Not a PR gate (schedule/dispatch only), so a flaky network
run never blocks a merge.

scripts/ci-testnet-convergence.sh is self-contained (generates keystores +
genesis, inits + starts N nodes on isolated loopback ports, polls for liveness,
then checks block-hash agreement). Depends on #827 to bootstrap DPoS from
genesis — merge that first.
… bootstraps DPoS

A fresh genesis-only chain booted with an empty authority set and never produced
a block. initialize_genesis credited the premine and seated block 0 but nothing
seated the [[genesis.validators]]. At the Voyager DPoS fork, activate_voyager
migrates the AuthorityManager set into the stake registry; with an empty set it
migrated nothing, leaving active_set empty, so consensus hit "BFT activation
blocked: active_set is empty" and sat at height 0. (Found bootstrapping a fresh
testnet from genesis; the live nets were bootstrapped through the Pioneer-era
admin-add path, which masked it.)

sentrix init now seats the genesis validators via a new
Blockchain::seat_genesis_validators, after construction. It is kept out of the
bare Blockchain::new / new_with_genesis constructor on purpose so that path stays
a clean slate: many tests build a chain and add a single proposer of their own,
and auto-seating there breaks them with NotYourTurn. AuthorityManager is not
committed to the trie/state_root, so seating does not change the genesis hash,
and only init runs it; running nodes restore the authority set from the persisted
state blob, so existing chains are unaffected.

Verified: a fresh 3-validator testnet boots from genesis, produces blocks
(0 to 26), and all three converge on identical block hashes. Regression test
asserts the genesis validators become the exact authority set and that
activate_voyager migrates that exact set into the stake registry, and asserts
the bare constructor stays validator-free.
@satyakwok satyakwok disabled auto-merge June 21, 2026 14:34
@satyakwok satyakwok force-pushed the fix/genesis-validators-seed-authority branch from 6ff69b9 to 611c945 Compare June 21, 2026 14:36
@github-actions github-actions Bot enabled auto-merge (squash) June 21, 2026 14:36
@github-actions github-actions Bot merged commit f953263 into main Jun 21, 2026
20 checks passed
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.

1 participant