diff --git a/internal/pow/solver/solver.go b/internal/pow/solver/solver.go new file mode 100644 index 0000000..4c0faeb --- /dev/null +++ b/internal/pow/solver/solver.go @@ -0,0 +1,94 @@ +package solver + +import ( + "context" + "runtime" + "sync/atomic" + + "hash-of-wisdom/internal/pow/challenge" +) + +// Solver handles parallel PoW solving with configurable parallelism +type Solver struct { + workers int +} + +// SolverOption represents functional options for solver configuration +type solverOption func(*Solver) + +// WithWorkers sets the number of parallel workers +func WithWorkers(workers int) solverOption { + return func(s *Solver) { + s.workers = workers + } +} + +// NewSolver creates a new parallel PoW solver +func NewSolver(options ...solverOption) *Solver { + solver := &Solver{ + workers: runtime.NumCPU(), // Default to CPU count + } + + for _, option := range options { + option(solver) + } + + return solver +} + +// Solve attempts to find a valid nonce for the given challenge +func (s *Solver) Solve(ctx context.Context, ch *challenge.Challenge) (*challenge.Solution, error) { + // Create cancellable context for workers + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // Channel to receive solution from any worker + solutionCh := make(chan *challenge.Solution, 1) + + // Shared nonce counter for work distribution + var nonceCounter atomic.Uint64 + + // Start parallel workers + for i := range s.workers { + go func(workerID int) { + s.worker(ctx, ch, &nonceCounter, solutionCh) + }(i) + } + + // Wait for either solution or context cancellation + select { + case solution := <-solutionCh: + return solution, nil + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +// worker performs PoW computation in parallel +func (s *Solver) worker(ctx context.Context, ch *challenge.Challenge, nonceCounter *atomic.Uint64, solutionCh chan<- *challenge.Solution) { + + for { + select { + case <-ctx.Done(): + return + default: + // Get next nonce to try + nonce := nonceCounter.Add(1) - 1 + + // Try this nonce + if ch.VerifySolution(nonce) { + // Found solution! Send it back + solution := &challenge.Solution{ + Challenge: *ch, + Nonce: nonce, + } + + select { + case solutionCh <- solution: + case <-ctx.Done(): + } + return + } + } + } +}