Files
zeekayandHanzo Dev 80569ef0e8 alpha means alpha distinct validators, on every road that reaches it
Four ways the tally could be reached by something that is not a quorum.

A peer that is not a validator could vote. The signed path never had to ask:
VerifyVote resolves the voter's key out of the set at the block's epoch, so an
id that is not in the set has no key and its vote dies there. The
transport-authenticated path has no signature to resolve and the tallies are
keyed by NodeID, so it counted distinct PEERS. A peer need not be a validator to
connect, and its NodeID is a hash of a certificate it makes for itself, so
distinct peers are free to mint. Worst on the reject road, which has no cert in
front of it and commits inline.

One node could vote repeatedly. The engine behind consensus.NewChain appended
votes to a slice and compared its length to alpha, so a single node reached
quorum alone. Votes are now keyed by voter: a second vote from a node replaces
its first. The Config comment called alpha "the number of votes", which is the
same mistake written as prose.

A cert for one block could finalize another. The outer envelope ids are the one
part of a position no signature covers — the signed identity is the inner
canonical — so the id we looked the block up by proves nothing. Re-point it at a
sibling at the same height and a genuine cert asks us to accept a block it does
not name. The arm that finds a wrapper now checks the canonical, which the arm
that finds none already did.

And a node could go silent on a block it still holds. Abandonment stops
re-soliciting peers who cannot vote; the slot sweep read it as "do not vote
either", so the settle pass never offered the slot and the height was never
signed while the block sat pending and undecided. It is also a per-node clock
decision, so it dropped nodes out of the tally at different times. One meaning
now, and no flag to select the other.

Also: a seed below the node's own applied head is refused rather than planting
the certified frontier under it, and the phantom-floor reconcile is deleted —
a repair for a bug already fixed, called by nothing, that asked an operator to
verify a fleet-wide height by hand before it would prune the equivocation
bindings.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-15 23:30:25 -07:00

78 lines
1.9 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc All rights reserved.
// See the file LICENSE for licensing terms.
package types
import (
"time"
"github.com/luxfi/consensus/core/choices"
coretypes "github.com/luxfi/consensus/core/types"
"github.com/luxfi/ids"
)
// Identifiers, named here so the block-and-vote surface reads in one vocabulary.
type (
ID = ids.ID
NodeID = ids.NodeID
)
// Decision is the outcome a block has been assigned.
type Decision = coretypes.Decision
const (
DecideUndecided = coretypes.DecideUndecided
DecideAccept = coretypes.DecideAccept
DecideReject = coretypes.DecideReject
)
// VoteType distinguishes a soft preference from a commitment.
type VoteType int
const (
VotePreference VoteType = iota
VoteCommit
)
// GenesisID is the ID of the genesis block.
var GenesisID = ids.Empty
// Block is a block in the chain.
type Block struct {
ID ID `json:"id"`
ParentID ID `json:"parent_id"`
Height uint64 `json:"height"`
Payload []byte `json:"payload"`
Time time.Time `json:"time"`
}
// Vote is one validator's vote on one block.
type Vote struct {
BlockID ID `json:"block_id"`
VoteType VoteType `json:"vote_type"`
Voter NodeID `json:"voter"`
Signature []byte `json:"signature"`
}
// Status is where a block stands.
type Status = choices.Status
const (
StatusUnknown = choices.Unknown
StatusProcessing = choices.Processing
StatusAccepted = choices.Accepted
)
// Config parameterizes a chain engine.
type Config struct {
// Alpha is the quorum: how many DISTINCT voters must name a block before it
// is accepted. Counting votes rather than voters lets one node reach quorum
// by itself. At one or below, the first vote to arrive is final.
Alpha int `json:"alpha"`
}
// DefaultConfig returns the default consensus configuration.
func DefaultConfig() Config {
return Config{Alpha: 20}
}