mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
* 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>
128 lines
6.2 KiB
Go
128 lines
6.2 KiB
Go
package consensus
|
|
|
|
import (
|
|
"source.quilibrium.com/quilibrium/monorepo/consensus/models"
|
|
"source.quilibrium.com/quilibrium/monorepo/lifecycle"
|
|
)
|
|
|
|
// TimeoutAggregator verifies and aggregates timeout states to build timeout
|
|
// certificates [TCs]. When enough timeout states are collected, it builds a TC
|
|
// and sends it to the EventLoop TimeoutAggregator also detects protocol
|
|
// violation, including invalid timeouts, double timeout, etc and notifies a
|
|
// HotStuff consumer for slashing.
|
|
type TimeoutAggregator[VoteT models.Unique] interface {
|
|
lifecycle.Component
|
|
|
|
// AddTimeout verifies and aggregates a timeout state.
|
|
// This method can be called concurrently, timeouts will be queued and
|
|
// processed asynchronously.
|
|
AddTimeout(timeoutState *models.TimeoutState[VoteT])
|
|
|
|
// PruneUpToRank deletes all `TimeoutCollector`s _below_ to the given rank, as
|
|
// well as related indices. We only retain and process `TimeoutCollector`s,
|
|
// whose rank is equal or larger than `lowestRetainedRank`. If
|
|
// `lowestRetainedRank` is smaller than the previous value, the previous value
|
|
// is kept and the method call is a NoOp. This value should be set to the
|
|
// latest active rank maintained by `Pacemaker`.
|
|
PruneUpToRank(lowestRetainedRank uint64)
|
|
}
|
|
|
|
// TimeoutCollector collects all timeout states for a specified rank. On the
|
|
// happy path, it generates a TimeoutCertificate when enough timeouts have been
|
|
// collected. The TimeoutCollector is a higher-level structure that orchestrates
|
|
// deduplication, caching and processing of timeouts, delegating those tasks to
|
|
// underlying modules (such as TimeoutProcessor). Implementations of
|
|
// TimeoutCollector must be concurrency safe.
|
|
type TimeoutCollector[VoteT models.Unique] interface {
|
|
// AddTimeout adds a Timeout State to the collector. When TSs from
|
|
// strictly more than 1/3 of consensus participants (measured by weight) were
|
|
// collected, the callback for partial TC will be triggered. After collecting
|
|
// TSs from a supermajority, a TC will be created and passed to the EventLoop.
|
|
// Expected error returns during normal operations:
|
|
// * timeoutcollector.ErrTimeoutForIncompatibleRank - submitted timeout for
|
|
// incompatible rank
|
|
// All other exceptions are symptoms of potential state corruption.
|
|
AddTimeout(timeoutState *models.TimeoutState[VoteT]) error
|
|
|
|
// Rank returns the rank that this instance is collecting timeouts for.
|
|
// This method is useful when adding the newly created timeout collector to
|
|
// timeout collectors map.
|
|
Rank() uint64
|
|
}
|
|
|
|
// TimeoutProcessor ingests Timeout States for a particular rank. It
|
|
// implements the algorithms for validating TSs, orchestrates their low-level
|
|
// aggregation and emits `OnPartialTimeoutCertificateCreated` and `OnTimeoutCertificateConstructedFromTimeouts`
|
|
// notifications. TimeoutProcessor cannot deduplicate TSs (this should be
|
|
// handled by the higher-level TimeoutCollector) and errors instead. Depending
|
|
// on their implementation, a TimeoutProcessor might drop timeouts or attempt to
|
|
// construct a TC.
|
|
type TimeoutProcessor[VoteT models.Unique] interface {
|
|
// Process performs processing of single timeout state. This function is safe
|
|
// to call from multiple goroutines. Expected error returns during normal
|
|
// operations:
|
|
// * timeoutcollector.ErrTimeoutForIncompatibleRank - submitted timeout for
|
|
// incompatible rank
|
|
// * models.InvalidTimeoutError - submitted invalid timeout(invalid structure
|
|
// or invalid signature)
|
|
// * models.DuplicatedSignerError if a timeout from the same signer was
|
|
// previously already added. It does _not necessarily_ imply that the
|
|
// timeout is invalid or the sender is equivocating.
|
|
// All other errors should be treated as exceptions.
|
|
Process(timeout *models.TimeoutState[VoteT]) error
|
|
}
|
|
|
|
// TimeoutCollectorFactory performs creation of TimeoutCollector for a given
|
|
// rank
|
|
type TimeoutCollectorFactory[VoteT models.Unique] interface {
|
|
// Create is a factory method to generate a TimeoutCollector for a given rank
|
|
// Expected error returns during normal operations:
|
|
// * models.ErrRankUnknown no rank containing the given rank is known
|
|
// All other errors should be treated as exceptions.
|
|
Create(rank uint64) (TimeoutCollector[VoteT], error)
|
|
}
|
|
|
|
// TimeoutProcessorFactory performs creation of TimeoutProcessor for a given
|
|
// rank
|
|
type TimeoutProcessorFactory[VoteT models.Unique] interface {
|
|
// Create is a factory method to generate a TimeoutProcessor for a given rank
|
|
// Expected error returns during normal operations:
|
|
// * models.ErrRankUnknown no rank containing the given rank is known
|
|
// All other errors should be treated as exceptions.
|
|
Create(rank uint64) (TimeoutProcessor[VoteT], error)
|
|
}
|
|
|
|
// TimeoutCollectors encapsulates the functionality to generate, store and prune
|
|
// `TimeoutCollector` instances (one per rank). Its main purpose is to provide a
|
|
// higher-level API to `TimeoutAggregator` for managing and interacting with the
|
|
// rank-specific `TimeoutCollector` instances. Implementations are concurrency
|
|
// safe.
|
|
type TimeoutCollectors[VoteT models.Unique] interface {
|
|
// GetOrCreateCollector retrieves the TimeoutCollector for the specified
|
|
// rank or creates one if none exists. When creating a timeout collector,
|
|
// the rank is used to query the consensus committee for the respective
|
|
// Rank the rank belongs to.
|
|
// It returns:
|
|
// - (collector, true, nil) if no collector can be found by the rank, and a
|
|
// new collector was created.
|
|
// - (collector, false, nil) if the collector can be found by the rank.
|
|
// - (nil, false, error) if running into any exception creating the timeout
|
|
// collector.
|
|
// Expected error returns during normal operations:
|
|
// * models.BelowPrunedThresholdError if rank is below the pruning threshold
|
|
// * models.ErrRankUnknown if rank is not yet pruned but no rank containing
|
|
// the given rank is known
|
|
GetOrCreateCollector(rank uint64) (
|
|
collector TimeoutCollector[VoteT],
|
|
created bool,
|
|
err error,
|
|
)
|
|
|
|
// PruneUpToRank prunes the timeout collectors with ranks _below_ the given
|
|
// value, i.e. we only retain and process timeout collectors, whose ranks are
|
|
// equal or larger than `lowestRetainedRank`. If `lowestRetainedRank` is
|
|
// smaller than the previous value, the previous value is kept and the method
|
|
// call is a NoOp.
|
|
PruneUpToRank(lowestRetainedRank uint64)
|
|
}
|