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.
229 lines
6.0 KiB
Go
229 lines
6.0 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package state
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/database"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/math/set"
|
|
)
|
|
|
|
var _ validatorState = (*metadata)(nil)
|
|
|
|
type validatorMetadata struct {
|
|
UpDuration time.Duration
|
|
LastUpdated uint64 // Unix time in seconds
|
|
PotentialReward uint64
|
|
PotentialDelegateeReward uint64
|
|
StakerStartTime uint64
|
|
|
|
txID ids.ID
|
|
lastUpdated time.Time
|
|
}
|
|
|
|
// parseValidatorMetadata overlays metadata's persisted fields (native
|
|
// validatorMetadata wire) from bytes. Empty bytes means nothing was persisted
|
|
// for this staker — the caller pre-populates tx-derived defaults
|
|
// (StakerStartTime/LastUpdated), which are kept as-is. lastUpdated is always
|
|
// derived from the resulting LastUpdated.
|
|
func parseValidatorMetadata(bytes []byte, metadata *validatorMetadata) error {
|
|
if len(bytes) > 0 {
|
|
if err := unmarshalValidatorMetadata(bytes, metadata); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
metadata.lastUpdated = time.Unix(int64(metadata.LastUpdated), 0)
|
|
return nil
|
|
}
|
|
|
|
type validatorState interface {
|
|
// LoadValidatorMetadata sets the [metadata] of [vdrID] on [netID].
|
|
// GetUptime and SetUptime will return an error if the [vdrID] and
|
|
// [netID] hasn't been loaded. This call will not result in a write to
|
|
// disk.
|
|
LoadValidatorMetadata(
|
|
vdrID ids.NodeID,
|
|
netID ids.ID,
|
|
metadata *validatorMetadata,
|
|
)
|
|
|
|
// GetUptime returns the current uptime measurements of [vdrID] on
|
|
// [netID].
|
|
GetUptime(
|
|
vdrID ids.NodeID,
|
|
netID ids.ID,
|
|
) (upDuration time.Duration, lastUpdated time.Time, err error)
|
|
|
|
// SetUptime updates the uptime measurements of [vdrID] on [netID].
|
|
// Unless these measurements are deleted first, the next call to
|
|
// WriteUptimes will write this update to disk.
|
|
SetUptime(
|
|
vdrID ids.NodeID,
|
|
netID ids.ID,
|
|
upDuration time.Duration,
|
|
lastUpdated time.Time,
|
|
) error
|
|
|
|
// GetDelegateeReward returns the current rewards accrued to [vdrID] on
|
|
// [netID].
|
|
GetDelegateeReward(
|
|
netID ids.ID,
|
|
vdrID ids.NodeID,
|
|
) (amount uint64, err error)
|
|
|
|
// SetDelegateeReward updates the rewards accrued to [vdrID] on [netID].
|
|
// Unless these measurements are deleted first, the next call to
|
|
// WriteUptimes will write this update to disk.
|
|
SetDelegateeReward(
|
|
netID ids.ID,
|
|
vdrID ids.NodeID,
|
|
amount uint64,
|
|
) error
|
|
|
|
// DeleteValidatorMetadata removes in-memory references to the metadata of
|
|
// [vdrID] on [netID]. If there were staged updates from a prior call to
|
|
// SetUptime or SetDelegateeReward, the updates will be dropped. This call
|
|
// will not result in a write to disk.
|
|
DeleteValidatorMetadata(vdrID ids.NodeID, netID ids.ID)
|
|
|
|
// WriteValidatorMetadata writes all staged updates from prior calls to
|
|
// SetUptime or SetDelegateeReward.
|
|
WriteValidatorMetadata(
|
|
dbPrimary database.KeyValueWriter,
|
|
dbNet database.KeyValueWriter,
|
|
) error
|
|
}
|
|
|
|
type metadata struct {
|
|
metadata map[ids.NodeID]map[ids.ID]*validatorMetadata // vdrID -> netID -> metadata
|
|
// updatedMetadata tracks the updates since WriteValidatorMetadata was last called
|
|
updatedMetadata map[ids.NodeID]set.Set[ids.ID] // vdrID -> netIDs
|
|
}
|
|
|
|
func newValidatorState() validatorState {
|
|
return &metadata{
|
|
metadata: make(map[ids.NodeID]map[ids.ID]*validatorMetadata),
|
|
updatedMetadata: make(map[ids.NodeID]set.Set[ids.ID]),
|
|
}
|
|
}
|
|
|
|
func (m *metadata) LoadValidatorMetadata(
|
|
vdrID ids.NodeID,
|
|
netID ids.ID,
|
|
uptime *validatorMetadata,
|
|
) {
|
|
chainMetadata, ok := m.metadata[vdrID]
|
|
if !ok {
|
|
chainMetadata = make(map[ids.ID]*validatorMetadata)
|
|
m.metadata[vdrID] = chainMetadata
|
|
}
|
|
chainMetadata[netID] = uptime
|
|
}
|
|
|
|
func (m *metadata) GetUptime(
|
|
vdrID ids.NodeID,
|
|
netID ids.ID,
|
|
) (time.Duration, time.Time, error) {
|
|
metadata, exists := m.metadata[vdrID][netID]
|
|
if !exists {
|
|
return 0, time.Time{}, database.ErrNotFound
|
|
}
|
|
return metadata.UpDuration, metadata.lastUpdated, nil
|
|
}
|
|
|
|
func (m *metadata) SetUptime(
|
|
vdrID ids.NodeID,
|
|
netID ids.ID,
|
|
upDuration time.Duration,
|
|
lastUpdated time.Time,
|
|
) error {
|
|
metadata, exists := m.metadata[vdrID][netID]
|
|
if !exists {
|
|
return database.ErrNotFound
|
|
}
|
|
metadata.UpDuration = upDuration
|
|
metadata.lastUpdated = lastUpdated
|
|
|
|
m.addUpdatedMetadata(vdrID, netID)
|
|
return nil
|
|
}
|
|
|
|
func (m *metadata) GetDelegateeReward(
|
|
netID ids.ID,
|
|
vdrID ids.NodeID,
|
|
) (uint64, error) {
|
|
metadata, exists := m.metadata[vdrID][netID]
|
|
if !exists {
|
|
return 0, database.ErrNotFound
|
|
}
|
|
return metadata.PotentialDelegateeReward, nil
|
|
}
|
|
|
|
func (m *metadata) SetDelegateeReward(
|
|
netID ids.ID,
|
|
vdrID ids.NodeID,
|
|
amount uint64,
|
|
) error {
|
|
metadata, exists := m.metadata[vdrID][netID]
|
|
if !exists {
|
|
return database.ErrNotFound
|
|
}
|
|
metadata.PotentialDelegateeReward = amount
|
|
|
|
m.addUpdatedMetadata(vdrID, netID)
|
|
return nil
|
|
}
|
|
|
|
func (m *metadata) DeleteValidatorMetadata(vdrID ids.NodeID, netID ids.ID) {
|
|
chainMetadata := m.metadata[vdrID]
|
|
delete(chainMetadata, netID)
|
|
if len(chainMetadata) == 0 {
|
|
delete(m.metadata, vdrID)
|
|
}
|
|
|
|
chainUpdatedMetadata := m.updatedMetadata[vdrID]
|
|
chainUpdatedMetadata.Remove(netID)
|
|
if chainUpdatedMetadata.Len() == 0 {
|
|
delete(m.updatedMetadata, vdrID)
|
|
}
|
|
}
|
|
|
|
func (m *metadata) WriteValidatorMetadata(
|
|
dbPrimary database.KeyValueWriter,
|
|
dbNet database.KeyValueWriter,
|
|
) error {
|
|
for vdrID, updatedNets := range m.updatedMetadata {
|
|
for netID := range updatedNets {
|
|
metadata := m.metadata[vdrID][netID]
|
|
metadata.LastUpdated = uint64(metadata.lastUpdated.Unix())
|
|
|
|
metadataBytes, err := marshalValidatorMetadata(metadata)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
db := dbNet
|
|
if netID == constants.PrimaryNetworkID {
|
|
db = dbPrimary
|
|
}
|
|
if err := db.Put(metadata.txID[:], metadataBytes); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
delete(m.updatedMetadata, vdrID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *metadata) addUpdatedMetadata(vdrID ids.NodeID, netID ids.ID) {
|
|
updatedNetMetadata, ok := m.updatedMetadata[vdrID]
|
|
if !ok {
|
|
updatedNetMetadata = make(set.Set[ids.ID])
|
|
m.updatedMetadata[vdrID] = updatedNetMetadata
|
|
}
|
|
updatedNetMetadata.Add(netID)
|
|
}
|