mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
361 lines
9.0 KiB
Go
361 lines
9.0 KiB
Go
package protocol_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"runtime"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/luxfi/log"
|
|
"github.com/luxfi/metric"
|
|
"github.com/luxfi/threshold/internal/test"
|
|
"github.com/luxfi/threshold/pkg/math/curve"
|
|
"github.com/luxfi/threshold/pkg/party"
|
|
"github.com/luxfi/threshold/pkg/pool"
|
|
"github.com/luxfi/threshold/pkg/protocol"
|
|
"github.com/luxfi/threshold/protocols/lss"
|
|
"github.com/luxfi/threshold/protocols/lss/config"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// BenchmarkHandler compares original vs optimized handler
|
|
func BenchmarkHandler(b *testing.B) {
|
|
// Benchmark enabled with proper timeout
|
|
tests := []struct {
|
|
name string
|
|
n int
|
|
threshold int
|
|
}{
|
|
{"3-of-5", 5, 3},
|
|
{"5-of-7", 7, 5},
|
|
{"7-of-11", 11, 7},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
b.Run(tt.name, func(b *testing.B) {
|
|
group := curve.Secp256k1{}
|
|
partyIDs := test.PartyIDs(tt.n)
|
|
pl := pool.NewPool(0)
|
|
defer pl.TearDown()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
ctx := context.Background()
|
|
logger := log.NewTestLogger(log.InfoLevel)
|
|
sessionID := []byte("test-session")
|
|
cfg := protocol.DefaultConfig()
|
|
cfg.ProtocolTimeout = 30 * time.Second // Shorter timeout for tests
|
|
|
|
handlers := make([]*protocol.Handler, tt.n)
|
|
for j, id := range partyIDs {
|
|
h, err := protocol.NewHandler(ctx, logger, metric.NewRegistry(),
|
|
lss.Keygen(group, id, partyIDs, tt.threshold, pl), sessionID, cfg)
|
|
require.NoError(b, err)
|
|
handlers[j] = h
|
|
}
|
|
|
|
runProtocol(handlers, partyIDs)
|
|
|
|
// Verify results
|
|
for _, h := range handlers {
|
|
result, err := h.Result()
|
|
require.NoError(b, err)
|
|
require.IsType(b, &config.Config{}, result)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkConcurrentMessages tests concurrent message handling
|
|
func BenchmarkConcurrentMessages(b *testing.B) {
|
|
b.Skip("Skipping benchmark that times out")
|
|
tests := []struct {
|
|
name string
|
|
n int
|
|
threshold int
|
|
parallel bool
|
|
}{
|
|
{"sequential-5", 5, 3, false},
|
|
{"parallel-5", 5, 3, true},
|
|
{"sequential-7", 7, 5, false},
|
|
{"parallel-7", 7, 5, true},
|
|
{"sequential-11", 11, 7, false},
|
|
{"parallel-11", 11, 7, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
b.Run(tt.name, func(b *testing.B) {
|
|
group := curve.Secp256k1{}
|
|
partyIDs := test.PartyIDs(tt.n)
|
|
pl := pool.NewPool(0)
|
|
defer pl.TearDown()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
ctx := context.Background()
|
|
logger := log.NewTestLogger(log.InfoLevel)
|
|
sessionID := []byte("test-session")
|
|
cfg := protocol.DefaultConfig()
|
|
cfg.ProtocolTimeout = 30 * time.Second // Shorter timeout for tests
|
|
|
|
handlers := make([]*protocol.Handler, tt.n)
|
|
for j, id := range partyIDs {
|
|
h, err := protocol.NewHandler(ctx, logger, metric.NewRegistry(),
|
|
lss.Keygen(group, id, partyIDs, tt.threshold, pl), sessionID, cfg)
|
|
require.NoError(b, err)
|
|
handlers[j] = h
|
|
}
|
|
|
|
if tt.parallel {
|
|
runProtocolParallel(handlers, partyIDs)
|
|
} else {
|
|
runProtocol(handlers, partyIDs)
|
|
}
|
|
|
|
// Verify results
|
|
for _, h := range handlers {
|
|
result, err := h.Result()
|
|
require.NoError(b, err)
|
|
require.IsType(b, &config.Config{}, result)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// runProtocol runs the protocol using sequential message delivery
|
|
func runProtocol(handlers []*protocol.Handler, partyIDs []party.ID) {
|
|
network := test.NewNetwork(partyIDs)
|
|
var wg sync.WaitGroup
|
|
|
|
for i, h := range handlers {
|
|
wg.Add(1)
|
|
go func(id party.ID, handler *protocol.Handler) {
|
|
defer wg.Done()
|
|
test.HandlerLoop(id, handler, network)
|
|
}(partyIDs[i], h)
|
|
}
|
|
|
|
// Wait with timeout
|
|
done := make(chan struct{})
|
|
go func() {
|
|
wg.Wait()
|
|
close(done)
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
// Protocol completed
|
|
case <-time.After(30 * time.Second):
|
|
// Timeout - protocol didn't complete
|
|
fmt.Println("Protocol timed out in benchmark")
|
|
}
|
|
}
|
|
|
|
// runProtocolParallel runs the protocol using parallel message delivery
|
|
func runProtocolParallel(handlers []*protocol.Handler, partyIDs []party.ID) {
|
|
// For now, same as sequential since the new handler already optimizes internally
|
|
runProtocol(handlers, partyIDs)
|
|
}
|
|
|
|
// BenchmarkMessageProcessing tests message processing throughput
|
|
func BenchmarkMessageProcessing(b *testing.B) {
|
|
tests := []struct {
|
|
name string
|
|
messages int
|
|
workers int
|
|
}{
|
|
{"100msgs-1worker", 100, 1},
|
|
{"100msgs-4workers", 100, 4},
|
|
{"100msgs-8workers", 100, 8},
|
|
{"1000msgs-1worker", 1000, 1},
|
|
{"1000msgs-4workers", 1000, 4},
|
|
{"1000msgs-8workers", 1000, 8},
|
|
{"10000msgs-4workers", 10000, 4},
|
|
{"10000msgs-8workers", 10000, 8},
|
|
{"10000msgs-16workers", 10000, 16},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
b.Run(test.name, func(b *testing.B) {
|
|
benchmarkMessageThroughput(b, test.messages, test.workers)
|
|
})
|
|
}
|
|
}
|
|
|
|
func benchmarkMessageThroughput(b *testing.B, numMessages, numWorkers int) {
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
// Simulate message processing with worker pool
|
|
msgChan := make(chan int, numMessages)
|
|
doneChan := make(chan struct{})
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(numWorkers)
|
|
|
|
// Start workers
|
|
for w := 0; w < numWorkers; w++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
for range msgChan {
|
|
// Simulate message processing
|
|
time.Sleep(100 * time.Nanosecond)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Send messages
|
|
go func() {
|
|
for m := 0; m < numMessages; m++ {
|
|
msgChan <- m
|
|
}
|
|
close(msgChan)
|
|
}()
|
|
|
|
// Wait for completion
|
|
go func() {
|
|
wg.Wait()
|
|
close(doneChan)
|
|
}()
|
|
|
|
<-doneChan
|
|
}
|
|
}
|
|
|
|
// BenchmarkMemoryUsage measures memory allocation patterns
|
|
func BenchmarkMemoryUsage(b *testing.B) {
|
|
b.Skip("Skipping benchmark that times out")
|
|
tests := []struct {
|
|
name string
|
|
n int
|
|
threshold int
|
|
}{
|
|
{"small-3-of-5", 5, 3},
|
|
{"medium-5-of-7", 7, 5},
|
|
{"large-7-of-11", 11, 7},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
b.Run(tt.name, func(b *testing.B) {
|
|
group := curve.Secp256k1{}
|
|
partyIDs := test.PartyIDs(tt.n)
|
|
pl := pool.NewPool(0)
|
|
defer pl.TearDown()
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
ctx := context.Background()
|
|
logger := log.NewTestLogger(log.InfoLevel)
|
|
sessionID := []byte("test-session")
|
|
cfg := protocol.DefaultConfig()
|
|
cfg.ProtocolTimeout = 30 * time.Second // Shorter timeout for tests
|
|
|
|
handlers := make([]*protocol.Handler, tt.n)
|
|
for j, id := range partyIDs {
|
|
h, err := protocol.NewHandler(ctx, logger, metric.NewRegistry(),
|
|
lss.Keygen(group, id, partyIDs, tt.threshold, pl), sessionID, cfg)
|
|
require.NoError(b, err)
|
|
handlers[j] = h
|
|
}
|
|
|
|
runProtocol(handlers, partyIDs)
|
|
|
|
// Force GC to measure actual memory usage
|
|
runtime.GC()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestHandlerPerformance provides performance comparison
|
|
func TestHandlerPerformance(t *testing.T) {
|
|
t.Skip("Skipping performance test that times out")
|
|
if testing.Short() {
|
|
t.Skip("Skipping performance test in short mode")
|
|
}
|
|
|
|
fmt.Println("\n=== Handler Performance Comparison ===")
|
|
|
|
// Test configuration
|
|
n := 7
|
|
threshold := 4
|
|
group := curve.Secp256k1{}
|
|
partyIDs := test.PartyIDs(n)
|
|
pl := pool.NewPool(0)
|
|
defer pl.TearDown()
|
|
|
|
ctx := context.Background()
|
|
logger := log.NewTestLogger(log.InfoLevel)
|
|
sessionID := []byte("test-session")
|
|
cfg := protocol.DefaultConfig()
|
|
|
|
// Measure optimized handler
|
|
start := time.Now()
|
|
origHandlers := make([]*protocol.Handler, n)
|
|
for i, id := range partyIDs {
|
|
h, err := protocol.NewHandler(ctx, logger, metric.NewRegistry(), lss.Keygen(group, id, partyIDs, threshold, pl), sessionID, cfg)
|
|
require.NoError(t, err)
|
|
origHandlers[i] = h
|
|
}
|
|
runProtocol(origHandlers, partyIDs)
|
|
origDuration := time.Since(start)
|
|
|
|
// Verify results
|
|
for _, h := range origHandlers {
|
|
result, err := h.Result()
|
|
require.NoError(t, err)
|
|
require.IsType(t, &config.Config{}, result)
|
|
}
|
|
|
|
// Measure concurrent handler (using concurrent delivery)
|
|
start = time.Now()
|
|
optHandlers := make([]*protocol.Handler, n)
|
|
for i, id := range partyIDs {
|
|
h, err := protocol.NewHandler(ctx, logger, metric.NewRegistry(), lss.Keygen(group, id, partyIDs, threshold, pl), sessionID, cfg)
|
|
require.NoError(t, err)
|
|
optHandlers[i] = h
|
|
}
|
|
runProtocolParallel(optHandlers, partyIDs)
|
|
optDuration := time.Since(start)
|
|
|
|
// Verify concurrent results
|
|
for _, h := range optHandlers {
|
|
result, err := h.Result()
|
|
require.NoError(t, err)
|
|
require.IsType(t, &config.Config{}, result)
|
|
}
|
|
|
|
// Report results
|
|
fmt.Printf("Sequential: %v\n", origDuration)
|
|
fmt.Printf("Parallel: %v\n", optDuration)
|
|
fmt.Printf("Speedup: %.2fx\n", float64(origDuration)/float64(optDuration))
|
|
|
|
// Memory comparison
|
|
var m1, m2 runtime.MemStats
|
|
runtime.GC()
|
|
runtime.ReadMemStats(&m1)
|
|
|
|
// Run protocol again to measure memory
|
|
handlers := make([]*protocol.Handler, n)
|
|
for i, id := range partyIDs {
|
|
h, err := protocol.NewHandler(ctx, logger, metric.NewRegistry(), lss.Keygen(group, id, partyIDs, threshold, pl), sessionID, cfg)
|
|
require.NoError(t, err)
|
|
handlers[i] = h
|
|
}
|
|
runProtocol(handlers, partyIDs)
|
|
|
|
runtime.GC()
|
|
runtime.ReadMemStats(&m2)
|
|
|
|
fmt.Printf("\nMemory Usage:\n")
|
|
fmt.Printf("Alloc: %v KB\n", (m2.Alloc-m1.Alloc)/1024)
|
|
fmt.Printf("TotalAlloc: %v KB\n", (m2.TotalAlloc-m1.TotalAlloc)/1024)
|
|
fmt.Printf("NumGC: %v\n", m2.NumGC-m1.NumGC)
|
|
}
|