Skip to content

fix(consensus)!: validate fresh block proposer before prevoting - #1527

Open
lklimek wants to merge 3 commits into
v1.8-devfrom
fix/check-proposer-protx
Open

lklimek wants to merge 3 commits into
v1.8-devfrom
fix/check-proposer-protx

Conversation

@lklimek

@lklimek lklimek commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

TL;DR: Reject new block proposals that name a different validator as their author, preventing misuse of that identity to influence subsequent proposer selection.

Issue being fixed or feature implemented

A scheduled proposer can sign a block naming another validator. Header validation checks membership but does not bind the named validator to the scheduled proposer.

User story

As a validator operator, I want nodes to verify who authored a new block so a proposer cannot use another validator's identity to retain proposal control.

Scenario

A validator takes its scheduled turn and submits a new block. Currently, peers accept a header naming its predecessor, which can cause the same validator to be selected again. With this change, peers refuse to vote for that new proposal.

What was done?

Detailed discussion

  • For fresh proposals (POLRound == -1), compare ProposerProTxHash with GetProposer(height, round) in the pre-prevote checks. A mismatch produces a nil prevote before ProcessProposal, including its cache path.
  • Preserve original headers for reproposals and retain the existing prior-round majority checks before voting.
  • Add seven regression scenarios and correct existing test fixtures to use the proposing validator's identity.

How Has This Been Tested?

  • Confirmed the regression fails before the fix: wrong-author proposals reach ProcessProposal.
  • Seven scenarios cover fresh proposals in rounds 0 and 1, wrong authors, predecessor capture, valid reproposals, missing POL votes, and POL votes for another block.
  • go test -race -tags=deadlock -p 1 ./internal/consensus -count=1 passed (92.711s).
  • Scoped golangci-lint v2.13 run with --new-from-rev=HEAD passed before commit (0 issues); gofmt and git diff --check passed.
  • Validation used Go 1.27.1 with CGO and the native BLS library. CI has not yet been verified.

Breaking Changes

Tightens consensus voting rules immediately, without an activation height or version gate. Updated validators reject fresh proposals with a mismatched author that older validators may accept. No wire-format or public API changes; historical commit validation and block sync are unchanged.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation

No separate documentation changes are included; the consensus rule change is described above and in the validation comment.

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Co-authored by Claudius the Magnificent AI Agent

PR Hygiene · 86887be

  • Bots — thepastaclaw ✓
  • Self-review — posted; again after any push
  • Build green
  • Approvals
    • github (.github/workflows/claude-code-review.yml) — ktechmidas or shumkov
    • files with no dedicated owner — you own it

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

Reject fresh proposals whose header names a validator other than the
scheduled round proposer before ProcessProposal. Preserve reproposals
with their original header and existing POL vote checks.

Cover predecessor capture, later rounds and valid or invalid POLs;
correct existing fixtures to use the proposing validator's identity.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

<sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub>
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: dashpay/tenderdash/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 203cfbea-631f-438a-9c15-a962439db306

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

@thepastaclaw

thepastaclaw commented Oct 1, 2026 •

Copy link
Copy Markdown

✅ Final review complete — no blockers (commit 86887be) · triage: critical

@lklimek lklimek added the claudius-review Trigger Claudius AI code review on this PR label Oct 1, 2026
@lklimek
lklimek marked this pull request as ready for review October 1, 2026 14:13
@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 1, 2026
Co-Authored-By: Codex <noreply@openai.com>

@claudbot claudbot 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.

Approved, grudgingly impressed: the proposer check is wired correctly, fails safe, and three independent passes couldn't find a single thing worth blocking on — just a rolling-upgrade caveat worth a sentence in the description, a couple of Go nits (sentinel errors, DRY), a test-coverage gap or two, and a CI-workflow stowaway that probably wanted its own PR.

0 finding(s) posted: 0 inline, 0 in this body.

🤖 Co-authored by Claudius the Magnificent AI Agent
📊 View full HTML review report

@claudbot claudbot Bot removed the claudius-review Trigger Claudius AI code review on this PR label Oct 1, 2026

@thepastaclaw thepastaclaw 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.

Final validation — Phase 1 + Phase 2

The consensus change correctly validates the scheduled proposer for fresh proposals before processing or voting, while preserving the existing reproposal/POL behavior. One non-blocking consistency issue remains: the new proposer-mismatch rejection does not use the sentinel-error pattern used by the other prevote validation failures; the supplied CI checks are green, with only PR Hygiene still pending.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: tenderdash-consensus-security); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: critical by gpt-6.1-sol (effort low) — The diff changes consensus proposer validation in internal/consensus/state_data.go and related prevoter logic, directly altering a peer-facing consensus rule despite its small size.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 84% left, 5h 6% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Single stage: Phase 1 and Phase 2 reviewed this head side by side, with no blocker gate between them (triage tier)
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort xhigh); agent phase2-reviewer, gpt-6.1-sol — tenderdash-consensus-security (completed, effort xhigh); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `internal/consensus/state_data.go`:
- [SUGGESTION] internal/consensus/state_data.go:695-697: Use a sentinel for fresh-proposal proposer mismatch
  The new proposer-mismatch branch returns an anonymous formatted error, while the other prevote validation failures use package sentinel errors. This prevents callers and tests from matching the rejection with errors.Is and makes the new consensus-critical failure reason less consistent and observable than its neighboring checks. Define an errPrevoteInvalidProposer sentinel and wrap it in this message; the nil-prevote behavior remains unchanged.

Comment on lines +695 to +697
if !bytes.Equal(s.ProposalBlock.ProposerProTxHash, proposer.ProTxHash) {
return fmt.Errorf("proposal-block proposer %X does not match round proposer %X",
s.ProposalBlock.ProposerProTxHash, proposer.ProTxHash)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Use a sentinel for fresh-proposal proposer mismatch

The new proposer-mismatch branch returns an anonymous formatted error, while the other prevote validation failures use package sentinel errors. This prevents callers and tests from matching the rejection with errors.Is and makes the new consensus-critical failure reason less consistent and observable than its neighboring checks. Define an errPrevoteInvalidProposer sentinel and wrap it in this message; the nil-prevote behavior remains unchanged.

source: muse-spark-1.3-contributor (phase1-reviewer: general)

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Your move: thepastaclaw left review threads unresolved; resolve them.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed and removed waiting-bots Waiting for the review bots to report on this head labels Oct 1, 2026

@lklimek lklimek left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

/self-reviewed

@lklimek
lklimek enabled auto-merge (squash) October 5, 2026 11:50
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

Ready for review — github: ktechmidas or shumkov.
Full checklist in the description.

@github-actions github-actions Bot added ready-for-human PR Hygiene: bots done, author self-reviewed, awaiting human review and removed waiting-self-review Waiting for the author to post /self-reviewed labels Oct 5, 2026
@github-actions
github-actions Bot requested review from ktechmidas and shumkov October 5, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human PR Hygiene: bots done, author self-reviewed, awaiting human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants