Covers all required K/Alpha configurations:
- K=1 (1/1): --dev single-node, self-vote only
- K=2 (2/2): minimum multi-node
- K=3 (2/3): small network standard
- K=5 (3/5): medium network
- K=20 (15/20 = 75%): production default
- K=21 (14/21 = 67%): mainnet minimum threshold
- K=100 (69/100 = 69%): large validator set
TestConsensusAcceptanceThresholds: verifies blocks accepted ONLY when
Alpha is reached, rejected below threshold. 12 sub-tests.
TestConsensusRejection: verifies reject votes trigger rejection.
TestSelfVoteOnlyForK1: ensures self-voting callback is NEVER
created for K>1 (multi-node MUST use network consensus).
TestConsensusConfigurations: end-to-end proposer behavior for all
K values — self-vote vs network poll.
Three fixes for single-node consensus (--dev mode, K=1):
1. Self-voting: when K=1 and all sampled validators are self, deliver
a self-vote via callback instead of polling 0 peers.
2. Block acceptance: call Verify() before Accept() — PlatformVM requires
block state prepared during Verify(). Without it, Accept() fails
silently due to missing block state.
3. DrainAccepted: after each VM notification, check for blocks that
consensus accepted and call their Verify+Accept pipeline.
Multi-node consensus (K>1) is unchanged — self-voting only activates
when K=1 and no external validators exist in the sample.
Tests:
- TestSingleNodeSelfVote: K=1 self-votes, no network queries
- TestMultiNodeDoesNotSelfVote: K=3 uses network, no self-vote
- TestSelfVoterNilWhenKGreaterThan1: callback only for K=1
- quasar.go: rename loop vars to avoid shadowing receiver in 5 loops
(blsSigner for blsSigners, share for coronaShares)
- witness.go: rename errors channel to errs (shadows builtin),
add bounds check in createVerkleCommitment for short stateRoot
- gpu_batch_pipeline.go: Metrics() returns p.metrics pointer instead
of zero-valued struct
getInactiveBuffer held bufferMu while spin-waiting for a free buffer,
deadlocking concurrent loadAndProcess goroutines that also needed
bufferMu (via swapBuffers). Release the lock before yielding and check
ctx.Done to unblock during shutdown.
Also bounds the Stop() drain loop to prevent indefinite hangs.
Prevents concurrent Accept() calls from duplicate gossip delivery by
adding sync.Mutex protection and height-based deduplication to the
gossiperProposer's fast-follow acceptance path.
- Fix nested lock (t.mu -> c.mu) deadlock in handleVote, buildBlocksLocked,
and processPendingBlocks by releasing t.mu before calling consensus methods
- Add sync.WaitGroup for proper goroutine lifecycle in Start/Stop
- Add reject vote tracking with quorum-based rejection
- Return error for duplicate block additions in ChainConsensus.AddBlock
- Remove all debug fmt.Printf statements
- Add defer engine.Stop(ctx) to all tests that call Start() to prevent
goroutine leaks
- Fix tests calling buildBlocksLocked to hold mu.Lock as expected
- Change AddBlock to return nil instead of error when block already exists
- Fix AddBlock error handling to still track blocks in pendingBlocks
- Add explicit Poll call for proposer's own vote after adding block
With quorum-size=1, the proposer's vote should immediately finalize the
block. Previously, the proposer's vote was counted but never processed
through Poll, preventing block finalization.
This fixes the "AddBlock failed: block already exists" loop where blocks
were being built but never finalized.
- Increase benchmark timeout to 10 min and reduce benchtime
- Mark Python and Rust SDK jobs as continue-on-error (optional)
- Fix TestProcessMultipleBatches timeout for race detector
- Fix race in Transitive.Start() by passing context to goroutines
instead of accessing struct field directly
- Add atomic operations to trackingMockBlock for thread-safe
Accept/Reject call counting in tests
- Add race detector build tags to skip performance timing checks
in quasar tests when running with -race flag (10-20x overhead)
Define MessageType, Message, Fx, FxLifecycle locally in core package
instead of aliasing from vm. This breaks the import cycle:
consensus → vm → consensus that was preventing builds without
workspace mode.
Remove dependency on github.com/luxfi/vm to break the cycle:
- consensus/engine/interfaces -> vm -> consensus/engine/chain/block
- Define State type and constants directly in interfaces package
This commit fixes the critical gap where consensus had k=5 parameter
but was broadcasting to ALL validators instead of sampling k peers.
Changes:
- Add ValidatorSampler interface for k-peer sampling
- Add NodeID and Validators fields to NetworkConfig
- Wire validator sampler through Runtime to gossiperProposer
- Implement k-sampling in RequestVotes() instead of broadcast-all
- Add SampleValidators() and ValidatorCount() helper methods
- Fix nil Logger panic in NewRuntime (nil interface check)
- Add debug logging for vote flow tracking
The gossiperProposer now:
1. Checks if req.Validators is nil (meaning "sample k")
2. Samples k validators from the validator set
3. Filters out self from the sample
4. Sends PullQuery to sampled validators only
This enables proper Snowball/Avalanche consensus behavior where
each poll queries a random sample of k validators.
Implement proper fusion signature in createHorizonSignature:
- Create 64-byte signature: 32-byte BLS hash + 32-byte PQ hash
- Hash checkpoint and validators into message
- Apply key-derived signatures for both components
- Document that full threshold signing uses Quasar.hybridConsensus
Update tests to verify:
- Correct signature length (64 bytes)
- Deterministic output
- Different inputs produce different signatures
Also includes GPU batch pipeline for consensus engine.
- Add state.SerializerConfig and state.NewSerializer for vertex serialization
- Add state.Manager interface extending State with DAG operations
- Add bootstrap.Config with all required interfaces (Blocker, Halter, LinearizableVM)
- Add bootstrap.Bootstrapper implementing BootstrapableEngine
- Add bootstrap/queue.Queue for job processing
- Add getter.Handler and getter.Getter interfaces
This enables the DAG consensus engine to be properly wired up in the node.
- Add StopWithError method for graceful shutdown with errors
- Add Context method to expose engine context
- Change Start signature from (ctx, uint32) to (ctx, bool)
- Add StartWithID for backward compatibility with uint32 request ID
Move AppSender, AppHandler, AppError, and Fx interfaces from engine/core
to engine/interfaces for a flat, simple package structure.
Remove engine/core - all interfaces now live in engine/interfaces.
- Add AppSender interface to engine/core for VM plugin communication
- Add AppHandler interface with message handling methods
- Add Fx struct for feature extensions
- Add AppSender interface to engine/chain/block for node integration
- Fix GetValidatorState to return typed ValidatorState instead of interface{}
- Add appsender package in core for consensus-level app messaging
These interfaces are required by the EVM package to build successfully
with the consensus package.
- Remove unused packages: engine/dag/{getter,bootstrap,vertex/vertexmock},
engine/pq/{bootstrap,block}, core/{tracker,verify}
- Add sync.RWMutex to protocol/wave for thread-safe map access
- Increase engine/dag test coverage from 11.7% to 98.3%
- Add comprehensive tests for DAG consensus, vertex, and engine
- All 27 packages pass tests, 16 at 100% coverage