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.
112 lines
3.1 KiB
Go
112 lines
3.1 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package scheduler
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/luxfi/log"
|
|
vmcore "github.com/luxfi/vm"
|
|
)
|
|
|
|
type Scheduler interface {
|
|
Dispatch(startTime time.Time)
|
|
|
|
// Client must guarantee that [SetBuildBlockTime]
|
|
// is never called after [Close]
|
|
SetBuildBlockTime(t time.Time)
|
|
Close()
|
|
}
|
|
|
|
// Scheduler receives notifications from a VM that it wants its engine to call
|
|
// the VM's BuildBlock method, and delivers the notification to the engine only
|
|
// when the engine should call BuildBlock. Namely, when this node is allowed to
|
|
// propose a block under the congestion control mechanism.
|
|
type scheduler struct {
|
|
log log.Logger
|
|
// The VM sends a message on this channel when it wants to tell the engine
|
|
// that the engine should call the VM's BuildBlock method
|
|
fromVM <-chan vmcore.Message
|
|
// The scheduler sends a message on this channel to notify the engine that
|
|
// it should call its VM's BuildBlock method
|
|
toEngine chan<- vmcore.Message
|
|
// When we receive a message on this channel, it means that we must refrain
|
|
// from telling the engine to call its VM's BuildBlock method until the
|
|
// given time
|
|
newBuildBlockTime chan time.Time
|
|
}
|
|
|
|
func New(log log.Logger, toEngine chan<- vmcore.Message) (Scheduler, chan<- vmcore.Message) {
|
|
vmToEngine := make(chan vmcore.Message, cap(toEngine))
|
|
return &scheduler{
|
|
log: log,
|
|
fromVM: vmToEngine,
|
|
toEngine: toEngine,
|
|
newBuildBlockTime: make(chan time.Time),
|
|
}, vmToEngine
|
|
}
|
|
|
|
func (s *scheduler) Dispatch(buildBlockTime time.Time) {
|
|
timer := time.NewTimer(time.Until(buildBlockTime))
|
|
waitloop:
|
|
for {
|
|
select {
|
|
case <-timer.C: // It's time to tell the engine to try to build a block
|
|
case buildBlockTime, ok := <-s.newBuildBlockTime:
|
|
// Stop the timer and clear [timer.C] if needed
|
|
if !timer.Stop() {
|
|
<-timer.C
|
|
}
|
|
|
|
if !ok {
|
|
// s.Close() was called
|
|
return
|
|
}
|
|
|
|
// The time at which we should notify the engine that it should try
|
|
// to build a block has changed
|
|
timer.Reset(time.Until(buildBlockTime))
|
|
continue waitloop
|
|
}
|
|
|
|
for {
|
|
select {
|
|
case msg := <-s.fromVM:
|
|
// Give the engine the message from the VM asking the engine to
|
|
// build a block
|
|
select {
|
|
case s.toEngine <- msg:
|
|
default:
|
|
// If the channel to the engine is full, drop the message
|
|
// from the VM to avoid deadlock
|
|
s.log.Debug("dropping message from VM",
|
|
log.String("reason", "channel to engine is full"),
|
|
log.String("messageType", fmt.Sprintf("%d", msg.Type)),
|
|
)
|
|
}
|
|
case buildBlockTime, ok := <-s.newBuildBlockTime:
|
|
// The time at which we should notify the engine that it should
|
|
// try to build a block has changed
|
|
if !ok {
|
|
// s.Close() was called
|
|
return
|
|
}
|
|
// We know [timer.C] was drained in the first select statement
|
|
// so its safe to call [timer.Reset]
|
|
timer.Reset(time.Until(buildBlockTime))
|
|
continue waitloop
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *scheduler) SetBuildBlockTime(t time.Time) {
|
|
s.newBuildBlockTime <- t
|
|
}
|
|
|
|
func (s *scheduler) Close() {
|
|
close(s.newBuildBlockTime)
|
|
}
|