Files
node/vms/proposervm/scheduler/automining_scheduler.go
zeekay 7cf87b230b node-unified is the node
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.
2026-09-07 16:15:25 -07:00

172 lines
4.2 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package scheduler
import (
"time"
"github.com/luxfi/log"
vmcore "github.com/luxfi/vm"
)
// AutominingScheduler is a scheduler that continuously produces blocks at a fixed interval
type AutominingScheduler interface {
Scheduler
// StartAutomining starts continuous block production
StartAutomining(interval time.Duration)
// StopAutomining stops continuous block production
StopAutomining()
}
type autominingScheduler struct {
*scheduler
// Channel to control automining
autominingControl chan autominingCommand
// Whether automining is currently active
autominingActive bool
// Interval between automatic block productions
autominingInterval time.Duration
}
type autominingCommand struct {
start bool
interval time.Duration
}
// NewAutomining creates a new scheduler with automining capabilities
func NewAutomining(log log.Logger, toEngine chan<- vmcore.Message) (AutominingScheduler, chan<- vmcore.Message) {
vmToEngine := make(chan vmcore.Message, cap(toEngine))
baseScheduler := &scheduler{
log: log,
fromVM: vmToEngine,
toEngine: toEngine,
newBuildBlockTime: make(chan time.Time),
}
return &autominingScheduler{
scheduler: baseScheduler,
autominingControl: make(chan autominingCommand, 1),
}, vmToEngine
}
func (s *autominingScheduler) Dispatch(buildBlockTime time.Time) {
timer := time.NewTimer(time.Until(buildBlockTime))
defer timer.Stop()
// Automining ticker - initially stopped
autominingTicker := time.NewTicker(time.Hour)
autominingTicker.Stop()
defer autominingTicker.Stop()
for {
select {
case <-timer.C: // It's time to tell the engine to try to build a block
s.handleBuildRequest()
// If automining is active, reset the timer for the next block
if s.autominingActive {
timer.Reset(s.autominingInterval)
}
case <-autominingTicker.C: // Automining interval elapsed
s.handleBuildRequest()
case cmd := <-s.autominingControl:
if cmd.start {
s.log.Info("starting automining",
log.Duration("interval", cmd.interval),
)
s.autominingActive = true
s.autominingInterval = cmd.interval
// Stop the regular timer and start automining ticker
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}
autominingTicker.Reset(cmd.interval)
} else {
s.log.Info("stopping automining")
s.autominingActive = false
autominingTicker.Stop()
// Reset the regular timer
timer.Reset(time.Until(buildBlockTime))
}
case buildBlockTime, ok := <-s.newBuildBlockTime:
// Stop the timer and clear [timer.C] if needed
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}
if !ok {
// s.Close() was called
return
}
// Only update the timer if automining is not active
if !s.autominingActive {
timer.Reset(time.Until(buildBlockTime))
}
case msg := <-s.fromVM:
// Forward the message from VM to engine
select {
case s.toEngine <- msg:
default:
// If the channel to the engine is full, drop the message
s.log.Debug("dropping message from VM",
log.String("reason", "channel to engine is full"),
log.Reflect("message", msg),
)
}
}
}
}
func (s *autominingScheduler) handleBuildRequest() {
// Send a build block message to the engine
msg := vmcore.Message{Type: vmcore.PendingTxs}
select {
case s.toEngine <- msg:
s.log.Debug("sent build block request to engine",
log.Bool("automining", s.autominingActive),
)
default:
s.log.Debug("dropping build block request",
log.String("reason", "channel to engine is full"),
)
}
}
func (s *autominingScheduler) StartAutomining(interval time.Duration) {
select {
case s.autominingControl <- autominingCommand{start: true, interval: interval}:
default:
s.log.Warn("automining control channel full, command dropped")
}
}
func (s *autominingScheduler) StopAutomining() {
select {
case s.autominingControl <- autominingCommand{start: false}:
default:
s.log.Warn("automining control channel full, command dropped")
}
}
func (s *autominingScheduler) Close() {
s.scheduler.Close()
close(s.autominingControl)
}