ceremonyclient/consensus/consensus_safety_rules.go
Cassandra Heart c797d482f9
v2.1.0.5 (#457)
* wip: conversion of hotstuff from flow into Q-oriented model

* bulk of tests

* remaining non-integration tests

* add integration test, adjust log interface, small tweaks

* further adjustments, restore full pacemaker shape

* add component lifecycle management+supervisor

* further refinements

* resolve timeout hanging

* mostly finalized state for consensus

* bulk of engine swap out

* lifecycle-ify most types

* wiring nearly complete, missing needed hooks for proposals

* plugged in, vetting message validation paths

* global consensus, plugged in and verified

* app shard now wired in too

* do not decode empty keys.yml (#456)

* remove obsolete engine.maxFrames config parameter (#454)

* default to Info log level unless debug is enabled (#453)

* respect config's  "logging" section params, remove obsolete single-file logging (#452)

* Trivial code cleanup aiming to reduce Go compiler warnings (#451)

* simplify range traversal

* simplify channel read for single select case

* delete rand.Seed() deprecated in Go 1.20 and no-op as of Go 1.24

* simplify range traversal

* simplify channel read for single select case

* remove redundant type from array

* simplify range traversal

* simplify channel read for single select case

* RC slate

* finalize 2.1.0.5

* Update comments in StrictMonotonicCounter

Fix comment formatting and clarify description.

---------

Co-authored-by: Black Swan <3999712+blacks1ne@users.noreply.github.com>
2025-11-11 05:00:17 -06:00

74 lines
3.7 KiB
Go

package consensus
import "source.quilibrium.com/quilibrium/monorepo/consensus/models"
// SafetyRules enforces all consensus rules that guarantee safety. It produces
// votes for the given states or TimeoutState for the given ranks, only if all
// safety rules are satisfied. In particular, SafetyRules guarantees a
// foundational security theorem for HotStuff, which we utilize also outside of
// consensus (e.g. queuing pending states for execution, verification, sealing
// etc):
//
// THEOREM: For each rank, there can be at most 1 certified state.
//
// Implementations are generally *not* concurrency safe.
type SafetyRules[StateT models.Unique, VoteT models.Unique] interface {
// ProduceVote takes a state proposal and current rank, and decides whether to
// vote for the state. Voting is deterministic, i.e. voting for same proposal
// will always result in the same vote.
// Returns:
// * (vote, nil): On the _first_ state for the current rank that is safe to
// vote for. Subsequently, voter does _not_ vote for any _other_ state with
// the same (or lower) rank. SafetyRules internally caches and persists its
// latest vote. As long as the SafetyRules' internal state remains
// unchanged, ProduceVote will return its cached for identical inputs.
// * (nil, model.NoVoteError): If the safety module decides that it is not
// safe to vote for the given state. This is a sentinel error and
// _expected_ during normal operation.
// All other errors are unexpected and potential symptoms of uncovered edge
// cases or corrupted internal state (fatal).
ProduceVote(
proposal *models.SignedProposal[StateT, VoteT],
curRank uint64,
) (*VoteT, error)
// ProduceTimeout takes current rank, highest locally known QC and TC
// (optional, must be nil if and only if QC is for previous rank) and decides
// whether to produce timeout for current rank.
// Returns:
// * (timeout, nil): It is safe to timeout for current rank using newestQC
// and lastRankTC.
// * (nil, model.NoTimeoutError): If replica is not part of the authorized
// consensus committee (anymore) and therefore is not authorized to produce
// a valid timeout state. This sentinel error is _expected_ during normal
// operation, e.g. during the grace-period after Rank switchover or after
// the replica self-ejected.
// All other errors are unexpected and potential symptoms of uncovered edge
// cases or corrupted internal state (fatal).
ProduceTimeout(
curRank uint64,
newestQC models.QuorumCertificate,
lastRankTC models.TimeoutCertificate,
) (*models.TimeoutState[VoteT], error)
// SignOwnProposal takes an unsigned state proposal and produces a vote for
// it. Vote is a cryptographic commitment to the proposal. By adding the vote
// to an unsigned proposal, the caller constructs a signed state proposal.
// This method has to be used only by the leader, which must be the proposer
// of the state (or an exception is returned).
// Implementors must guarantee that:
// - vote on the proposal satisfies safety rules
// - maximum one proposal is signed per rank
// Returns:
// * (vote, nil): the passed unsigned proposal is a valid one, and it's safe
// to make a proposal. Subsequently, leader does _not_ produce any _other_
// proposal with the same (or lower) rank.
// * (nil, model.NoVoteError): according to HotStuff's Safety Rules, it is
// not safe to sign the given proposal. This could happen because we have
// already proposed or timed out for the given rank. This is a sentinel
// error and _expected_ during normal operation.
// All other errors are unexpected and potential symptoms of uncovered edge
// cases or corrupted internal state (fatal).
SignOwnProposal(unsignedProposal *models.Proposal[StateT]) (*VoteT, error)
}