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.
164 lines
6.7 KiB
Go
164 lines
6.7 KiB
Go
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package txs
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
consensustest "github.com/luxfi/consensus/test/helpers"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/node/vms/platformvm/reward"
|
|
lux "github.com/luxfi/utxo"
|
|
"github.com/luxfi/utxo/secp256k1fx"
|
|
)
|
|
|
|
// TestAddValidatorTxSyntacticVerify pins the AddValidatorTx invariants. Struct-
|
|
// is-wire has no post-hoc field mutation, so every (in)valid case is expressed
|
|
// by passing values THROUGH the NewAddValidatorTx constructor.
|
|
func TestAddValidatorTxSyntacticVerify(t *testing.T) {
|
|
require := require.New(t)
|
|
rt := consensustest.Runtime(t, ids.GenerateTestID())
|
|
|
|
weight := uint64(2022)
|
|
goodOwner := func() *secp256k1fx.OutputOwners {
|
|
return &secp256k1fx.OutputOwners{Threshold: 1, Addrs: []ids.ShortID{preFundedKeys[0].Address()}}
|
|
}
|
|
validator := func() Validator {
|
|
return Validator{NodeID: ids.GenerateTestNodeID(), Start: 0, End: 3600, Wght: weight}
|
|
}
|
|
stakeOut := func(assetID ids.ID, owner *secp256k1fx.OutputOwners) []*lux.TransferableOutput {
|
|
return []*lux.TransferableOutput{{
|
|
Asset: lux.Asset{ID: assetID},
|
|
Out: &secp256k1fx.TransferOutput{Amt: weight, OutputOwners: *owner},
|
|
}}
|
|
}
|
|
base := func(networkID uint32) *lux.BaseTx {
|
|
return &lux.BaseTx{NetworkID: networkID, BlockchainID: rt.ChainID}
|
|
}
|
|
|
|
// Case: signed tx is nil
|
|
var stx *Tx
|
|
require.ErrorIs(stx.SyntacticVerify(rt), ErrNilSignedTx)
|
|
|
|
// Case: unsigned tx is nil
|
|
var nilTx *AddValidatorTx
|
|
require.ErrorIs(nilTx.SyntacticVerify(rt), ErrNilTx)
|
|
|
|
// Case: valid tx
|
|
valid, err := NewAddValidatorTx(base(rt.NetworkID), validator(), stakeOut(rt.UTXOAssetID, goodOwner()), goodOwner(), reward.PercentDenominator)
|
|
require.NoError(err)
|
|
require.NoError(valid.SyntacticVerify(rt))
|
|
|
|
// Case: wrong network ID
|
|
wrongNet, err := NewAddValidatorTx(base(rt.NetworkID+1), validator(), stakeOut(rt.UTXOAssetID, goodOwner()), goodOwner(), reward.PercentDenominator)
|
|
require.NoError(err)
|
|
require.ErrorIs(wrongNet.SyntacticVerify(rt), lux.ErrWrongNetworkID)
|
|
|
|
// Case: stake owner has no addresses (unspendable stake output)
|
|
stakeNoAddr, err := NewAddValidatorTx(base(rt.NetworkID), validator(), stakeOut(rt.UTXOAssetID, &secp256k1fx.OutputOwners{Threshold: 1}), goodOwner(), reward.PercentDenominator)
|
|
require.NoError(err)
|
|
require.ErrorIs(stakeNoAddr.SyntacticVerify(rt), secp256k1fx.ErrOutputUnspendable)
|
|
|
|
// Case: rewards owner has no addresses (unspendable rewards owner)
|
|
rewardsNoAddr, err := NewAddValidatorTx(base(rt.NetworkID), validator(), stakeOut(rt.UTXOAssetID, goodOwner()), &secp256k1fx.OutputOwners{Threshold: 1}, reward.PercentDenominator)
|
|
require.NoError(err)
|
|
require.ErrorIs(rewardsNoAddr.SyntacticVerify(rt), secp256k1fx.ErrOutputUnspendable)
|
|
|
|
// Case: too many shares (1 more than max)
|
|
tooManyShares, err := NewAddValidatorTx(base(rt.NetworkID), validator(), stakeOut(rt.UTXOAssetID, goodOwner()), goodOwner(), reward.PercentDenominator+1)
|
|
require.NoError(err)
|
|
require.ErrorIs(tooManyShares.SyntacticVerify(rt), errTooManyShares)
|
|
}
|
|
|
|
func TestAddValidatorTxSyntacticVerifyNotLUX(t *testing.T) {
|
|
require := require.New(t)
|
|
rt := consensustest.Runtime(t, ids.GenerateTestID())
|
|
|
|
owner := &secp256k1fx.OutputOwners{Threshold: 1, Addrs: []ids.ShortID{preFundedKeys[0].Address()}}
|
|
weight := uint64(2022)
|
|
validator := Validator{NodeID: ids.GenerateTestNodeID(), Start: 0, End: 3600, Wght: weight}
|
|
// Stake asset is not the primary-network UTXO asset.
|
|
stakeOuts := []*lux.TransferableOutput{{
|
|
Asset: lux.Asset{ID: ids.GenerateTestID()},
|
|
Out: &secp256k1fx.TransferOutput{Amt: weight, OutputOwners: *owner},
|
|
}}
|
|
|
|
u, err := NewAddValidatorTx(&lux.BaseTx{NetworkID: rt.NetworkID, BlockchainID: rt.ChainID}, validator, stakeOuts, owner, reward.PercentDenominator)
|
|
require.NoError(err)
|
|
require.ErrorIs(u.SyntacticVerify(rt), errStakeMustBeLUX)
|
|
}
|
|
|
|
// NOTE: the codec-era TestAddValidatorTxNotDelegatorTx (asserting
|
|
// *AddValidatorTx does NOT satisfy DelegatorTx) is intentionally dropped. It
|
|
// exercised deleted behavior: under struct-is-wire, RewardsOwner changed from a
|
|
// struct FIELD to an accessor METHOD, and RewardsOwner() is the only member
|
|
// DelegatorTx needs beyond what AddValidatorTx already exposes (UnsignedTx +
|
|
// PermissionlessStaker). So *AddValidatorTx now structurally satisfies both
|
|
// ValidatorTx and DelegatorTx. This is harmless: the sole production dispatch
|
|
// (service.go getStakerAttributes) type-switches `case ValidatorTx` BEFORE
|
|
// `case DelegatorTx`, and Go evaluates cases in order, so an AddValidatorTx is
|
|
// always routed through the ValidatorTx branch (correct rewards/shares).
|
|
|
|
// TestAddValidatorTxSyntacticVerify_ArbitraryPrimaryNetworkIDs asserts that
|
|
// AddValidatorTx — the canonical post-LP-018 add-validator-to-a-network tx —
|
|
// accepts arbitrary primary networkIDs, not just the Lux primary values
|
|
// (1/2/3/1337). A sovereign L1 IS a primary network at its own networkID;
|
|
// downstream consumers may operate primary networks at any uint32 they choose.
|
|
// The tx body has no per-chain "Chain" field, so SyntacticVerify must succeed
|
|
// against any valid primary networkID.
|
|
func TestAddValidatorTxSyntacticVerify_ArbitraryPrimaryNetworkIDs(t *testing.T) {
|
|
// Lux primaries (1/2/3/1337) plus four arbitrary synthetic IDs covering
|
|
// low / mid / high uint32 ranges, to demonstrate the tx is networkID-
|
|
// agnostic without baking any downstream value into this upstream test.
|
|
primaryNetworkIDs := []uint32{
|
|
1, // Lux mainnet
|
|
2, // Lux testnet
|
|
3, // Lux local
|
|
1337, // Lux dev/localnet
|
|
9001,
|
|
123456,
|
|
7_777_777,
|
|
4_000_000_000,
|
|
}
|
|
|
|
for _, networkID := range primaryNetworkIDs {
|
|
t.Run(formatPrimaryNetworkID(networkID), func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
rt := consensustest.Runtime(t, ids.GenerateTestID())
|
|
rt.NetworkID = networkID // operate the primary network at an arbitrary ID
|
|
|
|
weight := uint64(2026)
|
|
owner := &secp256k1fx.OutputOwners{Threshold: 1, Addrs: []ids.ShortID{preFundedKeys[0].Address()}}
|
|
validator := Validator{NodeID: ids.GenerateTestNodeID(), Start: 0, End: 3600, Wght: weight}
|
|
stakeOuts := []*lux.TransferableOutput{{
|
|
Asset: lux.Asset{ID: rt.UTXOAssetID},
|
|
Out: &secp256k1fx.TransferOutput{Amt: weight, OutputOwners: *owner},
|
|
}}
|
|
|
|
u, err := NewAddValidatorTx(&lux.BaseTx{NetworkID: rt.NetworkID, BlockchainID: rt.ChainID}, validator, stakeOuts, owner, reward.PercentDenominator)
|
|
require.NoError(err)
|
|
require.NoError(u.SyntacticVerify(rt))
|
|
})
|
|
}
|
|
}
|
|
|
|
func formatPrimaryNetworkID(id uint32) string {
|
|
switch id {
|
|
case 1:
|
|
return "mainnet-1"
|
|
case 2:
|
|
return "testnet-2"
|
|
case 3:
|
|
return "local-3"
|
|
case 1337:
|
|
return "dev-1337"
|
|
default:
|
|
return fmt.Sprintf("primary-networkID-%d", id)
|
|
}
|
|
}
|