Files
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

116 lines
4.9 KiB
Go

// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package stakingparams
import (
"time"
"github.com/luxfi/genesis/pkg/genesis"
"github.com/luxfi/node/utils/units"
"github.com/luxfi/node/vms/platformvm/reward"
)
// One unit for the whole node. Every threshold in this file is denominated in
// it, so a second definition of the unit would silently rescale all of them.
const (
Lux = units.Lux
KiloLux = units.KiloLux
MegaLux = units.MegaLux
GigaLux = units.GigaLux
)
// MainnetGenesis is the policy Lux mainnet runs under today, transcribed from
// the constants presently compiled into the node (MinValidatorStake 2000 LUX,
// MaxValidatorStake 5 GigaLux, MinStakeDuration 2 weeks, MaxStakeDuration
// 1 year, MinDelegationFee 2%, UptimeRequirement 80%).
//
// Seeding the history with exactly today's values is what makes adopting this
// mechanism a no-op on day one: nothing about the live network changes until
// stake votes to change it.
var MainnetGenesis = Params{
MinValidatorStake: 2_000 * Lux,
MaxValidatorStake: 5 * GigaLux,
MinStakeDuration: 2 * 7 * 24 * 60 * 60,
MaxStakeDuration: 365 * 24 * 60 * 60,
MinDelegationFee: 20_000, // 2%
UptimeRequirement: 800_000, // 80%
}
// MainnetBounds is the constitution — the envelope no vote can leave.
//
// Each bound is chosen against one question: what is the most exclusionary
// value a hostile stake majority could ever be allowed to reach, and is the
// network still open to an arbitrary global participant there? If the answer at
// Hi (or Lo, for the widening fields) is "no", the bound is wrong.
//
// - minValidatorStake Hi = 100_000 LUX. At the most hostile setting the
// mechanism permits, a holder of 100k LUX — 0.000005% of the 2T supply cap —
// can still validate. Below Lo = 1 LUX there is nothing to bond.
// - maxValidatorStake Lo = 1 MegaLux stops a cartel shrinking the ceiling to
// exclude large honest stakers; Hi holds today's 5 GigaLux.
// - minStakeDuration Hi = 30 days caps how long anyone can be forced to lock.
// - maxStakeDuration Hi = 365 days: the reward calculator's MintingPeriod is
// one year, so a longer bond has no defined emission. This bound is a
// correctness constraint, not a policy preference.
// - minDelegationFee Hi = 20% caps how much of a delegator's yield validators
// can vote themselves. Delegators are the one constituency that cannot
// defend itself by voting, because the vote is the validator's.
// - uptimeRequirement Hi = 95%. Above that, ordinary maintenance forfeits a
// reward, and the field stops being a liveness incentive and becomes an
// ejection weapon.
var MainnetBounds = Bounds{
Lo: Params{
MinValidatorStake: 1 * Lux,
MaxValidatorStake: 1 * MegaLux,
MinStakeDuration: 60 * 60,
MaxStakeDuration: 7 * 24 * 60 * 60,
MinDelegationFee: 0,
UptimeRequirement: 0,
},
Hi: Params{
MinValidatorStake: 100 * KiloLux,
MaxValidatorStake: 5 * GigaLux,
MinStakeDuration: 30 * 24 * 60 * 60,
MaxStakeDuration: 365 * 24 * 60 * 60,
MinDelegationFee: 200_000, // 20%
UptimeRequirement: 950_000, // 95%
},
}
// MainnetRate is the brake on exclusionary change: at most 10% of the current
// value per accepted change, and at most one accepted change per 14 days.
//
// 14 days is not arbitrary — it is mainnet's MinStakeDuration, so no bond can
// be entered and matured inside a single governance step. Combined with the 10%
// cap it puts roughly 1.6 years of continuous, public, on-chain effort between
// today's 2000 LUX floor and the 100k LUX ceiling, which is the window in which
// anyone being squeezed out can organise, exit, or fork.
var MainnetRate = Rate{
MaxStep: reward.PercentDenominator / 10, // 10% of current
MinInterval: 14 * 24 * time.Hour,
}
// MainnetHistory is the policy in force on Lux mainnet, oldest first. The
// first entry is what the chain was born with; the second raises the validator
// floor to 1,000,000 LUX — the same floor testnet and local have always had,
// and the one that makes an operator holding 50M a fifty-fold participant
// rather than a fifty-thousand-fold one. Anyone bonding at the old floor before
// the activation is judged on the terms they agreed to.
//
// The activation is genesis.Activation, the one instant every mainnet rule
// turns on at. It is defined once, in genesis, and read here — so the staking
// floor cannot activate at a moment the precompile schedule does not know.
var MainnetHistory = History{
{Activation: 0, Params: MainnetGenesis},
{Activation: genesis.Activation, Params: Params{
MinValidatorStake: 1_000_000 * Lux,
MaxValidatorStake: MainnetGenesis.MaxValidatorStake,
MinStakeDuration: MainnetGenesis.MinStakeDuration,
MaxStakeDuration: MainnetGenesis.MaxStakeDuration,
MinDelegationFee: MainnetGenesis.MinDelegationFee,
UptimeRequirement: MainnetGenesis.UptimeRequirement,
}},
}