Files
node/vms/platformvm/state/l1_validator_test.go
zeekayandHanzo Dev b1cc108c9f gofmt
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 01:51:51 -07:00

247 lines
7.5 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package state
import (
"math/rand"
"testing"
"github.com/stretchr/testify/require"
"github.com/luxfi/container/maybe"
"github.com/luxfi/crypto/bls"
"github.com/luxfi/database"
"github.com/luxfi/database/memdb"
"github.com/luxfi/ids"
"github.com/luxfi/node/cache"
"github.com/luxfi/node/cache/lru"
"github.com/luxfi/util"
)
func TestL1Validator_Compare(t *testing.T) {
tests := []struct {
name string
v L1Validator
o L1Validator
expected int
}{
{
name: "v.EndAccumulatedFee < o.EndAccumulatedFee",
v: L1Validator{
ValidationID: ids.GenerateTestID(),
EndAccumulatedFee: 1,
},
o: L1Validator{
ValidationID: ids.GenerateTestID(),
EndAccumulatedFee: 2,
},
expected: -1,
},
{
name: "v.EndAccumulatedFee = o.EndAccumulatedFee, v.ValidationID < o.ValidationID",
v: L1Validator{
ValidationID: ids.ID{0},
EndAccumulatedFee: 1,
},
o: L1Validator{
ValidationID: ids.ID{1},
EndAccumulatedFee: 1,
},
expected: -1,
},
{
name: "v.EndAccumulatedFee = o.EndAccumulatedFee, v.ValidationID = o.ValidationID",
v: L1Validator{
ValidationID: ids.ID{0},
EndAccumulatedFee: 1,
},
o: L1Validator{
ValidationID: ids.ID{0},
EndAccumulatedFee: 1,
},
expected: 0,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)
require.Equal(test.expected, test.v.Compare(test.o))
require.Equal(-test.expected, test.o.Compare(test.v))
require.Equal(test.expected == -1, test.v.Less(test.o))
require.False(test.o.Less(test.v))
})
}
}
func TestL1Validator_immutableFieldsAreUnmodified(t *testing.T) {
var (
randomizeL1Validator = func(l1Validator L1Validator) L1Validator {
// Randomize unrelated fields
l1Validator.Weight = rand.Uint64() // #nosec G404
l1Validator.MinNonce = rand.Uint64() // #nosec G404
l1Validator.EndAccumulatedFee = rand.Uint64() // #nosec G404
return l1Validator
}
l1Validator = newL1Validator()
)
t.Run("equal", func(t *testing.T) {
v := randomizeL1Validator(l1Validator)
require.True(t, l1Validator.immutableFieldsAreUnmodified(v))
})
t.Run("everything is different", func(t *testing.T) {
v := randomizeL1Validator(newL1Validator())
require.True(t, l1Validator.immutableFieldsAreUnmodified(v))
})
t.Run("different chainID", func(t *testing.T) {
v := randomizeL1Validator(l1Validator)
v.ChainID = ids.GenerateTestID()
require.False(t, l1Validator.immutableFieldsAreUnmodified(v))
})
t.Run("different nodeID", func(t *testing.T) {
v := randomizeL1Validator(l1Validator)
v.NodeID = ids.GenerateTestNodeID()
require.False(t, l1Validator.immutableFieldsAreUnmodified(v))
})
t.Run("different publicKey", func(t *testing.T) {
v := randomizeL1Validator(l1Validator)
v.PublicKey = utils.RandomBytes(bls.PublicKeyLen)
require.False(t, l1Validator.immutableFieldsAreUnmodified(v))
})
t.Run("different remainingBalanceOwner", func(t *testing.T) {
v := randomizeL1Validator(l1Validator)
v.RemainingBalanceOwner = utils.RandomBytes(32)
require.False(t, l1Validator.immutableFieldsAreUnmodified(v))
})
t.Run("different deactivationOwner", func(t *testing.T) {
v := randomizeL1Validator(l1Validator)
v.DeactivationOwner = utils.RandomBytes(32)
require.False(t, l1Validator.immutableFieldsAreUnmodified(v))
})
t.Run("different startTime", func(t *testing.T) {
v := randomizeL1Validator(l1Validator)
v.StartTime = rand.Uint64() // #nosec G404
require.False(t, l1Validator.immutableFieldsAreUnmodified(v))
})
}
func TestGetL1Validator(t *testing.T) {
var (
l1Validator = newL1Validator()
dbWithL1Validator = memdb.New()
dbWithoutL1Validator = memdb.New()
cacheWithL1Validator = lru.NewCache[ids.ID, maybe.Maybe[L1Validator]](10)
cacheWithoutL1Validator = lru.NewCache[ids.ID, maybe.Maybe[L1Validator]](10)
)
require.NoError(t, putL1Validator(dbWithL1Validator, cacheWithL1Validator, l1Validator))
require.NoError(t, deleteL1Validator(dbWithoutL1Validator, cacheWithoutL1Validator, l1Validator.ValidationID))
tests := []struct {
name string
cache cache.Cacher[ids.ID, maybe.Maybe[L1Validator]]
db database.KeyValueReader
expectedL1Validator L1Validator
expectedErr error
expectedEntry maybe.Maybe[L1Validator]
}{
{
name: "cached with validator",
cache: cacheWithL1Validator,
db: dbWithoutL1Validator,
expectedL1Validator: l1Validator,
expectedEntry: maybe.Some(l1Validator),
},
{
name: "from disk with validator",
cache: lru.NewCache[ids.ID, maybe.Maybe[L1Validator]](10),
db: dbWithL1Validator,
expectedL1Validator: l1Validator,
expectedEntry: maybe.Some(l1Validator),
},
{
name: "cached without validator",
cache: cacheWithoutL1Validator,
db: dbWithL1Validator,
expectedErr: database.ErrNotFound,
},
{
name: "from disk without validator",
cache: lru.NewCache[ids.ID, maybe.Maybe[L1Validator]](10),
db: dbWithoutL1Validator,
expectedErr: database.ErrNotFound,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)
gotL1Validator, err := getL1Validator(test.cache, test.db, l1Validator.ValidationID)
require.ErrorIs(err, test.expectedErr)
require.Equal(test.expectedL1Validator, gotL1Validator)
cachedL1Validator, ok := test.cache.Get(l1Validator.ValidationID)
require.True(ok)
require.Equal(test.expectedEntry, cachedL1Validator)
})
}
}
func TestPutL1Validator(t *testing.T) {
var (
require = require.New(t)
l1Validator = newL1Validator()
db = memdb.New()
cache = lru.NewCache[ids.ID, maybe.Maybe[L1Validator]](10)
)
expectedL1ValidatorBytes, err := marshalL1Validator(l1Validator)
require.NoError(err)
require.NoError(putL1Validator(db, cache, l1Validator))
l1ValidatorBytes, err := db.Get(l1Validator.ValidationID[:])
require.NoError(err)
require.Equal(expectedL1ValidatorBytes, l1ValidatorBytes)
l1ValidatorFromCache, ok := cache.Get(l1Validator.ValidationID)
require.True(ok)
require.Equal(maybe.Some(l1Validator), l1ValidatorFromCache)
}
func TestDeleteL1Validator(t *testing.T) {
var (
require = require.New(t)
validationID = ids.GenerateTestID()
db = memdb.New()
cache = lru.NewCache[ids.ID, maybe.Maybe[L1Validator]](10)
)
require.NoError(db.Put(validationID[:], nil))
require.NoError(deleteL1Validator(db, cache, validationID))
hasL1Validator, err := db.Has(validationID[:])
require.NoError(err)
require.False(hasL1Validator)
l1ValidatorFromCache, ok := cache.Get(validationID)
require.True(ok)
require.Equal(maybe.Nothing[L1Validator](), l1ValidatorFromCache)
}
func newL1Validator() L1Validator {
return L1Validator{
ValidationID: ids.GenerateTestID(),
ChainID: ids.GenerateTestID(),
NodeID: ids.GenerateTestNodeID(),
PublicKey: utils.RandomBytes(bls.PublicKeyLen),
RemainingBalanceOwner: utils.RandomBytes(32),
DeactivationOwner: utils.RandomBytes(32),
StartTime: rand.Uint64(), // #nosec G404
Weight: rand.Uint64(), // #nosec G404
MinNonce: rand.Uint64(), // #nosec G404
EndAccumulatedFee: rand.Uint64(), // #nosec G404
}
}