mirror of
https://github.com/luxfi/node.git
synced 2026-10-30 15:24:05 +00:00
The module already called itself github.com/luxfi/node while containing no node in Go: cmd/luxd was twenty-one lines that printed the size of a few types, and the Go column of the matrix measured a VM plugin. A repo that fetches the thing it claims to be has not replaced it, so the Go sources move in — 1515 files, the daemon and everything under it — and the build reaches outside this module for nothing. Rust and C++ sit beside it unchanged and are still measured against it by the differential. That is the point of one repo: the reference implementation and the two ports are the same checkout, so parity is a thing you can run rather than a thing you assert. Verified: builds, and the closure carries no lux-private — checked at build time rather than believed. The daemon starts twelve chains on a local network (P X C Q Z A B G K M F, plus D through its plugin) and reports healthy.
126 lines
3.5 KiB
Go
126 lines
3.5 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package timer
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"time"
|
|
)
|
|
|
|
// ProgressFromHash returns the progress out of MaxUint64 assuming [b] is a key
|
|
// in a uniformly distributed sequence that is being iterated lexicographically.
|
|
func ProgressFromHash(b []byte) uint64 {
|
|
// binary.BigEndian.Uint64 will panic if the input length is less than 8, so
|
|
// pad 0s as needed.
|
|
var progress [8]byte
|
|
copy(progress[:], b)
|
|
return binary.BigEndian.Uint64(progress[:])
|
|
}
|
|
|
|
// EstimateETA attempts to estimate the remaining time for a job to finish given
|
|
// the [startTime] and it's current progress.
|
|
func EstimateETA(startTime time.Time, progress, end uint64) time.Duration {
|
|
timeSpent := time.Since(startTime)
|
|
|
|
percentExecuted := float64(progress) / float64(end)
|
|
estimatedTotalDuration := time.Duration(float64(timeSpent) / percentExecuted)
|
|
eta := estimatedTotalDuration - timeSpent
|
|
return eta.Round(time.Second)
|
|
}
|
|
|
|
// EtaTracker provides exponentially weighted moving average ETA estimates
|
|
type EtaTracker struct {
|
|
startTime time.Time
|
|
samples int
|
|
alpha float64
|
|
sampleCount int
|
|
lastProgress uint64
|
|
lastSampleTime time.Time
|
|
}
|
|
|
|
// NewEtaTracker creates a new ETA tracker with the given number of samples and alpha
|
|
func NewEtaTracker(samples int, alpha float64) *EtaTracker {
|
|
return &EtaTracker{
|
|
startTime: time.Now(),
|
|
samples: samples,
|
|
alpha: alpha,
|
|
}
|
|
}
|
|
|
|
// Update updates the ETA tracker with new progress
|
|
func (e *EtaTracker) Update(progress, total uint64) {
|
|
// Simple implementation - just track the time
|
|
}
|
|
|
|
// AddSample adds a sample to the ETA tracker and returns ETA pointer and progress percentage
|
|
func (e *EtaTracker) AddSample(progress, total uint64, sampleTime time.Time) (*time.Duration, float64) {
|
|
if total == 0 {
|
|
return nil, 0
|
|
}
|
|
|
|
// Initialize start time on first sample
|
|
if e.sampleCount == 0 {
|
|
e.startTime = sampleTime
|
|
e.lastProgress = progress
|
|
e.lastSampleTime = sampleTime
|
|
}
|
|
|
|
// Update sample count
|
|
e.sampleCount++
|
|
|
|
// Check if we have enough samples
|
|
if e.sampleCount < e.samples {
|
|
e.lastProgress = progress
|
|
e.lastSampleTime = sampleTime
|
|
return nil, 0
|
|
}
|
|
|
|
// Check if time went backwards
|
|
if sampleTime.Before(e.lastSampleTime) {
|
|
return nil, 0
|
|
}
|
|
|
|
// Check if progress didn't advance
|
|
if progress <= e.lastProgress {
|
|
return nil, 0
|
|
}
|
|
|
|
// If we're at or past the end, return 0 ETA immediately
|
|
if progress >= total {
|
|
e.lastProgress = progress
|
|
e.lastSampleTime = sampleTime
|
|
eta := time.Duration(0)
|
|
return &eta, 100.0
|
|
}
|
|
|
|
// Calculate ETA based on recent rate (since last sample), not overall rate
|
|
// This allows us to detect acceleration/deceleration
|
|
timeSinceLastSample := sampleTime.Sub(e.lastSampleTime)
|
|
progressSinceLastSample := progress - e.lastProgress
|
|
|
|
if timeSinceLastSample > 0 && progressSinceLastSample > 0 {
|
|
// Calculate rate: progress per unit time
|
|
rate := float64(progressSinceLastSample) / timeSinceLastSample.Seconds()
|
|
remaining := total - progress
|
|
etaSeconds := float64(remaining) / rate
|
|
eta := time.Duration(etaSeconds * float64(time.Second)).Round(time.Second)
|
|
|
|
e.lastProgress = progress
|
|
e.lastSampleTime = sampleTime
|
|
|
|
progressPercent := (float64(progress) / float64(total)) * 100
|
|
|
|
return &eta, progressPercent
|
|
}
|
|
|
|
e.lastProgress = progress
|
|
e.lastSampleTime = sampleTime
|
|
return nil, 0
|
|
}
|
|
|
|
// ETA returns the estimated time remaining
|
|
func (e *EtaTracker) ETA(progress, total uint64) time.Duration {
|
|
return EstimateETA(e.startTime, progress, total)
|
|
}
|