Files
node/vms/platformvm/txs/add_chain_validator_test.go
T
Hanzo AI 8de1b78ed8 refactor: migrate UTXO components to standalone github.com/luxfi/utxo
One place, one way to define UTXO primitives. Delete the in-tree duplicate
at node/vms/components/lux/ and import the standalone luxfi/utxo package
with a 'lux' alias so existing call-sites (lux.UTXO, lux.TransferableInput,
etc.) remain unchanged in consumers.

Files changed: 167 imports rewritten, 2 directories deleted.

Build still green on the whole tree except pre-existing examples/multi-network
QChainMainnetID issue (unrelated).

Next: rename luxfi/utxo/luxmock → utxomock for full brand-neutrality; that
is a separate PR since it requires touching all consumer alias names.
2026-04-13 06:47:35 -07:00

246 lines
6.7 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package txs
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/luxfi/runtime"
"github.com/luxfi/constants"
"github.com/luxfi/crypto/secp256k1"
"github.com/luxfi/ids"
lux "github.com/luxfi/utxo"
"github.com/luxfi/timer/mockable"
"github.com/luxfi/utxo/secp256k1fx"
)
// Note: Consider refactoring to use table tests for better test organization
func TestAddChainValidatorTxSyntacticVerify(t *testing.T) {
require := require.New(t)
clk := mockable.Clock{}
nodeID := ids.GenerateTestNodeID()
testChainID := ids.GenerateTestID() // Use a test chain ID instead of empty
rt := &runtime.Runtime{
NetworkID: constants.UnitTestID,
ChainID: testChainID,
NodeID: nodeID,
}
signers := [][]*secp256k1.PrivateKey{preFundedKeys}
var (
stx *Tx
addNetValidatorTx *AddChainValidatorTx
err error
)
// Case : signed tx is nil
err = stx.SyntacticVerify(rt)
require.ErrorIs(err, ErrNilSignedTx)
// Case : unsigned tx is nil
err = addNetValidatorTx.SyntacticVerify(rt)
require.ErrorIs(err, ErrNilTx)
validatorWeight := uint64(2022)
netID := ids.ID{'s', 'u', 'b', 'n', 'e', 't', 'I', 'D'}
inputs := []*lux.TransferableInput{{
UTXOID: lux.UTXOID{
TxID: ids.ID{'t', 'x', 'I', 'D'},
OutputIndex: 2,
},
Asset: lux.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}},
In: &secp256k1fx.TransferInput{
Amt: uint64(5678),
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
},
}}
outputs := []*lux.TransferableOutput{{
Asset: lux.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}},
Out: &secp256k1fx.TransferOutput{
Amt: uint64(1234),
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{preFundedKeys[0].Address()},
},
},
}}
chainAuth := &secp256k1fx.Input{
SigIndices: []uint32{0, 1},
}
addNetValidatorTx = &AddChainValidatorTx{
BaseTx: BaseTx{BaseTx: lux.BaseTx{
NetworkID: rt.NetworkID,
BlockchainID: rt.ChainID,
Ins: inputs,
Outs: outputs,
Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8},
}},
ChainValidator: ChainValidator{
Validator: Validator{
NodeID: nodeID,
Start: uint64(clk.Time().Unix()),
End: uint64(clk.Time().Add(time.Hour).Unix()),
Wght: validatorWeight,
},
Chain: netID,
},
ChainAuth: chainAuth,
}
// Case: valid tx
stx, err = NewSigned(addNetValidatorTx, Codec, signers)
require.NoError(err)
require.NoError(stx.SyntacticVerify(rt))
// Case: Wrong network ID
addNetValidatorTx.SyntacticallyVerified = false
addNetValidatorTx.NetworkID++
stx, err = NewSigned(addNetValidatorTx, Codec, signers)
require.NoError(err)
err = stx.SyntacticVerify(rt)
require.ErrorIs(err, lux.ErrWrongNetworkID)
addNetValidatorTx.NetworkID--
// Case: Specifies primary network ChainID
addNetValidatorTx.SyntacticallyVerified = false
addNetValidatorTx.Chain = ids.Empty
stx, err = NewSigned(addNetValidatorTx, Codec, signers)
require.NoError(err)
err = stx.SyntacticVerify(rt)
require.ErrorIs(err, errAddPrimaryNetworkValidator)
addNetValidatorTx.Chain = netID
// Case: No weight
addNetValidatorTx.SyntacticallyVerified = false
addNetValidatorTx.Wght = 0
stx, err = NewSigned(addNetValidatorTx, Codec, signers)
require.NoError(err)
err = stx.SyntacticVerify(rt)
require.ErrorIs(err, ErrWeightTooSmall)
addNetValidatorTx.Wght = validatorWeight
// Case: Net auth indices not unique
addNetValidatorTx.SyntacticallyVerified = false
input := addNetValidatorTx.ChainAuth.(*secp256k1fx.Input)
oldInput := *input
input.SigIndices[0] = input.SigIndices[1]
stx, err = NewSigned(addNetValidatorTx, Codec, signers)
require.NoError(err)
err = stx.SyntacticVerify(rt)
require.ErrorIs(err, secp256k1fx.ErrInputIndicesNotSortedUnique)
*input = oldInput
// Case: adding to Primary Network
addNetValidatorTx.SyntacticallyVerified = false
addNetValidatorTx.Chain = constants.PrimaryNetworkID
stx, err = NewSigned(addNetValidatorTx, Codec, signers)
require.NoError(err)
err = stx.SyntacticVerify(rt)
require.ErrorIs(err, errAddPrimaryNetworkValidator)
}
func TestAddNetValidatorMarshal(t *testing.T) {
require := require.New(t)
clk := mockable.Clock{}
nodeID := ids.GenerateTestNodeID()
testChainID := ids.GenerateTestID() // Use a test chain ID instead of empty
rt := &runtime.Runtime{
NetworkID: constants.UnitTestID,
ChainID: testChainID,
NodeID: nodeID,
}
signers := [][]*secp256k1.PrivateKey{preFundedKeys}
var (
stx *Tx
addNetValidatorTx *AddChainValidatorTx
err error
)
// create a valid tx
validatorWeight := uint64(2022)
netID := ids.ID{'s', 'u', 'b', 'n', 'e', 't', 'I', 'D'}
inputs := []*lux.TransferableInput{{
UTXOID: lux.UTXOID{
TxID: ids.ID{'t', 'x', 'I', 'D'},
OutputIndex: 2,
},
Asset: lux.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}},
In: &secp256k1fx.TransferInput{
Amt: uint64(5678),
Input: secp256k1fx.Input{SigIndices: []uint32{0}},
},
}}
outputs := []*lux.TransferableOutput{{
Asset: lux.Asset{ID: ids.ID{'a', 's', 's', 'e', 't'}},
Out: &secp256k1fx.TransferOutput{
Amt: uint64(1234),
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{preFundedKeys[0].Address()},
},
},
}}
chainAuth := &secp256k1fx.Input{
SigIndices: []uint32{0, 1},
}
addNetValidatorTx = &AddChainValidatorTx{
BaseTx: BaseTx{BaseTx: lux.BaseTx{
NetworkID: rt.NetworkID,
BlockchainID: rt.ChainID,
Ins: inputs,
Outs: outputs,
Memo: []byte{1, 2, 3, 4, 5, 6, 7, 8},
}},
ChainValidator: ChainValidator{
Validator: Validator{
NodeID: nodeID,
Start: uint64(clk.Time().Unix()),
End: uint64(clk.Time().Add(time.Hour).Unix()),
Wght: validatorWeight,
},
Chain: netID,
},
ChainAuth: chainAuth,
}
// Case: valid tx
stx, err = NewSigned(addNetValidatorTx, Codec, signers)
require.NoError(err)
require.NoError(stx.SyntacticVerify(rt))
txBytes, err := Codec.Marshal(CodecVersion, stx)
require.NoError(err)
parsedTx, err := Parse(Codec, txBytes)
require.NoError(err)
require.NoError(parsedTx.SyntacticVerify(rt))
require.Equal(stx, parsedTx)
}
func TestAddChainValidatorTxNotValidatorTx(t *testing.T) {
txIntf := any((*AddChainValidatorTx)(nil))
_, ok := txIntf.(ValidatorTx)
require.False(t, ok)
}
func TestAddChainValidatorTxNotDelegatorTx(t *testing.T) {
txIntf := any((*AddChainValidatorTx)(nil))
_, ok := txIntf.(DelegatorTx)
require.False(t, ok)
}
func TestAddChainValidatorTxNotPermissionlessStaker(t *testing.T) {
txIntf := any((*AddChainValidatorTx)(nil))
_, ok := txIntf.(PermissionlessStaker)
require.False(t, ok)
}