Documentation
¶
Overview ¶
Package hotstuff2 implements the HotStuff-2 consensus algorithm.
HotStuff-2 is a two-phase Byzantine Fault Tolerant (BFT) consensus protocol that achieves optimistic responsiveness and linear view-change complexity.
This implementation follows the architecture patterns from nspcc-dev/dbft for compatibility with NeoGo and uses generic types for flexibility.
Index ¶
- Constants
- Variables
- type BLSSigner
- type Block
- type Config
- type ConfigError
- type ConfigOption
- func WithCryptoScheme[H Hash](scheme string) ConfigOption[H]
- func WithExecutor[H Hash](executor Executor[H]) ConfigOption[H]
- func WithLogger[H Hash](logger *zap.Logger) ConfigOption[H]
- func WithMyIndex[H Hash](index uint16) ConfigOption[H]
- func WithNetwork[H Hash](network Network[H]) ConfigOption[H]
- func WithPacemaker[H Hash](config PacemakerConfig) ConfigOption[H]
- func WithPrivateKey[H Hash](key PrivateKey) ConfigOption[H]
- func WithStorage[H Hash](storage Storage[H]) ConfigOption[H]
- func WithTargetBlockTime[H Hash](blockTime time.Duration) ConfigOption[H]
- func WithTimer[H Hash](timer Timer) ConfigOption[H]
- func WithValidators[H Hash](validators ValidatorSet) ConfigOption[H]
- func WithVerification[H Hash](enabled bool) ConfigOption[H]
- type ConsensusMessage
- func MessageFromBytes[H Hash](data []byte, hashFromBytes func([]byte) (H, error), ...) (*ConsensusMessage[H], error)
- func NewNewViewMessage[H Hash](view uint32, validatorIndex uint16, highQC *QC[H]) *ConsensusMessage[H]
- func NewProposeMessage[H Hash](view uint32, validatorIndex uint16, block Block[H], justifyQC *QC[H]) *ConsensusMessage[H]
- func NewVoteMessage[H Hash](view uint32, validatorIndex uint16, vote *Vote[H]) *ConsensusMessage[H]
- func (m *ConsensusMessage[H]) Block() Block[H]
- func (m *ConsensusMessage[H]) Bytes() []byte
- func (m *ConsensusMessage[H]) Hash() H
- func (m *ConsensusMessage[H]) HighQC() *QC[H]
- func (m *ConsensusMessage[H]) JustifyQC() *QC[H]
- func (m *ConsensusMessage[H]) Type() MessageType
- func (m *ConsensusMessage[H]) ValidatorIndex() uint16
- func (m *ConsensusMessage[H]) View() uint32
- func (m *ConsensusMessage[H]) Vote() *Vote[H]
- type ConsensusPayload
- type ConsensusState
- type Context
- func (c *Context[H]) AddBlock(block Block[H])
- func (c *Context[H]) AddNewView(view uint32, validatorIndex uint16, highQC *QC[H]) int
- func (c *Context[H]) AddQC(qc *QC[H])
- func (c *Context[H]) AddVote(vote *Vote[H]) int
- func (c *Context[H]) CanCommit(block Block[H], qc *QC[H]) bool
- func (c *Context[H]) Commit(block Block[H])
- func (c *Context[H]) CommittedBlocks() []Block[H]
- func (c *Context[H]) GetBlock(hash H) (Block[H], bool)
- func (c *Context[H]) GetCommitted(height uint32) (Block[H], bool)
- func (c *Context[H]) GetQC(nodeHash H) (*QC[H], bool)
- func (c *Context[H]) GetVotes(view uint32, nodeHash H) []*Vote[H]
- func (c *Context[H]) HasNewViewQuorum(view uint32, quorum int) bool
- func (c *Context[H]) HasSentNewView(view uint32, validatorIndex uint16) bool
- func (c *Context[H]) HasVoted(view uint32, validatorIndex uint16) bool
- func (c *Context[H]) HighQC() *QC[H]
- func (c *Context[H]) HighestQCFromNewViews(view uint32) *QC[H]
- func (c *Context[H]) IsAncestor(ancestor H, descendant H) bool
- func (c *Context[H]) IsCommitted(height uint32) bool
- func (c *Context[H]) LastCommitTime() time.Time
- func (c *Context[H]) LockedQC() *QC[H]
- func (c *Context[H]) NewViewCount(view uint32) int
- func (c *Context[H]) PruneVotes(currentView uint32, keepViews uint32)
- func (c *Context[H]) SafeToVote(block Block[H], justifyQC *QC[H]) bool
- func (c *Context[H]) SetView(view uint32)
- func (c *Context[H]) State() ConsensusState
- func (c *Context[H]) Stats() map[string]interface{}
- func (c *Context[H]) TimeSinceLastCommit() time.Duration
- func (c *Context[H]) UpdateHighQC(qc *QC[H]) bool
- func (c *Context[H]) UpdateLockedQC(qc *QC[H]) bool
- func (c *Context[H]) View() uint32
- func (c *Context[H]) VoteCount(view uint32, nodeHash H) int
- type Executor
- type GenericValidatorSet
- func (vs *GenericValidatorSet) Contains(index uint16) bool
- func (vs *GenericValidatorSet) Count() int
- func (vs *GenericValidatorSet) F() int
- func (vs *GenericValidatorSet) GetByIndex(index uint16) (PublicKey, error)
- func (vs *GenericValidatorSet) GetLeader(view uint32) uint16
- func (vs *GenericValidatorSet) GetPublicKeys(indices []uint16) ([]PublicKey, error)
- type Hash
- type Hooks
- type HotStuff2
- type MessageCodec
- type MessageType
- type Network
- type Pacemaker
- func (pm *Pacemaker) CanAcceptProposal(lastCommitTime time.Time) bool
- func (pm *Pacemaker) Config() PacemakerConfig
- func (pm *Pacemaker) CurrentTimeout() uint64
- func (pm *Pacemaker) IncreaseTimeout()
- func (pm *Pacemaker) MinBlockTimeEnabled() bool
- func (pm *Pacemaker) OnCommit(view uint32) <-chan struct{}
- func (pm *Pacemaker) OnProgress(view uint32)
- func (pm *Pacemaker) OnTimeout(view uint32)
- func (pm *Pacemaker) ResetTimeout()
- func (pm *Pacemaker) Start(view uint32)
- func (pm *Pacemaker) Stop()
- func (pm *Pacemaker) TimeUntilCanPropose(lastCommitTime time.Time) time.Duration
- func (pm *Pacemaker) WaitForCommitDelay()
- func (pm *Pacemaker) WaitForMinBlockTime(lastCommitTime time.Time)
- type PacemakerConfig
- type PrivateKey
- type PublicKey
- type QC
- type QuorumCertificate
- type Storage
- type TestBlock
- type TestExecutor
- type TestHash
- type TestNetwork
- func (n *TestNetwork) Broadcast(payload ConsensusPayload[TestHash])
- func (n *TestNetwork) Close() error
- func (n *TestNetwork) Receive() <-chan ConsensusPayload[TestHash]
- func (n *TestNetwork) SendTo(validatorIndex uint16, payload ConsensusPayload[TestHash])
- func (n *TestNetwork) SentMessages() []ConsensusPayload[TestHash]
- type TestStorage
- func (s *TestStorage) Close() error
- func (s *TestStorage) GetBlock(hash TestHash) (Block[TestHash], error)
- func (s *TestStorage) GetHighestLockedQC() (QuorumCertificate[TestHash], error)
- func (s *TestStorage) GetLastBlock() (Block[TestHash], error)
- func (s *TestStorage) GetQC(nodeHash TestHash) (QuorumCertificate[TestHash], error)
- func (s *TestStorage) GetView() (uint32, error)
- func (s *TestStorage) PutBlock(block Block[TestHash]) error
- func (s *TestStorage) PutHighestLockedQC(qc QuorumCertificate[TestHash]) error
- func (s *TestStorage) PutQC(qc QuorumCertificate[TestHash]) error
- func (s *TestStorage) PutView(view uint32) error
- type TestValidatorSet
- func (vs *TestValidatorSet) Contains(index uint16) bool
- func (vs *TestValidatorSet) Count() int
- func (vs *TestValidatorSet) F() int
- func (vs *TestValidatorSet) GetByIndex(index uint16) (PublicKey, error)
- func (vs *TestValidatorSet) GetLeader(view uint32) uint16
- func (vs *TestValidatorSet) GetPublicKeys(indices []uint16) ([]PublicKey, error)
- type Timer
- type ValidatorSet
- type Vote
- func NewBLSVote[H Hash](view uint32, nodeHash H, validatorIndex uint16, signer BLSSigner) (*Vote[H], error)
- func NewVote[H Hash](view uint32, nodeHash H, validatorIndex uint16, privateKey PrivateKey) (*Vote[H], error)
- func VoteFromBytes[H Hash](data []byte, hashFromBytes func([]byte) (H, error)) (*Vote[H], error)
- func (v *Vote[H]) BLSDigest() []byte
- func (v *Vote[H]) Bytes() []byte
- func (v *Vote[H]) Digest() []byte
- func (v *Vote[H]) NodeHash() H
- func (v *Vote[H]) Signature() []byte
- func (v *Vote[H]) Timestamp() uint64
- func (v *Vote[H]) ValidatorIndex() uint16
- func (v *Vote[H]) Verify(publicKey PublicKey) error
- func (v *Vote[H]) View() uint32
Constants ¶
const ( // CryptoSchemeEd25519 indicates Ed25519 multi-signature (O(n) size). CryptoSchemeEd25519 = "ed25519" // CryptoSchemeBLS indicates BLS12-381 aggregate signature (O(1) size). CryptoSchemeBLS = "bls" )
const ( // VoteTimestampWindow is the acceptable time window for vote timestamps. // Votes with timestamps outside this window are rejected (replay protection). VoteTimestampWindow = 60 * 1000 // 60 seconds in milliseconds )
Variables ¶
var ( // ErrConfig indicates a configuration error that prevents startup. // These are hard errors that require fixing the configuration and restarting. // Examples: missing required fields, invalid validator index, insufficient validators. ErrConfig = errors.New("configuration error") // ErrInvalidMessage indicates a malformed or invalid message was received. // These are soft errors - the message should be dropped but consensus continues. // Examples: deserialization failure, message too short, unknown message type. ErrInvalidMessage = errors.New("invalid message") // ErrByzantine indicates potential Byzantine behavior from a peer. // Integrators may want to track these for peer scoring or slashing. // Examples: invalid signature, timestamp manipulation, duplicate votes. ErrByzantine = errors.New("byzantine behavior detected") // ErrInternal indicates an internal invariant violation. // These suggest bugs in the library or storage corruption. // Examples: QC validation failed on locally-created QC, missing expected block. ErrInternal = errors.New("internal error") )
Error classes for consensus operations. These represent categories of errors that integrators can handle uniformly. Use errors.Is() to check error class, then inspect the error message for details.
Error Classification:
- ErrConfig: Hard configuration errors - must fix and restart
- ErrInvalidMessage: Malformed or invalid messages from peers - log and ignore
- ErrByzantine: Potential Byzantine behavior detected - may warrant peer penalties
- ErrInternal: Internal invariant violations - indicates bugs or corruption
Functions ¶
This section is empty.
Types ¶
type BLSSigner ¶
type BLSSigner interface {
// SignBLS signs a message using BLS12-381.
SignBLS(message []byte) ([]byte, error)
}
BLSSigner is the interface for BLS signature creation. This is separate from PrivateKey to support BLS-specific signing.
type Block ¶
type Block[H Hash] interface { // Hash returns the unique identifier for this block. // Also referred to as "nodeHash" in the HotStuff-2 paper. Hash() H // Height returns the block height (0 for genesis). // Also referred to as block number or sequence number. Height() uint32 // PrevHash returns the hash of the parent block. // Must reference a valid block in the node tree. PrevHash() H // Payload returns the application-specific block content. // Consensus treats this as opaque bytes - interpretation is left // to the Executor implementation. // // Examples: // - Serialized transaction list // - DAG vertex references (Narwhal-style) // - Rollup batch commitment // - Empty (for empty blocks) Payload() []byte // ProposerIndex returns the validator index of the block proposer. ProposerIndex() uint16 // Timestamp returns the block timestamp (milliseconds since epoch). Timestamp() uint64 // Bytes returns the serialized form of the block. Bytes() []byte }
Block represents a proposed block in the consensus protocol. Blocks form a tree structure via parent links.
The Block interface is intentionally minimal and payload-agnostic. Consensus treats block content as opaque bytes, allowing integration with various execution models:
- Traditional transactions (serialize tx list into Payload)
- DAG-based mempools like Narwhal (payload contains vertex references)
- Rollup batches (payload contains batch commitments)
- Any other application-specific data
type Config ¶
type Config[H Hash] struct { // MyIndex is the validator index of this node. MyIndex uint16 // Validators is the set of all validators in the network. Validators ValidatorSet // PrivateKey is the private key for signing messages. PrivateKey PrivateKey // Storage provides persistent storage for blocks and consensus state. Storage Storage[H] // Network provides message broadcasting and delivery. Network Network[H] // Executor handles block execution and validation. Executor Executor[H] // Timer provides timeout management for the pacemaker. Timer Timer // Pacemaker configures the timing behavior (timeouts, block time, backoff). // If nil, DefaultPacemakerConfig() is used. Pacemaker *PacemakerConfig // Logger for structured logging. Logger *zap.Logger // CryptoScheme specifies which signature scheme to use ("ed25519" or "bls"). CryptoScheme string // EnableVerification enables runtime TLA+ model twins verification. EnableVerification bool }
Config holds the configuration for a HotStuff2 consensus instance.
func NewConfig ¶
func NewConfig[H Hash](opts ...ConfigOption[H]) (*Config[H], error)
NewConfig creates a new Config with the given options.
type ConfigError ¶
ConfigError represents a configuration validation error.
func (*ConfigError) Error ¶
func (e *ConfigError) Error() string
type ConfigOption ¶
ConfigOption is a functional option for configuring HotStuff2.
func WithCryptoScheme ¶
func WithCryptoScheme[H Hash](scheme string) ConfigOption[H]
WithCryptoScheme sets the signature scheme ("ed25519" or "bls").
func WithExecutor ¶
func WithExecutor[H Hash](executor Executor[H]) ConfigOption[H]
WithExecutor sets the block executor.
func WithLogger ¶
func WithLogger[H Hash](logger *zap.Logger) ConfigOption[H]
WithLogger sets the logger.
func WithMyIndex ¶
func WithMyIndex[H Hash](index uint16) ConfigOption[H]
WithMyIndex sets the validator index for this node.
func WithNetwork ¶
func WithNetwork[H Hash](network Network[H]) ConfigOption[H]
WithNetwork sets the network layer.
func WithPacemaker ¶
func WithPacemaker[H Hash](config PacemakerConfig) ConfigOption[H]
WithPacemaker sets the pacemaker configuration. Use this to configure target block time, timeouts, and backoff behavior.
func WithPrivateKey ¶
func WithPrivateKey[H Hash](key PrivateKey) ConfigOption[H]
WithPrivateKey sets the private key for signing.
func WithStorage ¶
func WithStorage[H Hash](storage Storage[H]) ConfigOption[H]
WithStorage sets the storage backend.
func WithTargetBlockTime ¶
func WithTargetBlockTime[H Hash](blockTime time.Duration) ConfigOption[H]
WithTargetBlockTime is a convenience method to configure pacemaker for a specific target block time. This sets up appropriate timeouts for production use.
func WithTimer ¶
func WithTimer[H Hash](timer Timer) ConfigOption[H]
WithTimer sets the timer implementation.
func WithValidators ¶
func WithValidators[H Hash](validators ValidatorSet) ConfigOption[H]
WithValidators sets the validator set.
func WithVerification ¶
func WithVerification[H Hash](enabled bool) ConfigOption[H]
WithVerification enables or disables runtime TLA+ verification.
type ConsensusMessage ¶
type ConsensusMessage[H Hash] struct { // contains filtered or unexported fields }
ConsensusMessage represents a message in the HotStuff2 protocol.
Maps to TLA+ Message types: - PROPOSE: Leader broadcasts block with justification QC - VOTE: Replica votes for a proposal - NEWVIEW: Replica sends view change message with highQC
func MessageFromBytes ¶
func MessageFromBytes[H Hash]( data []byte, hashFromBytes func([]byte) (H, error), blockFromBytes func([]byte) (Block[H], error), ) (*ConsensusMessage[H], error)
MessageFromBytes deserializes a ConsensusMessage from bytes.
func NewNewViewMessage ¶
func NewNewViewMessage[H Hash]( view uint32, validatorIndex uint16, highQC *QC[H], ) *ConsensusMessage[H]
NewNewViewMessage creates a NEWVIEW message.
func NewProposeMessage ¶
func NewProposeMessage[H Hash]( view uint32, validatorIndex uint16, block Block[H], justifyQC *QC[H], ) *ConsensusMessage[H]
NewProposeMessage creates a PROPOSE message.
func NewVoteMessage ¶
func NewVoteMessage[H Hash]( view uint32, validatorIndex uint16, vote *Vote[H], ) *ConsensusMessage[H]
NewVoteMessage creates a VOTE message.
func (*ConsensusMessage[H]) Block ¶
func (m *ConsensusMessage[H]) Block() Block[H]
Block returns the proposed block (PROPOSE only).
func (*ConsensusMessage[H]) Bytes ¶
func (m *ConsensusMessage[H]) Bytes() []byte
Bytes serializes the message to bytes. Format: [type:1][view:4][validatorIndex:2][payload...]
func (*ConsensusMessage[H]) Hash ¶
func (m *ConsensusMessage[H]) Hash() H
Hash returns the hash of this message (implementation depends on block hash).
func (*ConsensusMessage[H]) HighQC ¶
func (m *ConsensusMessage[H]) HighQC() *QC[H]
HighQC returns the highest QC (NEWVIEW only).
func (*ConsensusMessage[H]) JustifyQC ¶
func (m *ConsensusMessage[H]) JustifyQC() *QC[H]
JustifyQC returns the justification QC (PROPOSE only).
func (*ConsensusMessage[H]) Type ¶
func (m *ConsensusMessage[H]) Type() MessageType
Type returns the message type.
func (*ConsensusMessage[H]) ValidatorIndex ¶
func (m *ConsensusMessage[H]) ValidatorIndex() uint16
ValidatorIndex returns the sender's validator index.
func (*ConsensusMessage[H]) View ¶
func (m *ConsensusMessage[H]) View() uint32
View returns the view number.
func (*ConsensusMessage[H]) Vote ¶
func (m *ConsensusMessage[H]) Vote() *Vote[H]
Vote returns the vote (VOTE only).
type ConsensusPayload ¶
type ConsensusPayload[H Hash] interface { // Type returns the message type (PROPOSE, VOTE, NEWVIEW). Type() MessageType // View returns the view number for this message. View() uint32 // ValidatorIndex returns the index of the validator who created this message. ValidatorIndex() uint16 // Bytes returns the serialized form of the payload. Bytes() []byte // Hash returns the hash of the payload for signing. Hash() H }
ConsensusPayload represents a message in the consensus protocol.
type ConsensusState ¶
type ConsensusState interface {
// View returns the current view number.
View() uint32
// Height returns the height of the last committed block.
Height() uint32
// LockedQCView returns the view of the locked QC, or 0 if none.
LockedQCView() uint32
// HighQCView returns the view of the highest QC seen, or 0 if none.
HighQCView() uint32
// CommittedCount returns the number of committed blocks.
CommittedCount() int
}
ConsensusState provides read-only access to consensus state. Use HotStuff2.State() to obtain an instance.
type Context ¶
type Context[H Hash] struct { // contains filtered or unexported fields }
Context maintains the consensus state for a HotStuff2 replica.
This maps to the TLA+ spec state variables: - view[r] -> view - lockedQC[r] -> lockedQC - highQC[r] -> highQC - committed[r] -> committed - votes tracking -> votes map - NEWVIEW tracking -> newviews map (for leader view change)
Thread-safe: All methods use mutex for concurrent access.
Note: Maps use string keys (hash.String()) instead of Hash type directly to avoid comparable constraint issues with generic interfaces.
func NewContext ¶
NewContext creates a new consensus context.
func (*Context[H]) AddNewView ¶
AddNewView records a NEWVIEW message from a validator for a view. Returns the count of unique validators who have sent NEWVIEW for this view. TLA+ spec: network' = network \cup { [type |-> "NEWVIEW", view |-> v, replica |-> r, qc |-> highQC[r]] }
func (*Context[H]) CanCommit ¶
CanCommit checks if a block can be committed using the two-chain rule.
TLA+ CanCommit(block, qc):
/\ blockParent[qc] = block /\ blockView[qc] = blockView[block] + 1
Both conditions must hold: qcBlock must be child of block AND they must be in consecutive views.
func (*Context[H]) CommittedBlocks ¶
CommittedBlocks returns all committed blocks.
func (*Context[H]) GetCommitted ¶
GetCommitted returns the committed block at the given height.
func (*Context[H]) HasNewViewQuorum ¶
HasNewViewQuorum returns true if 2f+1 NEWVIEW messages have been received for a view. TLA+ spec: IsQuorum(NewViewReplicasFromNetwork(v))
func (*Context[H]) HasSentNewView ¶
HasSentNewView returns true if this validator has already sent NEWVIEW for a view.
func (*Context[H]) HighestQCFromNewViews ¶
HighestQCFromNewViews returns the highest QC from all NEWVIEW messages in a view. TLA+ spec: HighestQCFromNetwork(v)
func (*Context[H]) IsAncestor ¶
IsAncestor checks if ancestor is an ancestor of descendant in the block tree.
func (*Context[H]) IsCommitted ¶
IsCommitted returns true if a block at the given height is committed.
func (*Context[H]) LastCommitTime ¶
LastCommitTime returns the time of the last commit.
func (*Context[H]) NewViewCount ¶
NewViewCount returns the number of NEWVIEW messages received for a view. TLA+ spec: Cardinality(NewViewReplicasFromNetwork(v))
func (*Context[H]) PruneVotes ¶
PruneVotes removes old votes and newviews to free memory.
func (*Context[H]) SafeToVote ¶
SafeToVote implements the TLA+ SafeNodeRule predicate.
func (*Context[H]) State ¶
func (c *Context[H]) State() ConsensusState
State returns a read-only ConsensusState for the context.
func (*Context[H]) TimeSinceLastCommit ¶
TimeSinceLastCommit returns the duration since the last commit.
func (*Context[H]) UpdateHighQC ¶
UpdateHighQC updates the highest QC if the new QC has higher view.
func (*Context[H]) UpdateLockedQC ¶
UpdateLockedQC updates the locked QC if the new QC has higher view.
type Executor ¶
type Executor[H Hash] interface { // Execute applies a block's payload and returns the resulting state hash. // Must be deterministic - same input always produces same output. Execute(block Block[H]) (stateHash H, err error) // Verify checks if a block is valid before voting. // Should validate: // - Parent block exists // - Payload is well-formed (application-specific) // - Block height is correct // - Any application-specific rules Verify(block Block[H]) error // GetStateHash returns the current state hash after all executed blocks. GetStateHash() H // CreateBlock creates a new block proposal. // Called when this validator is the leader. // The implementation decides what payload to include (e.g., transactions // from mempool, DAG references, rollup batch, etc.). CreateBlock(height uint32, prevHash H, proposerIndex uint16) (Block[H], error) }
Executor handles block execution and validation.
func NewMockExecutor ¶
NewMockExecutor creates a generic mock executor.
type GenericValidatorSet ¶
type GenericValidatorSet struct {
// contains filtered or unexported fields
}
GenericValidatorSet implements ValidatorSet for testing with any key type.
func NewGenericValidatorSet ¶
func NewGenericValidatorSet(n int, keys map[uint16]PublicKey) *GenericValidatorSet
NewGenericValidatorSet creates a generic validator set with any key type.
func (*GenericValidatorSet) Contains ¶
func (vs *GenericValidatorSet) Contains(index uint16) bool
func (*GenericValidatorSet) Count ¶
func (vs *GenericValidatorSet) Count() int
func (*GenericValidatorSet) F ¶
func (vs *GenericValidatorSet) F() int
func (*GenericValidatorSet) GetByIndex ¶
func (vs *GenericValidatorSet) GetByIndex(index uint16) (PublicKey, error)
func (*GenericValidatorSet) GetLeader ¶
func (vs *GenericValidatorSet) GetLeader(view uint32) uint16
func (*GenericValidatorSet) GetPublicKeys ¶
func (vs *GenericValidatorSet) GetPublicKeys(indices []uint16) ([]PublicKey, error)
type Hash ¶
type Hash interface {
// Bytes returns the raw byte representation of the hash.
Bytes() []byte
// Equals returns true if this hash equals the other hash.
// Must be consistent with Bytes() comparison.
Equals(other Hash) bool
// String returns a human-readable representation (typically hex-encoded).
String() string
}
Hash represents a cryptographic hash function output. Implementations must be comparable and suitable for use as map keys.
type Hooks ¶
type Hooks[H Hash] struct { // OnPropose is called when this node proposes a block (leader only). OnPropose func(view uint32, block Block[H]) // OnVote is called when this node votes for a proposal. OnVote func(view uint32, blockHash H) // OnQCFormed is called when a quorum certificate is formed. OnQCFormed func(view uint32, qc QuorumCertificate[H]) // OnCommit is called when a block is committed (finalized). OnCommit func(block Block[H]) // OnViewChange is called when the view changes. OnViewChange func(oldView, newView uint32) // OnTimeout is called when a view times out. OnTimeout func(view uint32) }
Hooks provides callbacks for consensus events. All callbacks are optional - nil callbacks are safely ignored. Callbacks are invoked synchronously, so implementations should be fast or dispatch to a goroutine to avoid blocking consensus.
type HotStuff2 ¶
type HotStuff2[H Hash] struct { // contains filtered or unexported fields }
HotStuff2 implements the HotStuff-2 consensus protocol.
This implementation follows the TLA+ specification in formal-models/tla/hotstuff2.tla Key protocol actions: - LeaderPropose: Leader broadcasts proposal with justification QC - ReplicaVote: Replica votes if proposal extends locked QC (SafeNode rule) - LeaderFormQC: Leader forms QC from 2f+1 votes - ReplicaUpdateOnQC: Replica updates state on seeing QC - ReplicaTimeout: Replica advances view on timeout
Safety: Lock mechanism prevents voting for conflicting blocks Liveness: Adaptive timeouts with exponential backoff
func NewHotStuff2 ¶
NewHotStuff2 creates a new HotStuff2 consensus instance. Deprecated: Use NewHotStuff2WithHooks for full observability support. This function is kept for backwards compatibility.
func NewHotStuff2WithHooks ¶
NewHotStuff2WithHooks creates a new HotStuff2 consensus instance with event hooks.
func (*HotStuff2[H]) State ¶
func (hs *HotStuff2[H]) State() ConsensusState
State returns a read-only view of consensus state for monitoring.
type MessageCodec ¶
type MessageCodec[H Hash] struct { // HashFromBytes deserializes a hash from bytes. HashFromBytes func([]byte) (H, error) // BlockFromBytes deserializes a block from bytes. BlockFromBytes func([]byte) (Block[H], error) }
MessageCodec provides convenient encoding/decoding of consensus messages. Create once and reuse for all message operations.
func NewMessageCodec ¶
func NewMessageCodec[H Hash]( hashFromBytes func([]byte) (H, error), blockFromBytes func([]byte) (Block[H], error), ) *MessageCodec[H]
NewMessageCodec creates a new message codec with the given deserializers.
func (*MessageCodec[H]) Decode ¶
func (c *MessageCodec[H]) Decode(data []byte) (*ConsensusMessage[H], error)
Decode deserializes a consensus message from bytes.
func (*MessageCodec[H]) Encode ¶
func (c *MessageCodec[H]) Encode(msg *ConsensusMessage[H]) []byte
Encode serializes a consensus message to bytes.
type MessageType ¶
type MessageType uint8
MessageType represents the type of consensus message.
const ( // MessageProposal represents a block proposal from the leader. MessageProposal MessageType = iota // MessageVote represents a vote for a proposal. MessageVote // MessageNewView represents a new view message during view change. MessageNewView )
func (MessageType) String ¶
func (mt MessageType) String() string
String returns the string representation of the message type.
type Network ¶
type Network[H Hash] interface { // Broadcast sends a message to all validators. Broadcast(payload ConsensusPayload[H]) // SendTo sends a message to a specific validator. SendTo(validatorIndex uint16, payload ConsensusPayload[H]) // Receive returns a channel for receiving consensus messages. // The channel should be buffered to prevent message loss. Receive() <-chan ConsensusPayload[H] // Close releases any resources held by the network. Close() error }
Network provides message broadcasting and delivery.
func NewMockNetwork ¶
NewMockNetwork creates a generic mock network.
type Pacemaker ¶
type Pacemaker struct {
// contains filtered or unexported fields
}
Pacemaker manages view synchronization and timeouts for HotStuff2.
The pacemaker triggers view changes when the current view doesn't make progress. It uses adaptive timeouts with exponential backoff for liveness under asynchrony.
The timing model follows standard BFT practices:
- TimeoutPropose: Wait for leader to propose
- TimeoutVote: Wait for votes (unused in two-phase HotStuff-2)
- TimeoutCommit: Minimum delay between blocks (target block time)
func NewPacemaker ¶
NewPacemaker creates a new Pacemaker with the given configuration.
func NewPacemakerWithConfig ¶
func NewPacemakerWithConfig(timer Timer, logger *zap.Logger, onTimeout func(view uint32), config PacemakerConfig) *Pacemaker
NewPacemakerWithConfig creates a new Pacemaker with explicit configuration.
func (*Pacemaker) CanAcceptProposal ¶
CanAcceptProposal checks if a proposal can be accepted based on minimum block time. Returns true if MinBlockTime is not configured, or if enough time has elapsed. The skew parameter allows for clock drift tolerance.
func (*Pacemaker) Config ¶
func (pm *Pacemaker) Config() PacemakerConfig
Config returns the pacemaker configuration.
func (*Pacemaker) CurrentTimeout ¶
CurrentTimeout returns the current timeout duration.
func (*Pacemaker) IncreaseTimeout ¶
func (pm *Pacemaker) IncreaseTimeout()
IncreaseTimeout increases the timeout duration using exponential backoff. This should be called after a view change (timeout without commit).
func (*Pacemaker) MinBlockTimeEnabled ¶
MinBlockTimeEnabled returns true if minimum block time enforcement is enabled.
func (*Pacemaker) OnCommit ¶
OnCommit should be called when a block is committed. It enforces the minimum block time (TimeoutCommit) before allowing the next view to start proposing. Returns a channel that will be closed when the commit delay is complete.
func (*Pacemaker) OnProgress ¶
OnProgress should be called when consensus makes progress (receives valid proposal/votes). This resets the view timeout but does NOT affect the commit delay.
func (*Pacemaker) ResetTimeout ¶
func (pm *Pacemaker) ResetTimeout()
ResetTimeout resets the timeout to the base value. This is typically called after successful commit.
func (*Pacemaker) TimeUntilCanPropose ¶
TimeUntilCanPropose returns how long until a proposal can be made. Returns 0 if MinBlockTime is not configured or already past threshold.
func (*Pacemaker) WaitForCommitDelay ¶
func (pm *Pacemaker) WaitForCommitDelay()
WaitForCommitDelay waits for the commit delay to complete. This is a convenience method that blocks until the delay is done.
func (*Pacemaker) WaitForMinBlockTime ¶
WaitForMinBlockTime waits until the minimum block time has elapsed since lastCommitTime. This should be called by leaders before proposing a new block. Returns immediately if MinBlockTime is not configured (0).
type PacemakerConfig ¶
type PacemakerConfig struct {
// TimeoutPropose is how long to wait for a proposal before timing out.
// This is the initial timeout for each view.
// Default: 1000ms (1 second)
TimeoutPropose time.Duration
// TimeoutVote is how long to wait for votes after receiving +2/3 prevotes.
// In HotStuff-2, this is mainly used for the two-chain commit rule.
// Default: 1000ms (1 second)
TimeoutVote time.Duration
// TimeoutCommit is the minimum delay after committing a block before
// starting the next view. This is the primary control for target block time.
// Setting this to 0 allows blocks to be produced as fast as possible.
// Default: 0 (immediate, optimistically responsive)
TimeoutCommit time.Duration
// MinBlockTime enforces a minimum time between blocks at the consensus level.
// When set (> 0):
// - Leaders wait until last_commit_time + MinBlockTime before proposing
// - Validators reject proposals that arrive before last_commit_time + MinBlockTime - MinBlockTimeSkew
//
// This provides stronger guarantees than TimeoutCommit alone, as it prevents
// malicious leaders from proposing blocks faster than the target rate.
//
// Default: 0 (disabled, use TimeoutCommit for block pacing)
MinBlockTime time.Duration
// MinBlockTimeSkew is the clock skew tolerance for MinBlockTime enforcement.
// Validators will accept proposals that arrive up to this much before the
// minimum block time. This accounts for clock drift between nodes.
//
// Only used when MinBlockTime > 0.
// Default: 500ms
MinBlockTimeSkew time.Duration
// BackoffMultiplier is the factor by which timeouts increase after each
// failed round (view change without commit). Values > 1.0 provide exponential
// backoff which helps the network synchronize during periods of instability.
// Default: 1.5 (50% increase per failed round)
BackoffMultiplier float64
// MaxTimeout is the maximum timeout duration. Timeouts will not grow beyond
// this value regardless of backoff.
// Default: 30s
MaxTimeout time.Duration
// SkipTimeoutCommit, if true, skips the commit delay when we receive
// all votes (fast path). This allows faster block times when the network
// is healthy while still enforcing the target block time under degraded
// conditions.
// Default: false
SkipTimeoutCommit bool
}
PacemakerConfig configures the pacemaker timing behavior.
This follows the standard BFT timing model used by production systems like CometBFT (Tendermint) and Aptos. The key parameters are:
- TimeoutPropose: How long to wait for a block proposal before timing out
- TimeoutVote: How long to wait for votes after receiving a proposal
- TimeoutCommit: Minimum time between blocks (target block time)
- BackoffMultiplier: Exponential backoff factor for failed rounds
For public blockchains, TimeoutCommit is typically the primary control for block time. For example, setting TimeoutCommit to 5 seconds results in approximately 5-second blocks under normal conditions.
Minimum Block Time Enforcement ¶
For stronger block time guarantees, enable MinBlockTime. When set:
- Leaders wait until last_commit_time + MinBlockTime before proposing
- Validators refuse to vote for proposals that arrive too early
This prevents malicious/fast leaders from speeding up the chain while preserving HotStuff-2 safety and remaining compatible with the liveness model.
func DefaultPacemakerConfig ¶
func DefaultPacemakerConfig() PacemakerConfig
DefaultPacemakerConfig returns the default pacemaker configuration. This is tuned for low-latency networks with optimistic responsiveness.
func DemoPacemakerConfig ¶
func DemoPacemakerConfig() PacemakerConfig
DemoPacemakerConfig returns a configuration suitable for demos and testing with visible block production (approximately 1 block per second).
func ProductionPacemakerConfig ¶
func ProductionPacemakerConfig(targetBlockTime time.Duration) PacemakerConfig
ProductionPacemakerConfig returns a configuration suitable for production public blockchains with a target block time.
This enables MinBlockTime enforcement, which ensures:
- Leaders wait until last_commit_time + targetBlockTime before proposing
- Validators reject proposals that arrive too early
This provides stronger guarantees against malicious leaders trying to speed up block production.
func (PacemakerConfig) Validate ¶
func (c PacemakerConfig) Validate() error
Validate checks that the configuration values are sensible.
type PrivateKey ¶
type PrivateKey interface {
// PublicKey returns the corresponding public key.
// Returns a type that implements PublicKey interface methods.
PublicKey() interface {
Bytes() []byte
Verify(message []byte, signature []byte) bool
Equals(other interface{ Bytes() []byte }) bool
String() string
}
// Sign signs the given message and returns the signature.
// Returns an error if signing fails.
Sign(message []byte) ([]byte, error)
// Bytes returns the raw byte representation of the private key.
// WARNING: Handle with care - this exposes sensitive key material.
Bytes() []byte
}
PrivateKey represents a validator's private key for signing messages.
type PublicKey ¶
type PublicKey interface {
// Bytes returns the raw byte representation of the public key.
Bytes() []byte
// Verify verifies a signature over the given message.
// Returns true if the signature is valid for this public key.
Verify(message []byte, signature []byte) bool
// Equals returns true if this public key equals the other.
// Accepts interface{} for flexibility with different implementations.
Equals(other interface{ Bytes() []byte }) bool
// String returns a human-readable representation of the public key.
String() string
}
PublicKey represents a validator's public key for signature verification.
type QC ¶
type QC[H Hash] struct { // contains filtered or unexported fields }
QC represents a Quorum Certificate - aggregated proof that 2f+1 validators voted for a block in a specific view.
CRITICAL SAFETY: QC validation is the cornerstone of consensus safety. A forged QC can cause Byzantine faults and break consensus.
Safety rules (from TLA+ spec): - MUST have exactly 2f+1 distinct signers (deduplicated) - MUST verify aggregate signature - NEVER accept QC without full validation
Attack scenario: Without deduplication, Byzantine nodes could create valid-looking QCs with only f+1 real votes by duplicating signatures.
func NewQC ¶
func NewQC[H Hash]( view uint32, nodeHash H, votes []*Vote[H], validators ValidatorSet, cryptoScheme string, ) (*QC[H], error)
NewQC creates a new QC from a set of votes.
CRITICAL: This function deduplicates signers before forming the QC. Duplicate votes from the same validator MUST be rejected to prevent Byzantine attacks where <2f+1 real votes appear as a valid QC.
The cryptoScheme parameter determines how signatures are aggregated: - "ed25519": Concatenate signatures (O(n) size) - "bls": Aggregate signatures using BLS12-381 (O(1) size)
func QCFromBytes ¶
QCFromBytes reconstructs a QC from serialized bytes.
func (*QC[H]) AggregateSignature ¶
AggregateSignature returns the aggregated signature bytes.
func (*QC[H]) Bytes ¶
Bytes serializes the QC to bytes. Format: [view:4][nodeHashLen:2][nodeHash][signerCount:2][signer1:2]...[timestamp1:8]...[schemeLen:1][scheme][aggSigLen:2][aggSig]
func (*QC[H]) CryptoScheme ¶
CryptoScheme returns the cryptographic scheme used ("ed25519" or "bls").
func (*QC[H]) Node ¶
func (qc *QC[H]) Node() H
Node returns the hash of the block this QC certifies.
func (*QC[H]) Signers ¶
Signers returns the list of validator indices who signed. Guaranteed to be deduplicated and sorted.
func (*QC[H]) Validate ¶
func (qc *QC[H]) Validate(validators ValidatorSet) error
Validate verifies the QC is well-formed and signatures are valid.
CRITICAL SAFETY: This implements the complete QC validation logic. Failures here can cause Byzantine faults.
Validation steps: 1. Check quorum size (2f+1) 2. Verify all signers are valid validators 3. Check signers are deduplicated 4. Verify aggregate signature
Returns error if any validation fails.
type QuorumCertificate ¶
type QuorumCertificate[H Hash] interface { // Node returns the hash of the block this QC certifies. Node() H // View returns the view number in which this QC was formed. View() uint32 // Signers returns the list of validator indices who signed. // MUST be deduplicated and sorted. Signers() []uint16 // AggregateSignature returns the aggregated signature. AggregateSignature() []byte // Bytes returns the serialized form of the QC. Bytes() []byte // Validate verifies the QC is well-formed and signatures are valid. // Returns error if: // - Signer count < 2f+1 // - Duplicate signers found // - Invalid signer indices // - Aggregate signature verification fails Validate(validators ValidatorSet) error }
QuorumCertificate represents an aggregated certificate from 2f+1 validators.
CRITICAL SAFETY RULES: QC validation is the most critical part of consensus safety. A forged QC can cause replicas to commit conflicting blocks, violating Byzantine fault tolerance.
Implementations MUST:
- Validate signer set has exactly 2f+1 distinct validators (not more, not less)
- Deduplicate signers before accepting QC (prevents forged QCs via duplicate votes)
- Verify aggregate signature matches node digest + view number
- NEVER accept QC without full validation - even from trusted sources
Attack scenario: If duplicate signers are allowed, a Byzantine node could create a valid-looking QC with only f+1 real votes by duplicating each signature.
type Storage ¶
type Storage[H Hash] interface { // GetBlock retrieves a block by its hash. GetBlock(hash H) (Block[H], error) // PutBlock persists a block. // Must complete durably before returning. PutBlock(block Block[H]) error // GetLastBlock returns the most recently committed block. GetLastBlock() (Block[H], error) // GetQC retrieves the QC that certifies the given block. GetQC(nodeHash H) (QuorumCertificate[H], error) // PutQC persists a QC. // Must complete durably before returning. PutQC(qc QuorumCertificate[H]) error // GetHighestLockedQC returns the highest locked QC. // This is safety-critical for crash recovery. GetHighestLockedQC() (QuorumCertificate[H], error) // PutHighestLockedQC persists the highest locked QC. // Must complete durably before returning. PutHighestLockedQC(qc QuorumCertificate[H]) error // GetView returns the current view number. GetView() (uint32, error) // PutView persists the current view number. // Must complete durably before returning. PutView(view uint32) error // Close releases any resources held by the storage. Close() error }
Storage provides persistent storage for consensus state.
CRITICAL SAFETY: All Put operations must be durable before returning. The locked QC and view number must be persisted atomically to prevent safety violations after crash recovery.
func NewMockStorage ¶
NewMockStorage creates a generic mock storage.
type TestBlock ¶
type TestBlock struct {
// contains filtered or unexported fields
}
TestBlock implements Block for testing.
func (*TestBlock) ProposerIndex ¶
type TestExecutor ¶
type TestExecutor struct {
// contains filtered or unexported fields
}
TestExecutor implements Executor for testing.
func NewTestExecutor ¶
func NewTestExecutor() *TestExecutor
func (*TestExecutor) CreateBlock ¶
func (*TestExecutor) Execute ¶
func (e *TestExecutor) Execute(block Block[TestHash]) (TestHash, error)
func (*TestExecutor) GetStateHash ¶
func (e *TestExecutor) GetStateHash() TestHash
type TestHash ¶
type TestHash [32]byte
TestHash implements Hash for testing using SHA256.
func NewTestHash ¶
NewTestHash creates a test hash from a string.
type TestNetwork ¶
type TestNetwork struct {
// contains filtered or unexported fields
}
TestNetwork implements Network for testing.
func NewTestNetwork ¶
func NewTestNetwork() *TestNetwork
func (*TestNetwork) Broadcast ¶
func (n *TestNetwork) Broadcast(payload ConsensusPayload[TestHash])
func (*TestNetwork) Close ¶
func (n *TestNetwork) Close() error
func (*TestNetwork) Receive ¶
func (n *TestNetwork) Receive() <-chan ConsensusPayload[TestHash]
func (*TestNetwork) SendTo ¶
func (n *TestNetwork) SendTo(validatorIndex uint16, payload ConsensusPayload[TestHash])
func (*TestNetwork) SentMessages ¶
func (n *TestNetwork) SentMessages() []ConsensusPayload[TestHash]
type TestStorage ¶
type TestStorage struct {
// contains filtered or unexported fields
}
TestStorage implements Storage for testing.
func NewTestStorage ¶
func NewTestStorage() *TestStorage
func (*TestStorage) Close ¶
func (s *TestStorage) Close() error
func (*TestStorage) GetBlock ¶
func (s *TestStorage) GetBlock(hash TestHash) (Block[TestHash], error)
func (*TestStorage) GetHighestLockedQC ¶
func (s *TestStorage) GetHighestLockedQC() (QuorumCertificate[TestHash], error)
func (*TestStorage) GetLastBlock ¶
func (s *TestStorage) GetLastBlock() (Block[TestHash], error)
func (*TestStorage) GetQC ¶
func (s *TestStorage) GetQC(nodeHash TestHash) (QuorumCertificate[TestHash], error)
func (*TestStorage) GetView ¶
func (s *TestStorage) GetView() (uint32, error)
func (*TestStorage) PutHighestLockedQC ¶
func (s *TestStorage) PutHighestLockedQC(qc QuorumCertificate[TestHash]) error
func (*TestStorage) PutQC ¶
func (s *TestStorage) PutQC(qc QuorumCertificate[TestHash]) error
func (*TestStorage) PutView ¶
func (s *TestStorage) PutView(view uint32) error
type TestValidatorSet ¶
type TestValidatorSet struct {
// contains filtered or unexported fields
}
TestValidatorSet implements ValidatorSet for testing.
func NewTestValidatorSet ¶
func NewTestValidatorSet(n int) *TestValidatorSet
func NewTestValidatorSetWithKeys ¶
func NewTestValidatorSetWithKeys(n int) (*TestValidatorSet, []*crypto.Ed25519PrivateKey)
NewTestValidatorSetWithKeys creates a validator set and returns the private keys.
func (*TestValidatorSet) Contains ¶
func (vs *TestValidatorSet) Contains(index uint16) bool
func (*TestValidatorSet) Count ¶
func (vs *TestValidatorSet) Count() int
func (*TestValidatorSet) F ¶
func (vs *TestValidatorSet) F() int
func (*TestValidatorSet) GetByIndex ¶
func (vs *TestValidatorSet) GetByIndex(index uint16) (PublicKey, error)
func (*TestValidatorSet) GetLeader ¶
func (vs *TestValidatorSet) GetLeader(view uint32) uint16
func (*TestValidatorSet) GetPublicKeys ¶
func (vs *TestValidatorSet) GetPublicKeys(indices []uint16) ([]PublicKey, error)
type Timer ¶
type Timer interface {
// Start starts the timer with the given duration in milliseconds.
Start(duration uint64)
// Stop stops the timer.
Stop()
// Reset resets the timer with a new duration.
Reset(duration uint64)
// C returns a channel that receives when the timer expires.
C() <-chan struct{}
}
Timer provides timeout management for the pacemaker.
type ValidatorSet ¶
type ValidatorSet interface {
// Count returns the total number of validators.
Count() int
// GetByIndex returns the public key for a validator by index.
// Returns error if index is out of bounds.
GetByIndex(index uint16) (PublicKey, error)
// Contains returns true if the validator index is valid.
Contains(index uint16) bool
// GetPublicKeys returns public keys for the given validator indices.
// Used for aggregate signature verification.
GetPublicKeys(indices []uint16) ([]PublicKey, error)
// GetLeader returns the validator index of the leader for a given view.
// Typically implements round-robin: view % count.
GetLeader(view uint32) uint16
// F returns the maximum number of Byzantine validators tolerated.
// Must return (n-1)/3 where n is the total validator count.
F() int
}
ValidatorSet represents the current set of consensus validators.
type Vote ¶
type Vote[H Hash] struct { // contains filtered or unexported fields }
Vote represents a replica's vote for a block proposal.
Votes are the fundamental building blocks of QCs (Quorum Certificates). A QC is formed when 2f+1 replicas vote for the same block in the same view.
CRITICAL SAFETY: Votes include replay protection via timestamp validation. Replicas must reject votes with timestamps outside acceptable window (60s).
func NewBLSVote ¶
func NewBLSVote[H Hash]( view uint32, nodeHash H, validatorIndex uint16, signer BLSSigner, ) (*Vote[H], error)
NewBLSVote creates a new vote using BLS signature scheme. BLS votes sign the common message (view + nodeHash) without validatorIndex or timestamp. This enables O(1) signature aggregation in QC formation.
func NewVote ¶
func NewVote[H Hash]( view uint32, nodeHash H, validatorIndex uint16, privateKey PrivateKey, ) (*Vote[H], error)
NewVote creates a new vote for a block at a given view (Ed25519). For BLS votes, use NewBLSVote instead.
func VoteFromBytes ¶
VoteFromBytes reconstructs a Vote from serialized bytes.
func (*Vote[H]) BLSDigest ¶
BLSDigest returns the common message for BLS signing. Format: [view:4][nodeHash] This is the message ALL validators sign when using BLS, enabling aggregation. Unlike Digest(), this does NOT include validatorIndex or timestamp.
func (*Vote[H]) Bytes ¶
Bytes serializes the vote to bytes. Format: [view:4][nodeHashLen:2][nodeHash][validatorIndex:2][timestamp:8][sigLen:2][signature]
func (*Vote[H]) Digest ¶
Digest returns the digest of the vote for signing/verification (Ed25519). Digest includes: view + nodeHash + validatorIndex + timestamp This is used for Ed25519 signatures which include per-validator data.
func (*Vote[H]) NodeHash ¶
func (v *Vote[H]) NodeHash() H
NodeHash returns the hash of the block being voted for.
func (*Vote[H]) Timestamp ¶
Timestamp returns the Unix timestamp (milliseconds) when this vote was created.
func (*Vote[H]) ValidatorIndex ¶
ValidatorIndex returns the index of the validator who created this vote.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package bench provides benchmarking utilities for HotStuff-2.
|
Package bench provides benchmarking utilities for HotStuff-2. |
|
cmd
|
|
|
benchgen
command
Command benchgen generates HTML benchmark reports.
|
Command benchgen generates HTML benchmark reports. |
|
Demo is a web-based visualization of HotStuff-2 consensus.
|
Demo is a web-based visualization of HotStuff-2 consensus. |
|
simulator
Package simulator provides a local network simulation for HotStuff-2 consensus.
|
Package simulator provides a local network simulation for HotStuff-2 consensus. |
|
internal
|
|
|
crypto
Package crypto provides cryptographic primitives for HotStuff-2.
|
Package crypto provides cryptographic primitives for HotStuff-2. |
|
Package timer provides timer implementations for HotStuff-2 pacemaker.
|
Package timer provides timer implementations for HotStuff-2 pacemaker. |
|
Package twins implements the Twins framework for Byzantine fault testing.
|
Package twins implements the Twins framework for Byzantine fault testing. |