cmd: delete six unshipped tools, make the shipped one honest and tested

Seven main packages sat at 0% coverage. Only cmd/consensus reaches a user:
.hanzo/workflows/release.yml builds it into the release artifact. The other
six were built by a Makefile CI never invokes, or by nothing at all, and
nothing in or outside the module imports them.

They did not merely go unused, they misreported. bench printed a 30k TPS
figure that was the throughput of a failed map lookup, its chain half unable
to start at all. checker exited 0 announcing "all health checks passed" while
asserting nothing. sim drew from rand and formatted it like a quorum. server
asserted its engine to an interface the engine does not implement, so health
was a hardcoded true, and it was in no build recipe. conformance printed a
1-of-3 accept as normal. params duplicated cmd/consensus.

cmd/consensus keeps only what it can prove. The engine "test" and "health"
actions started an engine, printed a check mark and asserted nothing, so they
would pass against a Start that does nothing; they are gone along with the
stale "not yet implemented" arms for constructors that do exist. What remains
is the parameter report, absorbing the -json flag from params.

An unknown -network no longer falls back to mainnet. A typo used to print
mainnet's K=21 while the operator read it as the network they asked for.

Its old test never called a single symbol from main.go: it reimplemented a
CLI in the test file, parsed flags main.go does not have, and passed with
main.go deleted. Replaced with tests pinned to config, each verified to fail
under a deliberate mutation of the code it covers.

The .gitignore build-artifact patterns were unanchored, so `consensus` and
`bench` matched the cmd/consensus and bench source directories and silently
untracked new files in both. Anchored to the root artifacts they meant.

Also drops the Makefile and scripts that drove the deleted binaries, the
zmq-bench target chain building a cmd/ package absent for many commits, and
the E2E server test that can now only ever skip.

cmd/consensus: 0.0% -> 100.0% of statements, 1302 lines deleted.

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
2026-08-15 22:38:07 -07:00
co-authored by Hanzo Dev
parent c4fe410e6e
commit fe378a9557
18 changed files with 327 additions and 1985 deletions
+6 -6
View File
@@ -35,14 +35,14 @@ go.work.sum
*.swo
*~
# Build artifacts
# Build artifacts. Anchored: an unanchored `consensus` or `bench` also matches
# the cmd/consensus and bench source directories, so new files there were
# silently untracked. `make build` writes into bin/; release.yml writes
# consensus-<os>-<arch> here.
build/
dist/
consensus
bench
checker
params
sim
/consensus
/consensus-*
# Coverage
coverage.html
+10 -109
View File
@@ -2,29 +2,21 @@
# See the file LICENSE for licensing terms.
.PHONY: all test build clean lint format check tools help benchmark \
generate generate-mocks coverage coverage-html coverage-95 \
install-tools remove-generated examples examples-go examples-c examples-cpp examples-rust
coverage coverage-html coverage-95 \
install-tools examples examples-go examples-c examples-cpp examples-rust
# Default target
all: build test
# === BUILD TARGETS ===
# Build all tools and commands
# Build the commands. A failure here fails the build: swallowing it with
# `|| echo` is how this target came to report success while building nothing.
build: ## Build all tools and commands
@echo "🔨 Building all tools..."
@echo "Building params..."
@go build -o bin/params ./cmd/params || echo "ERROR: Failed to build params"
@echo "Building checker..."
@go build -o bin/checker ./cmd/checker || echo "ERROR: Failed to build checker"
@echo "Building simulator..."
@go build -o bin/sim ./cmd/sim || echo "ERROR: Failed to build sim"
@echo "Building bench..."
@go build -tags zmq -o bin/bench ./cmd/bench 2>/dev/null || go build -o bin/bench ./cmd/bench || echo "WARNING: Building without ZMQ support"
@echo "Building consensus CLI..."
@go build -o bin/consensus ./cmd/consensus || echo "ERROR: Failed to build consensus CLI"
@echo "✅ Build complete! Tools built:"
@ls -1 bin/ 2>/dev/null | grep -v '^$$' || echo "No tools built"
@echo "🔨 Building..."
@go build -o bin/consensus ./cmd/consensus
@echo "✅ Built:"
@ls -1 bin/
# === TEST TARGETS ===
@@ -108,27 +100,6 @@ benchmark: ## Run pure algorithm benchmarks without networking
@echo "🚀 Running pure consensus benchmarks..."
@go test -bench=. -benchmem ./config ./protocol/... ./engine/... ./photon ./core/... ./qzmq
# Build zmq-bench tool
zmq-bench: ## Build the ZMQ benchmark tool
@echo "🔨 Building zmq-bench tool..."
@go build -tags zmq -o bin/zmq-bench ./cmd/zmq-bench || echo "ERROR: zmq-bench requires ZMQ"
# Run zmq-bench tool
run-zmq-bench: zmq-bench ## Run ZMQ benchmark tool with configurable parameters
@echo "🚀 Running benchmark..."
@echo " Nodes: $(NODES)"
@echo " Batch: $(BATCH)"
@echo " Interval: $(INTERVAL)"
@echo " Rounds: $(ROUNDS)"
@echo ""
./bin/zmq-bench -nodes $(NODES) -batch $(BATCH) -interval $(INTERVAL) -rounds $(ROUNDS)
# Configuration for benchmarks
NODES ?= 10
BATCH ?= 4096
INTERVAL ?= 5ms
ROUNDS ?= 100
# Run massively parallel ZMQ benchmarks with Ginkgo
benchmark-zmq: check-ginkgo ## Run ZeroMQ transport benchmarks
@echo "🌐 Running transport benchmarks..."
@@ -139,53 +110,6 @@ test-parallel: check-ginkgo ## Run tests in parallel with Ginkgo
@echo "⚡ Running tests in parallel..."
ginkgo -p ./...
# Run CI benchmark suite (10, 100, 1000 nodes)
ci-cluster: zmq-bench ## Run CI multi-node consensus benchmarks (10, 100, 1000 nodes)
@echo "🌟 Running CI benchmark suite..."
@echo ""
@echo "### 10 nodes (default)"
@./bin/zmq-bench -nodes 10 -batch 8192 -interval 1ms -rounds 500 -quiet
@echo ""
@echo "### 100 nodes"
@./bin/zmq-bench -nodes 100 -batch 8192 -interval 1ms -rounds 100 -quiet
@echo ""
@echo "### 500 nodes"
@./bin/zmq-bench -nodes 1000 -batch 8192 -interval 1ms -rounds 50 -quiet
# Run quick benchmark
benchmark-quick: zmq-bench ## Quick benchmark with 10 nodes
@./bin/zmq-bench -nodes 10 -batch 8192 -interval 1ms -rounds 20
# Run maximum TPS benchmark
benchmark-max-tps: zmq-bench ## Run benchmark optimized for maximum TPS
@echo "🚀 Running maximum TPS benchmark..."
@CPU_COUNT=$$(sysctl -n hw.ncpu 2>/dev/null || nproc 2>/dev/null || echo 4); \
echo " CPU cores: $$CPU_COUNT"; \
echo " Nodes: $$((CPU_COUNT * 2))"; \
echo " Batch: 16384"; \
echo " Interval: 1ms"; \
echo ""; \
./bin/zmq-bench -nodes $$((CPU_COUNT * 2)) -batch 16384 -interval 1ms -rounds 100
# === CODE GENERATION TARGETS ===
# Generate all code (mocks)
generate: generate-mocks ## Generate all code (mocks)
@echo "✅ All code generation complete"
# Generate mock files
generate-mocks: check-mockgen ## Generate mock files
@echo "🔧 Generating mocks..."
@go generate ./...
@echo "✅ Mocks generated"
# Remove all generated files
remove-generated: ## Remove all generated files (*_mock.go, mock_*.go)
@echo "🧹 Removing generated files..."
@find . -name "*_mock.go" -type f -delete
@find . -name "mock_*.go" -type f -delete
@echo "✅ Generated files removed"
# === CODE QUALITY TARGETS ===
# Run linters
@@ -258,7 +182,6 @@ install-tools: ## Install development tools
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
@go install honnef.co/go/tools/cmd/staticcheck@latest
@go install golang.org/x/tools/cmd/goimports@latest
@go install github.com/golang/mock/mockgen@latest
@go install golang.org/x/vuln/cmd/govulncheck@latest
@$(MAKE) check-ginkgo
@echo "✅ Development tools installed"
@@ -296,10 +219,6 @@ clean: ## Clean build artifacts
@cd pkg/rust && cargo clean 2>/dev/null || true
@echo "✅ Clean complete"
# Clean everything including generated files
clean-all: clean remove-generated ## Clean everything including generated files
@echo "✅ Complete clean finished"
# === PAPER TARGETS ===
# Build the PDF white paper
@@ -340,12 +259,6 @@ docs-clean: ## Clean documentation build artifacts
@cd docs && rm -rf .next out node_modules
@echo "✅ Documentation cleaned"
# === UTILITY TARGETS ===
# Run params tool
run-params: build ## Build and run params tool
@./bin/params
# Show comprehensive help
help: ## Show this help
@echo "🔧 Lux Consensus Makefile"
@@ -354,7 +267,7 @@ help: ## Show this help
@echo ""
@echo "📋 Main Targets:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
grep -E '^(all|build|test|coverage-95|generate|clean|help):' | \
grep -E '^(all|build|test|coverage-95|clean|help):' | \
sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'
@echo ""
@echo "🧪 Test Targets:"
@@ -367,11 +280,6 @@ help: ## Show this help
grep -E '^(bench|benchmark)' | \
sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'
@echo ""
@echo "🔧 Code Generation:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
grep -E '^generate' | \
sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'
@echo ""
@echo "🔍 Code Quality:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
grep -E '^(lint|format|security|pre-commit)' | \
@@ -381,11 +289,8 @@ help: ## Show this help
@echo " # Achieve 95% test coverage"
@echo " make coverage-95"
@echo ""
@echo " # Generate all code and run tests"
@echo " make generate test"
@echo ""
@echo " # Clean and rebuild everything"
@echo " make clean-all generate build test"
@echo " make clean build test"
@echo ""
@echo " # Build integration examples"
@echo " make examples"
@@ -396,10 +301,6 @@ help: ## Show this help
check-ginkgo:
@which ginkgo > /dev/null || (echo "📦 Installing Ginkgo..."; go install github.com/onsi/ginkgo/v2/ginkgo@latest)
# Check if mockgen is installed
check-mockgen:
@which mockgen > /dev/null || (echo "📦 Installing mockgen..."; go install github.com/golang/mock/mockgen@latest)
# Check if LaTeX is installed
check-latex:
@which pdflatex > /dev/null || (echo "❌ pdflatex not found. Install LaTeX (e.g., brew install --cask mactex)"; exit 1)
+54 -259
View File
@@ -1,285 +1,80 @@
# Lux Consensus Testing Guide
# Testing
## Quick Start
Always `GOWORK=off` in this repo.
## The suite
```bash
# Build everything
make build
# Run quick test
./bin/consensus -action test
# Run simulation
./bin/sim -nodes 5 -rounds 10
GOWORK=off go test ./... # everything
GOWORK=off go test -race ./... # what CI runs
GOWORK=off go test -run TestName ./config # one test
```
## Manual Testing with cURL
`protocol/quasar` is the long pole: ~11600 SLH-DSA tests, which the race
detector multiplies by roughly 22. Give it `-timeout=40m` under `-race`, or it
gets killed mid-run and reports FAIL at exactly the timeout.
## Coverage
### 1. Start the test server
```bash
./bin/server -port 9090 -network local &
GOWORK=off go test -coverprofile=coverage.out ./...
GOWORK=off go tool cover -func=coverage.out # per function
GOWORK=off go tool cover -html=coverage.out # annotated source
```
### 2. Test endpoints
`make coverage-95` fails the build under 95%.
A coverage number only means something if the tests can fail. Before trusting
one, break the code on purpose and confirm the test that covers it goes red —
a test that passes against a mutilated implementation is measuring nothing.
## Integration
`test/integration` drives the engines through the public API. Nothing there
needs a server or a fixture process; `go test ./test/integration` is the whole
story.
## Benchmarks
#### Health Check
```bash
curl http://localhost:9090/health
# Output: OK
GOWORK=off go test -bench=. -benchmem ./...
make benchmark # config, protocol, engine, core
make benchmark-zmq # ZAP transport, needs ginkgo
```
#### Status Check
Increase `-benchtime=30s` when results scatter. Numbers in `BENCHMARKS.md` were
taken on an M1 Max; treat anything measured elsewhere as a different data set,
not a regression.
## Profiling
```bash
curl http://localhost:9090/status | jq
# Returns engine status and parameters
GOWORK=off go test -cpuprofile=cpu.prof -bench=.
GOWORK=off go tool pprof cpu.prof
GOWORK=off go test -memprofile=mem.prof -bench=.
GOWORK=off go tool pprof mem.prof
```
#### Run Consensus Test
## The CLI
`make build` produces `bin/consensus`, which reports the parameters this build
ships for a network:
```bash
# Simple test (GET)
curl http://localhost:9090/test | jq
# Custom test (POST)
curl -X POST http://localhost:9090/test \
-H "Content-Type: application/json" \
-d '{"rounds": 20, "nodes": 7}' | jq
./bin/consensus # mainnet, as a table
./bin/consensus -network local -json # local, as JSON
```
#### Process Consensus Round
```bash
curl -X POST http://localhost:9090/consensus \
-H "Content-Type: application/json" \
-d '{
"block_id": "test-block-001",
"votes": {
"node1": 1,
"node2": 1,
"node3": 1,
"node4": 1,
"node5": 0
}
}' | jq
```
It refuses a network it does not know rather than defaulting, so a typo exits
non-zero instead of printing mainnet's numbers under the name you asked for.
## CLI Tools
## CI
### Consensus CLI
```bash
# Test different engines
./bin/consensus -engine chain -action test
./bin/consensus -engine dag -action test
./bin/consensus -engine pq -action test
Native runners via `.hanzo/workflows` — `ci.yml` for the suite, lint and the C
and Rust wrappers, `release.yml` for the cross-compiled `consensus` binaries.
# Check health
./bin/consensus -action health
# Get info
./bin/consensus -action info
```
### Simulator
```bash
# Basic simulation
./bin/sim -nodes 5 -rounds 10
# Advanced simulation
./bin/sim -nodes 21 -rounds 100 -failure 0.2 -latency 100ms -verbose
# Different networks
./bin/sim -network mainnet -nodes 21 -rounds 50
./bin/sim -network testnet -nodes 11 -rounds 30
./bin/sim -network local -nodes 5 -rounds 20
```
### Benchmarks
```bash
# Quick benchmark
./bin/bench -engine chain -blocks 1000
# Full benchmark
./bin/bench -engine all -duration 30s -parallel 8
# Verbose output
./bin/bench -engine pq -blocks 10000 -verbose
```
## E2E Testing
### Run all E2E tests
```bash
go test -v ./... -run TestE2E
```
### Specific E2E tests
```bash
# Test consensus engines
go test -v -run TestE2EConsensusEngine
# Test server endpoints (requires server running)
go test -v -run TestE2EConsensusServer
# Test performance
go test -v -run TestE2EPerformance
# Test simulation
go test -v -run TestE2ESimulation
```
## Unit Testing
### Run all tests
```bash
go test ./...
```
### Run with race detection
```bash
go test -race ./...
```
### Run with coverage
```bash
go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
```
### Run benchmarks
```bash
go test -bench=. ./...
go test -bench=. -benchtime=10s ./...
go test -bench=. -benchmem ./...
```
## Load Testing
### Simple load test
```bash
# 100 concurrent health checks
for i in {1..100}; do
curl -s http://localhost:9090/health &
done
wait
```
### Stress test with Apache Bench (ab)
```bash
# Install ab if needed
# macOS: brew install httpd
# Linux: apt-get install apache2-utils
# 1000 requests, 10 concurrent
ab -n 1000 -c 10 http://localhost:9090/health
# POST requests
ab -n 100 -c 5 -p consensus.json -T application/json \
http://localhost:9090/consensus
```
### Stress test with hey
```bash
# Install hey
go install github.com/rakyll/hey@latest
# Basic test
hey -n 1000 -c 10 http://localhost:9090/health
# POST with payload
hey -n 100 -c 5 -m POST \
-H "Content-Type: application/json" \
-d '{"block_id":"test","votes":{"n1":1,"n2":1,"n3":1}}' \
http://localhost:9090/consensus
```
## Automated Test Script
Run the comprehensive test suite:
```bash
./test_consensus.sh
```
This script runs:
- Manual HTTP tests
- CLI tool tests
- E2E tests
- Load tests
- Unit tests
- Benchmarks
## CI/CD Testing
The GitHub Actions CI runs:
- Unit tests with race detection
- Cross-platform builds (Linux, macOS, Windows)
- Benchmarks
- Linting
Check CI status:
```bash
gh run list --repo luxfi/consensus --limit 5
gh run view <run-id> --repo luxfi/consensus
```
## Performance Requirements
Expected performance metrics:
- **Consensus finality**: < 100ms for local network
- **Throughput**: > 10,000 consensus rounds/sec
- **Concurrency**: Handle 1000+ concurrent requests
- **Memory**: < 100MB for basic operations
## Debugging
### Enable verbose logging
```bash
./bin/sim -verbose
./bin/bench -verbose
```
### Check server logs
```bash
# If running in background
tail -f consensus-server.log
# Or run in foreground
./bin/server -port 9090 -network local
```
### Profile performance
```bash
# CPU profiling
go test -cpuprofile=cpu.prof -bench=.
go tool pprof cpu.prof
# Memory profiling
go test -memprofile=mem.prof -bench=.
go tool pprof mem.prof
```
## Common Issues
### Port already in use
```bash
# Find process using port
lsof -i :9090
# Kill process
kill -9 <PID>
```
### Tests failing
```bash
# Check for race conditions
go test -race ./...
# Run with verbose output
go test -v ./...
# Run specific test
go test -v -run TestName ./...
```
### Benchmark variations
If benchmarks show high variation, increase duration:
```bash
go test -bench=. -benchtime=30s ./...
```
-181
View File
@@ -1,181 +0,0 @@
// Package main provides the bench CLI tool for consensus benchmarking
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"github.com/luxfi/consensus/config"
"github.com/luxfi/consensus/engine/chain"
"github.com/luxfi/consensus/engine/dag"
"github.com/luxfi/ids"
)
func main() {
var (
engine = flag.String("engine", "all", "Engine to benchmark (chain, dag, all)")
network = flag.String("network", "local", "Network configuration (mainnet, testnet, local)")
duration = flag.Duration("duration", 10*time.Second, "Benchmark duration")
blocks = flag.Int("blocks", 1000, "Number of blocks to process")
parallel = flag.Int("parallel", 1, "Number of parallel workers")
useZMQ = flag.Bool("zmq", false, "Use ZMQ transport (if available)")
verbose = flag.Bool("verbose", false, "Verbose output")
help = flag.Bool("help", false, "Show help message")
)
flag.Parse()
if *help {
printHelp()
os.Exit(0)
}
// Get network configuration
params := getNetworkParams(*network)
ctx, cancel := context.WithTimeout(context.Background(), *duration)
defer cancel()
fmt.Printf("Benchmarking %s engine(s) with %s configuration\n", *engine, *network)
fmt.Printf("Duration: %s, Blocks: %d, Parallel: %d, ZMQ: %v\n\n", *duration, *blocks, *parallel, *useZMQ)
switch *engine {
case "chain":
benchmarkChain(ctx, params, *blocks, *parallel, *verbose)
case "dag":
benchmarkDAG(ctx, params, *blocks, *parallel, *verbose)
case "all":
benchmarkChain(ctx, params, *blocks, *parallel, *verbose)
fmt.Println()
benchmarkDAG(ctx, params, *blocks, *parallel, *verbose)
default:
fmt.Fprintf(os.Stderr, "Unknown engine: %s\n", *engine)
os.Exit(1)
}
}
func printHelp() {
fmt.Println("Consensus Benchmark Tool")
fmt.Println("\nUsage: bench [options]")
fmt.Println("\nOptions:")
fmt.Println(" -engine string Engine to benchmark (default: all)")
fmt.Println(" Options: chain, dag, all")
fmt.Println(" -network string Network configuration (default: local)")
fmt.Println(" Options: mainnet, testnet, local")
fmt.Println(" -duration time Benchmark duration (default: 10s)")
fmt.Println(" -blocks int Number of blocks to process (default: 1000)")
fmt.Println(" -parallel int Number of parallel workers (default: 1)")
fmt.Println(" -zmq Use ZMQ transport if available")
fmt.Println(" -verbose Verbose output")
fmt.Println(" -help Show this help message")
fmt.Println("\nExamples:")
fmt.Println(" bench # Benchmark all engines")
fmt.Println(" bench -engine chain -blocks 5000 # Benchmark chain engine with 5000 blocks")
fmt.Println(" bench -engine dag -parallel 4 # Benchmark DAG with 4 workers")
fmt.Println(" bench -network mainnet -duration 30s # Use mainnet config for 30s")
}
func getNetworkParams(network string) config.Parameters {
switch network {
case "mainnet":
return config.MainnetParams()
case "testnet":
return config.TestnetParams()
case "local":
return config.LocalParams()
default:
fmt.Fprintf(os.Stderr, "Unknown network: %s, using local\n", network)
return config.LocalParams()
}
}
func benchmarkChain(ctx context.Context, params config.Parameters, blocks int, parallel int, verbose bool) {
fmt.Println("=== Chain Engine Benchmark ===")
engine := chain.New()
start := time.Now()
if err := engine.Start(ctx, true); err != nil {
fmt.Printf("Failed to start chain engine: %v\n", err)
return
}
processed := 0
errors := 0
for i := 0; i < blocks && ctx.Err() == nil; i++ {
blockID := ids.GenerateTestID()
err := engine.GetBlock(ctx, ids.EmptyNodeID, 0, blockID)
if err != nil {
errors++
if verbose {
fmt.Printf("Error processing block %d: %v\n", i, err)
}
} else {
processed++
}
if verbose && i%100 == 0 {
fmt.Printf("Processed %d blocks...\n", i)
}
}
elapsed := time.Since(start)
tps := float64(processed) / elapsed.Seconds()
fmt.Printf("Results:\n")
fmt.Printf(" Processed: %d blocks\n", processed)
fmt.Printf(" Errors: %d\n", errors)
fmt.Printf(" Time: %s\n", elapsed)
fmt.Printf(" TPS: %.2f blocks/sec\n", tps)
_ = engine.Stop(ctx)
}
func benchmarkDAG(ctx context.Context, params config.Parameters, blocks int, parallel int, verbose bool) {
fmt.Println("=== DAG Engine Benchmark ===")
engine := dag.New()
start := time.Now()
if err := engine.Start(ctx, 1); err != nil {
fmt.Printf("Failed to start DAG engine: %v\n", err)
return
}
processed := 0
errors := 0
for i := 0; i < blocks && ctx.Err() == nil; i++ {
vertexID := ids.GenerateTestID()
_, err := engine.GetVtx(ctx, vertexID)
if err != nil {
errors++
if verbose {
fmt.Printf("Error processing vertex %d: %v\n", i, err)
}
} else {
processed++
}
if verbose && i%100 == 0 {
fmt.Printf("Processed %d vertices...\n", i)
}
}
elapsed := time.Since(start)
tps := float64(processed) / elapsed.Seconds()
fmt.Printf("Results:\n")
fmt.Printf(" Processed: %d vertices\n", processed)
fmt.Printf(" Errors: %d\n", errors)
fmt.Printf(" Time: %s\n", elapsed)
fmt.Printf(" TPS: %.2f vertices/sec\n", tps)
_ = engine.Shutdown(ctx)
}
func init() {
// As of Go 1.20, rand.Seed is deprecated - random seeding is automatic
// No manual seeding required for better randomness
}
-133
View File
@@ -1,133 +0,0 @@
// Package main provides the checker CLI tool for consensus health checking
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"github.com/luxfi/consensus"
"github.com/luxfi/consensus/config"
)
func main() {
var (
engine = flag.String("engine", "all", "Engine to check (chain, dag, pq, all)")
timeout = flag.Duration("timeout", 5*time.Second, "Health check timeout")
verbose = flag.Bool("verbose", false, "Verbose output")
help = flag.Bool("help", false, "Show help message")
)
flag.Parse()
if *help {
printHelp()
os.Exit(0)
}
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
defer cancel()
exitCode := 0
switch *engine {
case "chain":
chain := consensus.NewChain(consensus.DefaultConfig())
if !checkEngine(ctx, "chain", chain, *verbose) {
exitCode = 1
}
case "dag":
// DAG engine not yet implemented in new API
fmt.Println("DAG engine check not yet available in new API")
case "pq":
// PQ engine not yet implemented in new API
fmt.Println("PQ engine check not yet available in new API")
case "all":
chain := consensus.NewChain(consensus.DefaultConfig())
if !checkEngine(ctx, "chain", chain, *verbose) {
exitCode = 1
}
fmt.Println("DAG and PQ engine checks not yet available in new API")
default:
fmt.Fprintf(os.Stderr, "Unknown engine: %s\n", *engine)
os.Exit(1)
}
// Check configurations
if !checkConfigurations(*verbose) {
exitCode = 1
}
if exitCode == 0 {
fmt.Println("\n✓ All health checks passed")
} else {
fmt.Println("\n✗ Some health checks failed")
}
os.Exit(exitCode)
}
func printHelp() {
fmt.Println("Consensus Health Checker")
fmt.Println("\nUsage: checker [options]")
fmt.Println("\nOptions:")
fmt.Println(" -engine string Engine to check (default: all)")
fmt.Println(" Options: chain, dag, pq, all")
fmt.Println(" -timeout duration Health check timeout (default: 5s)")
fmt.Println(" -verbose Verbose output")
fmt.Println(" -help Show this help message")
fmt.Println("\nExamples:")
fmt.Println(" checker # Check all engines")
fmt.Println(" checker -engine chain # Check only chain engine")
fmt.Println(" checker -verbose # Verbose output for debugging")
}
func checkEngine(ctx context.Context, name string, engine consensus.Engine, verbose bool) bool {
fmt.Printf("Checking %s engine... ", name)
// Start engine
if err := engine.Start(ctx); err != nil {
fmt.Printf("✗ Failed to start: %v\n", err)
return false
}
defer func() { _ = engine.Stop() }()
// Basic functionality check - just verify it started
fmt.Println("✓")
if verbose {
fmt.Printf(" Engine started successfully\n")
}
return true
}
func checkConfigurations(verbose bool) bool {
fmt.Println("\nChecking configurations...")
configs := map[string]config.Parameters{
"mainnet": config.MainnetParams(),
"testnet": config.TestnetParams(),
"local": config.LocalParams(),
"xchain": config.XChainParams(),
}
allValid := true
for name, cfg := range configs {
fmt.Printf(" %s: ", name)
if err := cfg.Valid(); err != nil {
fmt.Printf("✗ %v\n", err)
allValid = false
} else {
fmt.Println("✓")
if verbose {
fmt.Printf(" K=%d, Alpha=%.2f, Beta=%d, BlockTime=%s\n",
cfg.K, cfg.Alpha, cfg.Beta, cfg.BlockTime)
}
}
}
return allValid
}
-35
View File
@@ -1,35 +0,0 @@
package main
import (
"context"
"fmt"
"github.com/luxfi/consensus"
"github.com/luxfi/ids"
)
// run a deterministic scenario: 3 validators, `accept` of them vote Preference.
func run(accept int) bool {
cfg := consensus.DefaultConfig()
cfg.K = 3
cfg.Alpha = 2 // quorum: 2 of 3
chain := consensus.NewChain(cfg)
ctx := context.Background()
_ = chain.Start(ctx)
var bid ids.ID
bid[0] = 42
_ = chain.Add(ctx, consensus.NewBlock(bid, consensus.GenesisID, 1, []byte("conf")))
for round := 0; round < 8; round++ {
for i := 0; i < accept; i++ {
var nid ids.NodeID
nid[0] = byte(i + 1)
_ = chain.RecordVote(ctx, consensus.NewVote(bid, consensus.VotePreference, nid))
}
}
return chain.IsAccepted(bid)
}
func main() {
for _, v := range []int{3, 2, 1, 0} {
fmt.Printf("GO accept=%d/3 -> accepted=%t\n", v, run(v))
}
}
+92 -129
View File
@@ -1,156 +1,119 @@
// Package main provides the main consensus CLI tool
// Command consensus reports the consensus parameters a build ships for a
// named network, as a table or as JSON. Operators use it to see what a
// binary will actually run with, and to diff that between builds.
package main
import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"os"
"time"
"github.com/luxfi/consensus"
"github.com/luxfi/consensus/config"
)
func main() {
var (
engine = flag.String("engine", "chain", "Consensus engine (chain, dag, pq)")
network = flag.String("network", "mainnet", "Network configuration")
action = flag.String("action", "info", "Action to perform (info, test, health)")
help = flag.Bool("help", false, "Show help message")
)
flag.Parse()
if *help {
printHelp()
os.Exit(0)
os.Exit(run(os.Args[1:], os.Stdout, os.Stderr))
}
switch *action {
case "info":
showInfo(*engine, *network)
case "test":
testEngine(*engine, *network)
case "health":
checkHealth(*engine)
default:
fmt.Fprintf(os.Stderr, "Unknown action: %s\n", *action)
os.Exit(1)
func run(args []string, out, errOut io.Writer) int {
fs := flag.NewFlagSet("consensus", flag.ContinueOnError)
fs.SetOutput(errOut)
network := fs.String("network", "mainnet", "network to report: mainnet, testnet, local")
asJSON := fs.Bool("json", false, "report as JSON instead of a table")
if err := fs.Parse(args); err != nil {
if errors.Is(err, flag.ErrHelp) {
return 0
}
return 2
}
func printHelp() {
fmt.Println("Lux Consensus CLI")
fmt.Println("\nUsage: consensus [options]")
fmt.Println("\nOptions:")
fmt.Println(" -engine string Consensus engine (default: chain)")
fmt.Println(" Options: chain, dag, pq")
fmt.Println(" -network string Network configuration (default: mainnet)")
fmt.Println(" Options: mainnet, testnet, local")
fmt.Println(" -action string Action to perform (default: info)")
fmt.Println(" Options: info, test, health")
fmt.Println(" -help Show this help message")
fmt.Println("\nExamples:")
fmt.Println(" consensus # Show chain engine info")
fmt.Println(" consensus -engine dag -action test # Test DAG engine")
fmt.Println(" consensus -action health # Check engine health")
p, ok := paramsFor(*network)
if !ok {
fmt.Fprintf(errOut, "unknown network %q: want mainnet, testnet or local\n", *network)
return 1
}
func showInfo(engineType, network string) {
fmt.Printf("=== Consensus Engine Info ===\n")
fmt.Printf("Engine: %s\n", engineType)
fmt.Printf("Network: %s\n", network)
params := getNetworkParams(network)
fmt.Printf("\nParameters:\n")
fmt.Printf(" K (sample size): %d\n", params.K)
fmt.Printf(" Alpha (quorum): %.2f\n", params.Alpha)
fmt.Printf(" Beta (decision rounds): %d\n", params.Beta)
fmt.Printf(" Block Time: %s\n", params.BlockTime)
fmt.Printf(" Round Timeout: %s\n", params.RoundTO)
switch engineType {
case "chain":
fmt.Println("\nChain Engine:")
fmt.Println(" - Linear blockchain consensus")
fmt.Println(" - Sequential block processing")
fmt.Println(" - Optimized for ordered transactions")
case "dag":
fmt.Println("\nDAG Engine:")
fmt.Println(" - Directed Acyclic Graph consensus")
fmt.Println(" - Parallel transaction processing")
fmt.Println(" - High throughput optimization")
case "pq":
fmt.Println("\nPost-Quantum Engine:")
fmt.Println(" - Quantum-resistant cryptography")
fmt.Println(" - ML-DSA-65 algorithm")
fmt.Println(" - Future-proof security")
write := writeTable
if *asJSON {
write = writeJSON
}
if err := write(out, fields(p)); err != nil {
fmt.Fprintln(errOut, err)
return 1
}
return 0
}
func testEngine(engineType, network string) {
fmt.Printf("Testing %s engine with %s configuration...\n", engineType, network)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
switch engineType {
case "chain":
engine := consensus.NewChain(consensus.DefaultConfig())
// Start engine
if err := engine.Start(ctx); err != nil {
fmt.Printf("✗ Failed to start: %v\n", err)
os.Exit(1)
}
defer func() { _ = engine.Stop() }()
fmt.Println("✓ Engine test passed")
fmt.Printf(" Engine started successfully\n")
case "dag":
fmt.Println("DAG engine not yet implemented in new API")
case "pq":
fmt.Println("PQ engine not yet implemented in new API")
default:
fmt.Fprintf(os.Stderr, "Unknown engine: %s\n", engineType)
os.Exit(1)
}
}
func checkHealth(engineType string) {
fmt.Printf("Checking %s engine health...\n", engineType)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
switch engineType {
case "chain":
engine := consensus.NewChain(consensus.DefaultConfig())
// Start engine
if err := engine.Start(ctx); err != nil {
fmt.Printf("✗ Failed to start: %v\n", err)
os.Exit(1)
}
defer func() { _ = engine.Stop() }()
fmt.Println("✓ Healthy")
fmt.Printf(" Engine started successfully\n")
case "dag":
fmt.Println("DAG engine not yet implemented in new API")
case "pq":
fmt.Println("PQ engine not yet implemented in new API")
default:
fmt.Fprintf(os.Stderr, "Unknown engine: %s\n", engineType)
os.Exit(1)
}
}
func getNetworkParams(network string) config.Parameters {
// paramsFor reports whether the network is one this build knows. An unknown
// name is refused rather than defaulted, so a typo cannot quietly print some
// other network's parameters while the operator reads them as the one asked for.
//
// config.XChainParams is deliberately absent: it returns a value identical to
// LocalParams, so offering it as a fourth name would answer the same question
// twice and no test could tell the two apart.
func paramsFor(network string) (config.Parameters, bool) {
switch network {
case "mainnet":
return config.MainnetParams()
return config.MainnetParams(), true
case "testnet":
return config.TestnetParams()
return config.TestnetParams(), true
case "local":
return config.LocalParams()
default:
return config.MainnetParams()
return config.LocalParams(), true
}
return config.Parameters{}, false
}
type field struct {
name string
value any
}
// fields is the single ordered description of a report, so the table and the
// JSON cannot drift apart in content. Durations and PQMode render through
// String so both formats carry the same human-readable value.
func fields(p config.Parameters) []field {
return []field{
{"k", p.K},
{"alpha", p.Alpha},
{"beta", p.Beta},
{"alphaPreference", p.AlphaPreference},
{"alphaConfidence", p.AlphaConfidence},
{"betaVirtuous", p.BetaVirtuous},
{"betaRogue", p.BetaRogue},
{"concurrentPolls", p.ConcurrentPolls},
{"concurrentRepolls", p.ConcurrentRepolls},
{"optimalProcessing", p.OptimalProcessing},
{"maxOutstandingItems", p.MaxOutstandingItems},
{"maxItemProcessingTime", p.MaxItemProcessingTime.String()},
{"parents", p.Parents},
{"batchSize", p.BatchSize},
{"blockTime", p.BlockTime.String()},
{"roundTimeout", p.RoundTO.String()},
{"convergenceSettleWindow", p.ConvergenceSettleWindow.String()},
{"gasLimit", p.GasLimit},
{"pqMode", p.PQMode.String()},
}
}
func writeTable(w io.Writer, fs []field) error {
for _, f := range fs {
if _, err := fmt.Fprintf(w, "%-24s %v\n", f.name, f.value); err != nil {
return err
}
}
return nil
}
func writeJSON(w io.Writer, fs []field) error {
m := make(map[string]any, len(fs))
for _, f := range fs {
m[f.name] = f.value
}
e := json.NewEncoder(w)
e.SetIndent("", " ")
return e.Encode(m)
}
+157 -82
View File
@@ -2,105 +2,180 @@ package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
"strings"
"testing"
"github.com/luxfi/consensus/config"
)
func TestRun(t *testing.T) {
tests := []struct {
name string
args []string
want string
wantErr bool
}{
{
name: "default run",
args: []string{},
want: "Starting consensus simulation",
},
{
name: "with nodes",
args: []string{"-nodes", "5"},
want: "nodes=5",
},
{
name: "with rounds",
args: []string{"-rounds", "100"},
want: "rounds=100",
},
{
name: "with alpha",
args: []string{"-alpha", "0.7"},
want: "alpha=0.7",
},
{
name: "with beta",
args: []string{"-beta", "10"},
want: "beta=10",
},
{
name: "all params",
args: []string{"-nodes", "21", "-rounds", "50", "-alpha", "0.8", "-beta", "15"},
want: "nodes=21",
},
// An unknown network must be refused, not silently answered with some other
// network's numbers. Breaks if paramsFor grows a default arm.
func TestUnknownNetworkIsRefused(t *testing.T) {
var out, errOut bytes.Buffer
if code := run([]string{"-network", "mianet"}, &out, &errOut); code != 1 {
t.Fatalf("exit = %d, want 1", code)
}
if out.Len() != 0 {
t.Errorf("stdout = %q, want empty: a refused network must report no parameters", out.String())
}
if !strings.Contains(errOut.String(), "mianet") {
t.Errorf("stderr = %q, want it to name the rejected network", errOut.String())
}
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Capture output
var buf bytes.Buffer
oldArgs := make([]string, len(tt.args))
copy(oldArgs, tt.args)
// Mock the run (since we can't actually execute main)
output := simulateRun(tt.args)
buf.WriteString(output)
got := buf.String()
if !strings.Contains(got, tt.want) && !tt.wantErr {
t.Errorf("run() output = %v, want substring %v", got, tt.want)
// Each name must reach its own constructor. Breaks if a network is wired to
// the wrong one, because the three differ in K, Beta and BlockTime.
func TestNetworkReachesItsOwnParameters(t *testing.T) {
for name, want := range map[string]config.Parameters{
"mainnet": config.MainnetParams(),
"testnet": config.TestnetParams(),
"local": config.LocalParams(),
} {
t.Run(name, func(t *testing.T) {
var out, errOut bytes.Buffer
if code := run([]string{"-network", name, "-json"}, &out, &errOut); code != 0 {
t.Fatalf("exit = %d (stderr %q), want 0", code, errOut.String())
}
got := decode(t, out.Bytes())
for _, f := range fields(want) {
if got[f.name] != fmt.Sprint(f.value) {
t.Errorf("%s = %q, want %q", f.name, got[f.name], fmt.Sprint(f.value))
}
}
})
}
}
// simulateRun simulates the main function behavior
func simulateRun(args []string) string {
var output strings.Builder
output.WriteString("Starting consensus simulation\n")
// The two formats are rendered by different code from one description, so this
// pins that they cannot drift: same names, same values, nothing dropped.
func TestTableAndJSONAgree(t *testing.T) {
var tbl, js, errOut bytes.Buffer
if code := run([]string{"-network", "mainnet"}, &tbl, &errOut); code != 0 {
t.Fatalf("table exit = %d", code)
}
if code := run([]string{"-network", "mainnet", "-json"}, &js, &errOut); code != 0 {
t.Fatalf("json exit = %d", code)
}
// Parse args
nodes := 10
rounds := 20
alpha := 0.8
beta := uint32(15)
for i := 0; i < len(args); i++ {
switch args[i] {
case "-nodes":
if i+1 < len(args) {
output.WriteString("nodes=" + args[i+1] + "\n")
fromJSON := decode(t, js.Bytes())
lines := strings.Split(strings.TrimRight(tbl.String(), "\n"), "\n")
if len(lines) != len(fromJSON) {
t.Fatalf("table has %d rows, JSON has %d keys", len(lines), len(fromJSON))
}
case "-rounds":
if i+1 < len(args) {
output.WriteString("rounds=" + args[i+1] + "\n")
for _, line := range lines {
name, value, ok := strings.Cut(strings.TrimSpace(line), " ")
if !ok {
t.Fatalf("row %q has no value", line)
}
case "-alpha":
if i+1 < len(args) {
output.WriteString("alpha=" + args[i+1] + "\n")
}
case "-beta":
if i+1 < len(args) {
output.WriteString("beta=" + args[i+1] + "\n")
if got, want := strings.TrimSpace(value), fromJSON[name]; got != want {
t.Errorf("%s: table %q, JSON %q", name, got, want)
}
}
}
output.WriteString("Configuration:\n")
output.WriteString(" Nodes: " + string(rune(nodes)) + "\n")
output.WriteString(" Rounds: " + string(rune(rounds)) + "\n")
output.WriteString(" Alpha: " + string(rune(int(alpha*10))) + "\n")
output.WriteString(" Beta: " + string(rune(beta)) + "\n")
// The exit code is the tool's contract with a shell. Breaks if -h starts
// reporting failure, or a bad flag starts reporting success.
func TestExitCodes(t *testing.T) {
for _, tt := range []struct {
name string
args []string
want int
}{
{"default is mainnet", nil, 0},
{"help", []string{"-h"}, 0},
{"unknown network", []string{"-network", "nope"}, 1},
{"unknown flag", []string{"-verbose"}, 2},
} {
t.Run(tt.name, func(t *testing.T) {
var out, errOut bytes.Buffer
if code := run(tt.args, &out, &errOut); code != tt.want {
t.Errorf("exit = %d, want %d", code, tt.want)
}
})
}
}
return output.String()
// A report that could not be written is a failure, not a silent success —
// otherwise `consensus > /full/disk` exits 0 having produced nothing.
func TestWriteFailureIsReported(t *testing.T) {
for _, args := range [][]string{{}, {"-json"}} {
var errOut bytes.Buffer
if code := run(args, brokenWriter{}, &errOut); code != 1 {
t.Errorf("run(%v) exit = %d, want 1", args, code)
}
if !strings.Contains(errOut.String(), "disk full") {
t.Errorf("run(%v) stderr = %q, want the write error", args, errOut.String())
}
}
}
type brokenWriter struct{}
func (brokenWriter) Write([]byte) (int, error) { return 0, errors.New("disk full") }
// main is what a shell actually runs, so it is exercised as a process: the
// test binary re-executes itself and reads the code it exits with. Breaks if
// os.Exit is dropped (a refused network would then look successful to a
// script) or if os.Args reaches run unsliced (the program name would parse
// as a flag and every invocation would fail).
func TestMainExitsWithRunsCode(t *testing.T) {
if args, child := os.LookupEnv(childArgs); child {
os.Args = append([]string{"consensus"}, strings.Fields(args)...)
main()
return
}
for _, tt := range []struct {
name string
args string
want int
}{
{"known network", "-network local", 0},
{"unknown network", "-network nope", 1},
} {
t.Run(tt.name, func(t *testing.T) {
cmd := exec.Command(os.Args[0], "-test.run=TestMainExitsWithRunsCode")
cmd.Env = append(os.Environ(), childArgs+"="+tt.args)
out, err := cmd.Output()
got := 0
var exit *exec.ExitError
if errors.As(err, &exit) {
got = exit.ExitCode()
} else if err != nil {
t.Fatalf("running child: %v", err)
}
if got != tt.want {
t.Fatalf("exit = %d, want %d (stdout %q)", got, tt.want, out)
}
if wantReport := tt.want == 0; wantReport != strings.Contains(string(out), "k ") {
t.Errorf("stdout = %q, report on stdout should be %v", out, wantReport)
}
})
}
}
// childArgs carries the command line into the re-executed test binary.
const childArgs = "CONSENSUS_TEST_ARGS"
// decode renders the JSON report as name -> literal text, so values compare
// against fmt.Sprint of the source field without float round-tripping.
func decode(t *testing.T, b []byte) map[string]string {
t.Helper()
d := json.NewDecoder(bytes.NewReader(b))
d.UseNumber()
var raw map[string]any
if err := d.Decode(&raw); err != nil {
t.Fatalf("report is not JSON: %v", err)
}
out := make(map[string]string, len(raw))
for k, v := range raw {
out[k] = fmt.Sprint(v)
}
return out
}
-123
View File
@@ -1,123 +0,0 @@
// Package main provides the params CLI tool for viewing consensus network parameters
package main
import (
"flag"
"fmt"
"os"
"github.com/luxfi/consensus/config"
)
func main() {
var (
network = flag.String("network", "mainnet", "Network to show parameters for (mainnet, testnet, local, xchain)")
json = flag.Bool("json", false, "Output in JSON format")
help = flag.Bool("help", false, "Show help message")
)
flag.Parse()
if *help {
printHelp()
os.Exit(0)
}
var params config.Parameters
switch *network {
case "mainnet":
params = config.MainnetParams()
case "testnet":
params = config.TestnetParams()
case "local":
params = config.LocalParams()
case "xchain":
params = config.XChainParams()
default:
fmt.Fprintf(os.Stderr, "Unknown network: %s\n", *network)
fmt.Fprintln(os.Stderr, "Valid networks: mainnet, testnet, local, xchain")
os.Exit(1)
}
if *json {
printJSON(params)
} else {
printTable(params)
}
}
func printHelp() {
fmt.Println("Consensus Parameters Viewer")
fmt.Println("\nUsage: params [options]")
fmt.Println("\nOptions:")
fmt.Println(" -network string Network to show parameters for (default: mainnet)")
fmt.Println(" Options: mainnet, testnet, local, xchain")
fmt.Println(" -json Output in JSON format")
fmt.Println(" -help Show this help message")
fmt.Println("\nExamples:")
fmt.Println(" params # Show mainnet parameters")
fmt.Println(" params -network testnet # Show testnet parameters")
fmt.Println(" params -network local -json # Show local parameters in JSON")
}
func printTable(p config.Parameters) {
fmt.Printf("K (sample size): %d\n", p.K)
fmt.Printf("Alpha (quorum): %.2f\n", p.Alpha)
fmt.Printf("Beta (decision rounds): %d\n", p.Beta)
fmt.Printf("Block Time: %s\n", p.BlockTime)
fmt.Printf("Round Timeout: %s\n", p.RoundTO)
if p.AlphaPreference > 0 {
fmt.Printf("Alpha Preference: %d\n", p.AlphaPreference)
}
if p.AlphaConfidence > 0 {
fmt.Printf("Alpha Confidence: %d\n", p.AlphaConfidence)
}
if p.BetaVirtuous > 0 {
fmt.Printf("Beta Virtuous: %d\n", p.BetaVirtuous)
}
if p.BetaRogue > 0 {
fmt.Printf("Beta Rogue: %d\n", p.BetaRogue)
}
if p.ConcurrentPolls > 0 {
fmt.Printf("Concurrent Polls: %d\n", p.ConcurrentPolls)
}
if p.ConcurrentRepolls > 0 {
fmt.Printf("Concurrent Repolls: %d\n", p.ConcurrentRepolls)
}
if p.OptimalProcessing > 0 {
fmt.Printf("Optimal Processing: %d\n", p.OptimalProcessing)
}
if p.MaxOutstandingItems > 0 {
fmt.Printf("Max Outstanding Items: %d\n", p.MaxOutstandingItems)
}
if p.Parents > 0 {
fmt.Printf("Parents: %d\n", p.Parents)
}
if p.BatchSize > 0 {
fmt.Printf("Batch Size: %d\n", p.BatchSize)
}
}
func printJSON(p config.Parameters) {
fmt.Printf(`{
"k": %d,
"alpha": %.2f,
"beta": %d,
"blockTime": "%s",
"roundTimeout": "%s",
"alphaPreference": %d,
"alphaConfidence": %d,
"betaVirtuous": %d,
"betaRogue": %d,
"concurrentPolls": %d,
"concurrentRepolls": %d,
"optimalProcessing": %d,
"maxOutstandingItems": %d,
"parents": %d,
"batchSize": %d
}
`, p.K, p.Alpha, p.Beta, p.BlockTime, p.RoundTO,
p.AlphaPreference, p.AlphaConfidence, p.BetaVirtuous, p.BetaRogue,
p.ConcurrentPolls, p.ConcurrentRepolls, p.OptimalProcessing,
p.MaxOutstandingItems, p.Parents, p.BatchSize)
}
-252
View File
@@ -1,252 +0,0 @@
package main
import (
"context"
"encoding/json"
"flag"
"log"
"net/http"
"time"
"github.com/luxfi/consensus"
"github.com/luxfi/consensus/config"
"github.com/luxfi/ids"
)
type ConsensusServer struct {
engine consensus.Engine
config config.Parameters
}
type StatusResponse struct {
Engine string `json:"engine"`
Network string `json:"network"`
Healthy bool `json:"healthy"`
Parameters config.Parameters `json:"parameters"`
Health interface{} `json:"health,omitempty"`
}
type TestRequest struct {
Rounds int `json:"rounds"`
Nodes int `json:"nodes"`
}
type TestResponse struct {
Success bool `json:"success"`
Rounds int `json:"rounds"`
Accepts int `json:"accepts"`
Rejects int `json:"rejects"`
AvgTime string `json:"avg_time"`
Confidence float64 `json:"confidence"`
}
func (s *ConsensusServer) handleStatus(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
health := make(map[string]interface{})
health["healthy"] = true
if adapter, ok := s.engine.(interface {
HealthCheck(context.Context) (interface{}, error)
}); ok {
if h, err := adapter.HealthCheck(ctx); err == nil {
if healthMap, ok := h.(map[string]interface{}); ok {
health = healthMap
} else if healthBoolMap, ok := h.(map[string]bool); ok {
for k, v := range healthBoolMap {
health[k] = v
}
}
}
}
healthy := true
if val, ok := health["healthy"].(bool); ok {
healthy = val
}
resp := StatusResponse{
Engine: "chain",
Network: "mainnet",
Healthy: healthy,
Parameters: s.config,
Health: health,
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
log.Printf("Error encoding response: %v", err)
}
}
func (s *ConsensusServer) handleTest(w http.ResponseWriter, r *http.Request) {
var req TestRequest
if r.Method == http.MethodPost {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
} else {
req.Rounds = 10
req.Nodes = 5
}
// Run simple consensus test
accepts := 0
rejects := 0
totalTime := time.Duration(0)
for i := 0; i < req.Rounds; i++ {
start := time.Now()
// Simulate consensus round
blockID := ids.GenerateTestID()
// Simulate votes from nodes
acceptVotes := 0
for j := 0; j < req.Nodes; j++ {
if j < (req.Nodes * 8 / 10) { // 80% vote to accept
acceptVotes++
}
}
if float64(acceptVotes)/float64(req.Nodes) >= s.config.Alpha {
accepts++
} else {
rejects++
}
totalTime += time.Since(start)
// Log the vote
log.Printf("Round %d: BlockID=%s, Accept=%d/%d\n", i+1, blockID, acceptVotes, req.Nodes)
}
avgTime := totalTime / time.Duration(req.Rounds)
confidence := float64(accepts) / float64(req.Rounds)
resp := TestResponse{
Success: true,
Rounds: req.Rounds,
Accepts: accepts,
Rejects: rejects,
AvgTime: avgTime.String(),
Confidence: confidence * 100,
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
log.Printf("Error encoding response: %v", err)
}
}
func (s *ConsensusServer) handleConsensus(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req struct {
BlockID string `json:"block_id"`
Votes map[string]int `json:"votes"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Process consensus
blockID, err := ids.FromString(req.BlockID)
if err != nil {
blockID = ids.GenerateTestID()
}
// Calculate if consensus reached
totalVotes := 0
acceptVotes := 0
for _, count := range req.Votes {
totalVotes += count
if count > 0 {
acceptVotes += count
}
}
finalized := false
if totalVotes > 0 {
confidence := float64(acceptVotes) / float64(totalVotes)
finalized = confidence >= s.config.Alpha
}
resp := map[string]interface{}{
"block_id": blockID.String(),
"finalized": finalized,
"votes": req.Votes,
"confidence": float64(acceptVotes) / float64(totalVotes) * 100,
"alpha": s.config.Alpha * 100,
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
log.Printf("Error encoding response: %v", err)
}
}
func main() {
var (
port = flag.String("port", "8080", "Server port")
network = flag.String("network", "mainnet", "Network configuration")
)
flag.Parse()
// Initialize consensus engine
engine := consensus.NewChainEngine()
var params config.Parameters
switch *network {
case "testnet":
params = config.TestnetParams()
case "local":
params = config.LocalParams()
default:
params = config.MainnetParams()
}
server := &ConsensusServer{
engine: engine,
config: params,
}
// Set up routes
mux := http.NewServeMux()
mux.HandleFunc("/status", server.handleStatus)
mux.HandleFunc("/test", server.handleTest)
mux.HandleFunc("/consensus", server.handleConsensus)
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte("OK")); err != nil {
log.Printf("Error writing response: %v", err)
}
})
log.Printf("Starting consensus server on port %s with %s config", *port, *network)
log.Printf("Endpoints:")
log.Printf(" GET /status - Get engine status")
log.Printf(" GET /health - Health check")
log.Printf(" GET /test - Run consensus test")
log.Printf(" POST /test - Run consensus test with custom params")
log.Printf(" POST /consensus - Process consensus round")
// Create server with timeouts to avoid G114 warning
srv := &http.Server{
Addr: ":" + *port,
Handler: mux,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
IdleTimeout: 60 * time.Second,
}
if err := srv.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
-212
View File
@@ -1,212 +0,0 @@
// Package main provides the sim CLI tool for consensus simulation
package main
import (
"context"
"flag"
"fmt"
"math/rand"
"os"
"time"
"github.com/luxfi/consensus/config"
)
func main() {
var (
nodes = flag.Int("nodes", 100, "Number of nodes in the network")
rounds = flag.Int("rounds", 10, "Number of consensus rounds to simulate")
network = flag.String("network", "mainnet", "Network configuration (mainnet, testnet, local)")
failure = flag.Float64("failure", 0.1, "Node failure rate (0.0-1.0)")
latency = flag.Duration("latency", 50*time.Millisecond, "Network latency")
verbose = flag.Bool("verbose", false, "Verbose output")
help = flag.Bool("help", false, "Show help message")
)
flag.Parse()
if *help {
printHelp()
os.Exit(0)
}
if *failure < 0 || *failure > 1 {
fmt.Fprintf(os.Stderr, "Failure rate must be between 0.0 and 1.0\n")
os.Exit(1)
}
// Get network configuration
params := getNetworkParams(*network)
fmt.Println("=== Consensus Simulation ===")
fmt.Printf("Network: %s\n", *network)
fmt.Printf("Nodes: %d\n", *nodes)
fmt.Printf("Rounds: %d\n", *rounds)
fmt.Printf("Failure: %.1f%%\n", *failure*100)
fmt.Printf("Latency: %s\n", *latency)
fmt.Printf("Parameters: K=%d, Alpha=%.2f, Beta=%d\n\n", params.K, params.Alpha, params.Beta)
// Run simulation
results := runSimulation(*nodes, *rounds, params, *failure, *latency, *verbose)
// Print results
printResults(results, params)
}
func printHelp() {
fmt.Println("Consensus Simulator")
fmt.Println("\nUsage: sim [options]")
fmt.Println("\nOptions:")
fmt.Println(" -nodes int Number of nodes in the network (default: 100)")
fmt.Println(" -rounds int Number of consensus rounds (default: 10)")
fmt.Println(" -network string Network configuration (default: mainnet)")
fmt.Println(" Options: mainnet, testnet, local")
fmt.Println(" -failure float Node failure rate 0.0-1.0 (default: 0.1)")
fmt.Println(" -latency duration Network latency (default: 50ms)")
fmt.Println(" -verbose Verbose output")
fmt.Println(" -help Show this help message")
fmt.Println("\nExamples:")
fmt.Println(" sim # Run default simulation")
fmt.Println(" sim -nodes 1000 -rounds 100 # Large scale simulation")
fmt.Println(" sim -failure 0.3 -latency 200ms # High failure, slow network")
fmt.Println(" sim -network testnet -verbose # Testnet config with details")
}
func getNetworkParams(network string) config.Parameters {
switch network {
case "mainnet":
return config.MainnetParams()
case "testnet":
return config.TestnetParams()
case "local":
return config.LocalParams()
default:
fmt.Fprintf(os.Stderr, "Unknown network: %s, using mainnet\n", network)
return config.MainnetParams()
}
}
type SimulationResult struct {
Round int
VotesReceived int
Confidence float64
Decision string
TimeToConsensus time.Duration
FailedNodes int
}
func runSimulation(nodes int, rounds int, params config.Parameters, failureRate float64, latency time.Duration, verbose bool) []SimulationResult {
results := make([]SimulationResult, 0, rounds)
ctx := context.Background()
for round := 1; round <= rounds; round++ {
if verbose {
fmt.Printf("Round %d: ", round)
}
start := time.Now()
result := simulateRound(ctx, nodes, params, failureRate, latency)
result.Round = round
result.TimeToConsensus = time.Since(start)
if verbose {
fmt.Printf("%s (confidence: %.2f%%, time: %s)\n",
result.Decision, result.Confidence*100, result.TimeToConsensus)
}
results = append(results, result)
// Simulate inter-round delay
time.Sleep(latency)
}
return results
}
func simulateRound(ctx context.Context, nodes int, params config.Parameters, failureRate float64, latency time.Duration) SimulationResult {
// Calculate failed nodes
failedNodes := int(float64(nodes) * failureRate)
activeNodes := nodes - failedNodes
// Sample K nodes randomly
k := params.K
if k > activeNodes {
k = activeNodes
}
// Simulate voting
votes := 0
for i := 0; i < k; i++ {
// Simulate network latency
time.Sleep(latency / time.Duration(k))
// Random vote with Byzantine behavior (simulation only, not security-critical)
if rand.Float64() > 0.2 { // 80% honest nodes //nolint:gosec // simulation randomness
votes++
}
}
// Calculate confidence
confidence := float64(votes) / float64(k)
// Determine decision based on alpha threshold
decision := "REJECT"
if confidence >= params.Alpha {
decision = "ACCEPT"
}
return SimulationResult{
VotesReceived: votes,
Confidence: confidence,
Decision: decision,
FailedNodes: failedNodes,
}
}
func printResults(results []SimulationResult, params config.Parameters) {
fmt.Println("=== Simulation Results ===")
accepts := 0
rejects := 0
totalTime := time.Duration(0)
totalConfidence := 0.0
for _, r := range results {
if r.Decision == "ACCEPT" {
accepts++
} else {
rejects++
}
totalTime += r.TimeToConsensus
totalConfidence += r.Confidence
}
fmt.Printf("\nConsensus Decisions:\n")
fmt.Printf(" Accepts: %d (%.1f%%)\n", accepts, float64(accepts)/float64(len(results))*100)
fmt.Printf(" Rejects: %d (%.1f%%)\n", rejects, float64(rejects)/float64(len(results))*100)
fmt.Printf("\nPerformance:\n")
fmt.Printf(" Avg Time: %s\n", totalTime/time.Duration(len(results)))
fmt.Printf(" Avg Confidence: %.2f%%\n", totalConfidence/float64(len(results))*100)
fmt.Printf(" Alpha Required: %.2f%%\n", params.Alpha*100)
// Calculate finality probability
finalityProb := calculateFinalityProbability(params.Alpha, params.Beta, totalConfidence/float64(len(results)))
fmt.Printf("\nFinality:\n")
fmt.Printf(" Probability: %.4f%%\n", finalityProb*100)
fmt.Printf(" Beta Rounds: %d\n", params.Beta)
}
func calculateFinalityProbability(alpha float64, beta uint32, avgConfidence float64) float64 {
// Simplified finality calculation
// P(finality) = confidence^beta
prob := 1.0
for i := uint32(0); i < beta; i++ {
prob *= avgConfidence
}
return prob
}
func init() {
// As of Go 1.20, rand.Seed is deprecated - random seeding is automatic
// No manual seeding required for better randomness
}
-32
View File
@@ -1,32 +0,0 @@
#!/bin/bash
# Temporary build script to work around node package issues
echo "Building consensus tools..."
# Build params (should work)
echo "Building params..."
go build -o bin/params ./cmd/params || echo "❌ Failed to build params"
# Build checker (should work)
echo "Building checker..."
go build -o bin/checker ./cmd/checker || echo "❌ Failed to build checker"
# Build sim (should work)
echo "Building simulator..."
go build -o bin/sim ./cmd/sim || echo "❌ Failed to build sim"
# Try to build zmq-bench standalone
echo "Building zmq-bench..."
cd cmd/zmq-bench
go build -tags zmq -o ../../bin/zmq-bench . || echo "⚠️ Failed to build zmq-bench"
cd ../..
# Build consensus CLI
echo "Building consensus CLI..."
cd cmd/consensus
go mod tidy
go build -o ../../bin/consensus . || echo "⚠️ Failed to build consensus CLI"
cd ../..
echo "✅ Build complete! Successfully built tools are in bin/"
ls -la bin/ 2>/dev/null || echo "No binaries built successfully"
-35
View File
@@ -1,35 +0,0 @@
#!/bin/bash
# Distributed multi-machine benchmark setup
set -e
# Configuration
MODE=${1:-coordinator} # coordinator or worker
COORDINATOR_IP=${2:-localhost}
COORDINATOR_PORT=${3:-5555}
NODES=${4:-100}
ROUNDS=${5:-1000}
if [ "$MODE" = "coordinator" ]; then
echo "🎯 Starting as COORDINATOR"
echo " Bind address: tcp://*:$COORDINATOR_PORT"
echo " Total nodes: $NODES"
echo " Rounds: $ROUNDS"
echo ""
echo "Workers should connect to: tcp://$(hostname -I | awk '{print $1}'):$COORDINATOR_PORT"
echo ""
./bin/consensus benchmark \
--transport zmq \
--zmq-bind "tcp://*:$COORDINATOR_PORT" \
--nodes $NODES \
--rounds $ROUNDS
else
echo "🔗 Starting as WORKER"
echo " Connecting to: tcp://$COORDINATOR_IP:$COORDINATOR_PORT"
echo ""
./bin/consensus benchmark \
--transport zmq \
--zmq-bind "tcp://$COORDINATOR_IP:$COORDINATOR_PORT"
fi
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
# Multi-node benchmark setup script
set -e
# Configuration
NODES=${1:-10}
BASE_PORT=${2:-30000}
BATCH_SIZE=${3:-4096}
INTERVAL=${4:-5ms}
ROUNDS=${5:-100}
echo "🚀 Starting $NODES-node consensus benchmark network"
echo " Base port: $BASE_PORT"
echo " Batch size: $BATCH_SIZE"
echo " Interval: $INTERVAL"
echo " Rounds: $ROUNDS"
echo ""
# Build the benchmark tool if needed
if [ ! -f bin/zmq-bench ]; then
echo "Building zmq-bench..."
make zmq-bench
fi
# Kill any existing zmq-bench processes
echo "Cleaning up any existing processes..."
pkill -f zmq-bench || true
sleep 1
# Start the benchmark
echo "Starting benchmark with $NODES nodes..."
./bin/zmq-bench \
-nodes $NODES \
-port $BASE_PORT \
-batch $BATCH_SIZE \
-interval $INTERVAL \
-rounds $ROUNDS
echo ""
echo "Benchmark complete!"
-39
View File
@@ -1,39 +0,0 @@
#!/bin/bash
# Run consensus benchmarks with different node counts
echo "Lux Consensus Benchmarks"
echo "========================"
echo ""
# Test with different node counts
for nodes in 5 10 15 20; do
echo "Testing with $nodes nodes:"
echo "-------------------------"
# Run simulation with local parameters
echo "Simulation test:"
./bin/sim -network local -nodes $nodes -rounds 100 -sims 10
echo ""
echo "Parameter analysis for $nodes nodes:"
./bin/params -nodes $nodes -summary
echo ""
echo "Safety check for $nodes nodes:"
./bin/checker -network local -nodes $nodes -analyze
echo ""
echo "=================================="
echo ""
done
# Test high TPS configuration
echo "High TPS Configuration Test:"
echo "---------------------------"
./bin/params -preset hightps -check
echo ""
./bin/sim -network hightps -nodes 10 -rounds 100 -sims 10
echo ""
echo "Benchmark complete!"
-118
View File
@@ -1,118 +0,0 @@
#!/bin/bash
# Test all CLI tools comprehensively
set -e
echo "==========================================="
echo " Lux Consensus Tools Test Suite"
echo "==========================================="
echo ""
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
# Test counter
TESTS_PASSED=0
TESTS_FAILED=0
# Test function
run_test() {
local test_name="$1"
local command="$2"
echo -n "Testing $test_name... "
if $command > /dev/null 2>&1; then
echo -e "${GREEN}✓${NC}"
((TESTS_PASSED++))
else
echo -e "${RED}✗${NC}"
echo " Failed command: $command"
((TESTS_FAILED++))
fi
}
echo "1. Testing bench tool"
echo "------------------------"
run_test "bench help" "./bin/bench -help"
run_test "bench chain engine" "./bin/bench -engine chain -blocks 10 -duration 1s"
run_test "bench dag engine" "./bin/bench -engine dag -blocks 10 -duration 1s"
run_test "bench pq engine" "./bin/bench -engine pq -blocks 10 -duration 1s"
run_test "bench all engines" "./bin/bench -engine all -blocks 5 -duration 1s"
run_test "bench with parallel" "./bin/bench -engine chain -parallel 2 -blocks 10"
run_test "bench mainnet config" "./bin/bench -network mainnet -blocks 5"
run_test "bench testnet config" "./bin/bench -network testnet -blocks 5"
run_test "bench local config" "./bin/bench -network local -blocks 5"
echo ""
echo "2. Testing checker tool"
echo "------------------------"
run_test "checker help" "./bin/checker -help"
run_test "checker all engines" "./bin/checker -engine all"
run_test "checker chain engine" "./bin/checker -engine chain"
run_test "checker dag engine" "./bin/checker -engine dag"
run_test "checker pq engine" "./bin/checker -engine pq"
run_test "checker with timeout" "./bin/checker -timeout 10s"
run_test "checker verbose" "./bin/checker -verbose"
echo ""
echo "3. Testing sim tool"
echo "------------------------"
run_test "sim help" "./bin/sim -help"
run_test "sim default" "./bin/sim -nodes 10 -rounds 2"
run_test "sim local network" "./bin/sim -nodes 5 -rounds 2 -network local"
run_test "sim testnet" "./bin/sim -nodes 11 -rounds 2 -network testnet"
run_test "sim mainnet" "./bin/sim -nodes 21 -rounds 2 -network mainnet"
run_test "sim with failure" "./bin/sim -nodes 10 -rounds 2 -failure 0.3"
run_test "sim with latency" "./bin/sim -nodes 10 -rounds 2 -latency 100ms"
run_test "sim large scale" "./bin/sim -nodes 100 -rounds 1"
run_test "sim verbose" "./bin/sim -nodes 5 -rounds 1 -verbose"
echo ""
echo "4. Testing consensus tool"
echo "------------------------"
run_test "consensus help" "./bin/consensus -help"
run_test "consensus info chain" "./bin/consensus -engine chain -action info"
run_test "consensus info dag" "./bin/consensus -engine dag -action info"
run_test "consensus info pq" "./bin/consensus -engine pq -action info"
run_test "consensus test chain" "./bin/consensus -engine chain -action test"
run_test "consensus test dag" "./bin/consensus -engine dag -action test"
run_test "consensus test pq" "./bin/consensus -engine pq -action test"
run_test "consensus health chain" "./bin/consensus -engine chain -action health"
run_test "consensus health dag" "./bin/consensus -engine dag -action health"
run_test "consensus health pq" "./bin/consensus -engine pq -action health"
run_test "consensus mainnet" "./bin/consensus -network mainnet -action info"
run_test "consensus testnet" "./bin/consensus -network testnet -action info"
run_test "consensus local" "./bin/consensus -network local -action info"
echo ""
echo "5. Testing params tool"
echo "------------------------"
run_test "params help" "./bin/params -help"
run_test "params mainnet" "./bin/params -network mainnet"
run_test "params testnet" "./bin/params -network testnet"
run_test "params local" "./bin/params -network local"
run_test "params xchain" "./bin/params -network xchain"
run_test "params json mainnet" "./bin/params -network mainnet -json"
run_test "params json testnet" "./bin/params -network testnet -json"
run_test "params json local" "./bin/params -network local -json"
run_test "params json xchain" "./bin/params -network xchain -json"
echo ""
echo "==========================================="
echo " TEST SUMMARY"
echo "==========================================="
echo -e "Tests Passed: ${GREEN}$TESTS_PASSED${NC}"
echo -e "Tests Failed: ${RED}$TESTS_FAILED${NC}"
echo ""
if [ $TESTS_FAILED -eq 0 ]; then
echo -e "${GREEN}All tests passed successfully!${NC}"
exit 0
else
echo -e "${RED}Some tests failed. Please review the output above.${NC}"
exit 1
fi
-103
View File
@@ -1,103 +0,0 @@
#!/bin/bash
# Comprehensive validation script for Lux Consensus
# Ensures 100% passing status across all components
set -e
echo "======================================"
echo " Lux Consensus Validation Suite "
echo "======================================"
echo ""
# Color codes
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'
# Track overall status
ALL_PASS=true
# Function to check status
check_status() {
local name="$1"
local command="$2"
printf "%-30s" "$name"
if eval "$command" > /dev/null 2>&1; then
echo -e "${GREEN}✓ PASS${NC}"
return 0
else
echo -e "${RED}✗ FAIL${NC}"
ALL_PASS=false
return 1
fi
}
echo "1. GO TESTS"
echo "----------------------------------------"
check_status "Running all tests..." "go test ./..."
TOTAL_PACKAGES=$(go list ./... | wc -l)
TESTED_PACKAGES=$(go test ./... 2>&1 | grep -c "^ok" || true)
echo " Packages tested: $TESTED_PACKAGES"
echo " Total packages: $TOTAL_PACKAGES"
echo ""
echo "2. LINTING"
echo "----------------------------------------"
check_status "Running golangci-lint..." "golangci-lint run --timeout=10m 2>&1 | grep -v '^level' | grep -v '^$' | test \$(wc -l) -eq 0"
echo ""
echo "3. BENCHMARKS"
echo "----------------------------------------"
check_status "Config benchmarks..." "go test -bench=. -benchtime=100ms -run=XXX ./config"
check_status "Engine PQ benchmarks..." "go test -bench=. -benchtime=100ms -run=XXX ./engine/pq"
check_status "Protocol benchmarks..." "go test -bench=. -benchtime=100ms -run=XXX ./protocol/field ./protocol/quasar"
check_status "QZMQ benchmarks..." "go test -bench=. -benchtime=100ms -run=XXX ./qzmq"
echo ""
echo "4. CLI TOOLS"
echo "----------------------------------------"
check_status "bench tool..." "./bin/bench -help"
check_status "checker tool..." "./bin/checker -help"
check_status "sim tool..." "./bin/sim -help"
check_status "consensus tool..." "./bin/consensus -help"
check_status "params tool..." "./bin/params -help"
echo ""
echo "5. TOOL FUNCTIONALITY"
echo "----------------------------------------"
check_status "bench chain engine..." "./bin/bench -engine chain -blocks 10 -duration 1s"
check_status "checker all engines..." "./bin/checker -engine all"
check_status "sim network..." "./bin/sim -nodes 5 -rounds 2"
check_status "consensus info..." "./bin/consensus -action info"
check_status "params mainnet..." "./bin/params -network mainnet"
echo ""
echo "6. BUILD VERIFICATION"
echo "----------------------------------------"
check_status "Clean build..." "make clean && make build"
echo ""
echo "======================================"
echo " VALIDATION SUMMARY "
echo "======================================"
echo ""
if [ "$ALL_PASS" = true ]; then
echo -e "${GREEN}✓ 100% PASSING${NC}"
echo ""
echo "All components validated successfully:"
echo " • All Go tests pass"
echo " • No linting errors"
echo " • All benchmarks run"
echo " • All CLI tools functional"
echo " • Build system operational"
exit 0
else
echo -e "${RED}✗ VALIDATION FAILED${NC}"
echo ""
echo "Some components failed validation."
echo "Please review the output above."
exit 1
fi
-88
View File
@@ -1,11 +1,8 @@
package integration
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"testing"
"time"
@@ -52,91 +49,6 @@ func TestE2EConsensusEngine(t *testing.T) {
}
}
// TestE2EConsensusServer tests the HTTP server endpoints
func TestE2EConsensusServer(t *testing.T) {
serverURL := "http://localhost:9090"
// Probe once. If port :9090 doesn't host our consensus server
// (no listener, or a different service answering), skip the
// whole suite — these tests require `consensus serve` running
// alongside. They are NOT a unit test of the consensus engine.
probe, probeErr := http.Get(serverURL + "/health")
if probeErr != nil {
t.Skipf("Consensus server not running at %s: %v", serverURL, probeErr)
}
probe.Body.Close()
if probe.StatusCode != http.StatusOK {
t.Skipf("Port %s answered with status %d (not our consensus server)", serverURL, probe.StatusCode)
}
// Test health endpoint
t.Run("HealthCheck", func(t *testing.T) {
resp, err := http.Get(serverURL + "/health")
if err != nil {
t.Skipf("Server not running: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("Health check failed: status %d", resp.StatusCode)
}
})
// Test status endpoint
t.Run("Status", func(t *testing.T) {
resp, err := http.Get(serverURL + "/status")
if err != nil {
t.Skipf("Server not running: %v", err)
}
defer resp.Body.Close()
var status map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
t.Errorf("Failed to decode status: %v", err)
return
}
healthy, ok := status["healthy"].(bool)
if !ok {
t.Skipf("Server response missing 'healthy' field (not our consensus server): %+v", status)
}
if !healthy {
t.Error("Engine not healthy")
}
t.Logf("Status: %+v", status)
})
// Test consensus processing
t.Run("ConsensusRound", func(t *testing.T) {
payload := map[string]interface{}{
"block_id": "test-block-123",
"votes": map[string]int{
"node1": 1,
"node2": 1,
"node3": 1,
"node4": 0,
},
}
body, _ := json.Marshal(payload)
resp, err := http.Post(serverURL+"/consensus", "application/json", bytes.NewReader(body))
if err != nil {
t.Skipf("Server not running: %v", err)
}
defer resp.Body.Close()
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
t.Errorf("Failed to decode result: %v", err)
}
// With 75% votes (3/4), consensus should be reached (alpha=0.8 for local)
// Actually with local params alpha might be lower
t.Logf("Consensus result: %+v", result)
})
}
// TestE2ESimulation runs a full simulation
func TestE2ESimulation(t *testing.T) {
params := config.LocalParams()