mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
External (HTTP / JSON-RPC) is the only place JSON is legitimate. Every
existing encoding/json import in node/ moves to github.com/go-json-experiment/json
(v2 root, not the v1 sub-package). NewEncoder/NewDecoder rewrite to
MarshalWrite/UnmarshalRead. MarshalIndent rewrites to Marshal with
jsontext.WithIndent. json.RawMessage rewrites to jsontext.Value.
*json.SyntaxError rewrites to *jsontext.SyntacticError.
81 files migrated. LLM.md captures the rule + v1->v2 delta table.
Known v2 semantic deltas surfaced by existing tests (followups, not regressions):
- [N]byte fields with no MarshalJSON now marshal as base64 string (v1 marshalled
as JSON array of byte numbers). Affects vms/platformvm/txs/*_test.go fixtures
with embedded BLS proofOfPossession.
- time.Duration has no v2 default representation; configs that wire-format
Duration as nanoseconds (vms/{xvm,platformvm}/config, config/spec) need to
switch to string-form Duration or carry an explicit option. v2 root does not
re-export FormatDurationAsNano.
- v2 enforces strict UTF-8 (vms/chainadapter/messaging fixture has non-UTF-8).
- json.MarshalWrite does not append a trailing '\n' (v1 NewEncoder.Encode did);
service/auth/auth_test.go expectation updated.
- nil []byte round-trips to empty (not nil); config_test deep-equal fixtures
surface this.
All affected sites are at the API boundary; ZAP wire envelope already covers
the internal data paths (state, P2P, consensus, MPC, threshold). Internal
JSON sites that should move to ZAP next (separate work):
- vms/da/store.go (DA blob/cert storage as JSON)
- vms/platformvm/airdrop (airdrop claims as JSON in db)
- vms/chainadapter/appchain (SQLite materializer schema/data blobs)
- vms/chainadapter/messaging (conversation codec)
- staking/kms.go (KMS HTTP client — external technically, leave)
- utils/{bimap,ips} (small marshaler shims — low priority)
299 lines
9.0 KiB
Go
299 lines
9.0 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package config
|
|
|
|
import (
|
|
"github.com/go-json-experiment/json"
|
|
"testing"
|
|
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestDefaultLowMemoryConfig(t *testing.T) {
|
|
config := DefaultLowMemoryConfig()
|
|
|
|
require.False(t, config.Enabled)
|
|
require.Equal(t, uint64(DefaultDBCacheSize), config.DBCacheSize)
|
|
require.Equal(t, uint64(DefaultDBMemtableSize), config.DBMemtableSize)
|
|
require.Equal(t, uint64(DefaultStateCacheSize), config.StateCacheSize)
|
|
require.Equal(t, uint64(DefaultBlockCacheSize), config.BlockCacheSize)
|
|
require.False(t, config.DisableBloomFilters)
|
|
require.False(t, config.LazyChainLoading)
|
|
require.False(t, config.SingleValidatorMode)
|
|
}
|
|
|
|
func TestNewLowMemoryConfig(t *testing.T) {
|
|
config := NewLowMemoryConfig()
|
|
|
|
require.True(t, config.Enabled)
|
|
require.Equal(t, uint64(LowMemDBCacheSize), config.DBCacheSize)
|
|
require.Equal(t, uint64(LowMemDBMemtableSize), config.DBMemtableSize)
|
|
require.Equal(t, uint64(LowMemStateCacheSize), config.StateCacheSize)
|
|
require.Equal(t, uint64(LowMemBlockCacheSize), config.BlockCacheSize)
|
|
require.True(t, config.DisableBloomFilters)
|
|
require.True(t, config.LazyChainLoading)
|
|
require.True(t, config.SingleValidatorMode)
|
|
}
|
|
|
|
func TestGetLowMemoryConfig_Default(t *testing.T) {
|
|
v := viper.New()
|
|
config := GetLowMemoryConfig(v)
|
|
|
|
require.False(t, config.Enabled)
|
|
require.Equal(t, uint64(DefaultDBCacheSize), config.DBCacheSize)
|
|
}
|
|
|
|
func TestGetLowMemoryConfig_LowMemoryEnabled(t *testing.T) {
|
|
v := viper.New()
|
|
v.Set(LowMemoryKey, true)
|
|
config := GetLowMemoryConfig(v)
|
|
|
|
require.True(t, config.Enabled)
|
|
require.Equal(t, uint64(LowMemDBCacheSize), config.DBCacheSize)
|
|
require.True(t, config.LazyChainLoading)
|
|
}
|
|
|
|
func TestGetLowMemoryConfig_DevLightEnabled(t *testing.T) {
|
|
v := viper.New()
|
|
v.Set(DevLightKey, true)
|
|
config := GetLowMemoryConfig(v)
|
|
|
|
require.True(t, config.Enabled)
|
|
require.Equal(t, uint64(LowMemDBCacheSize), config.DBCacheSize)
|
|
}
|
|
|
|
func TestGetLowMemoryConfig_ExplicitOverrides(t *testing.T) {
|
|
v := viper.New()
|
|
v.Set(LowMemoryKey, true)
|
|
v.Set(DBCacheSizeKey, uint64(32*MB))
|
|
v.Set(StateCacheSizeKey, uint64(64*MB))
|
|
|
|
config := GetLowMemoryConfig(v)
|
|
|
|
require.True(t, config.Enabled)
|
|
require.Equal(t, uint64(32*MB), config.DBCacheSize)
|
|
require.Equal(t, uint64(64*MB), config.StateCacheSize)
|
|
// Non-overridden values use low memory defaults
|
|
require.Equal(t, uint64(LowMemDBMemtableSize), config.DBMemtableSize)
|
|
}
|
|
|
|
func TestLoadConfigProfile_DevLight(t *testing.T) {
|
|
profile, err := LoadConfigProfile("dev-light")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, profile)
|
|
|
|
// Check expected keys are present
|
|
require.Contains(t, profile, "dev")
|
|
require.Contains(t, profile, "low-memory")
|
|
require.Contains(t, profile, "db-cache-size")
|
|
|
|
// Check comment fields are removed
|
|
require.NotContains(t, profile, "_comment")
|
|
require.NotContains(t, profile, "_targets")
|
|
}
|
|
|
|
func TestLoadConfigProfile_NonExistent(t *testing.T) {
|
|
profile, err := LoadConfigProfile("non-existent-profile")
|
|
require.Error(t, err)
|
|
require.Nil(t, profile)
|
|
}
|
|
|
|
func TestLoadConfigProfile_Empty(t *testing.T) {
|
|
profile, err := LoadConfigProfile("")
|
|
require.NoError(t, err)
|
|
require.Nil(t, profile)
|
|
}
|
|
|
|
func TestApplyConfigProfile(t *testing.T) {
|
|
v := viper.New()
|
|
v.Set("existing-key", "existing-value")
|
|
|
|
profile := map[string]interface{}{
|
|
"existing-key": "profile-value",
|
|
"new-key": "profile-new-value",
|
|
}
|
|
|
|
ApplyConfigProfile(v, profile)
|
|
|
|
// Existing key should not be overwritten
|
|
require.Equal(t, "existing-value", v.GetString("existing-key"))
|
|
// New key should be added
|
|
require.Equal(t, "profile-new-value", v.GetString("new-key"))
|
|
}
|
|
|
|
func TestEstimatedMemoryUsage(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config LowMemoryConfig
|
|
expectedIdle uint64
|
|
expectedLoad uint64
|
|
singleValBonus uint64
|
|
}{
|
|
{
|
|
name: "default config",
|
|
config: DefaultLowMemoryConfig(),
|
|
},
|
|
{
|
|
name: "low memory config",
|
|
config: NewLowMemoryConfig(),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
idle, load := tt.config.EstimatedMemoryUsage()
|
|
|
|
// Basic sanity checks
|
|
require.Greater(t, idle, uint64(0))
|
|
require.Greater(t, load, uint64(0))
|
|
require.Greater(t, load, idle)
|
|
|
|
// Low memory mode should have significantly lower memory usage
|
|
if tt.config.Enabled {
|
|
require.Less(t, idle, uint64(100*MB), "idle memory should be <100MB in low memory mode")
|
|
require.Less(t, load, uint64(200*MB), "load memory should be <200MB in low memory mode")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMemorySizeConstants(t *testing.T) {
|
|
// Constants are untyped, so compare as int
|
|
require.Equal(t, 1024, KB)
|
|
require.Equal(t, 1024*1024, MB)
|
|
require.Equal(t, 1024*1024*1024, GB)
|
|
|
|
// Verify low < standard < max for all settings
|
|
require.Less(t, LowMemDBCacheSize, DefaultDBCacheSize)
|
|
require.Less(t, LowMemDBMemtableSize, DefaultDBMemtableSize)
|
|
require.Less(t, LowMemStateCacheSize, DefaultStateCacheSize)
|
|
require.Less(t, LowMemBlockCacheSize, DefaultBlockCacheSize)
|
|
|
|
require.Less(t, DefaultDBCacheSize, MaxMemDBCacheSize)
|
|
require.Less(t, DefaultDBMemtableSize, MaxMemDBMemtableSize)
|
|
require.Less(t, DefaultStateCacheSize, MaxMemStateCacheSize)
|
|
require.Less(t, DefaultBlockCacheSize, MaxMemBlockCacheSize)
|
|
}
|
|
|
|
func TestMemoryProfile(t *testing.T) {
|
|
// Test low profile
|
|
lowConfig := GetMemoryConfigForProfile(MemoryProfileLow)
|
|
require.Equal(t, uint64(LowMemDBCacheSize), lowConfig.DBCacheSize)
|
|
require.True(t, lowConfig.DisableBloomFilters)
|
|
|
|
// Test standard profile
|
|
stdConfig := GetMemoryConfigForProfile(MemoryProfileStandard)
|
|
require.Equal(t, uint64(DefaultDBCacheSize), stdConfig.DBCacheSize)
|
|
require.False(t, stdConfig.DisableBloomFilters)
|
|
|
|
// Test max profile
|
|
maxConfig := GetMemoryConfigForProfile(MemoryProfileMax)
|
|
require.Equal(t, uint64(MaxMemDBCacheSize), maxConfig.DBCacheSize)
|
|
require.False(t, maxConfig.DisableBloomFilters)
|
|
}
|
|
|
|
func TestGetLowMemoryConfig_MemoryProfile(t *testing.T) {
|
|
// Test --memory-profile=low
|
|
v := viper.New()
|
|
v.Set(MemoryProfileKey, "low")
|
|
config := GetLowMemoryConfig(v)
|
|
require.True(t, config.Enabled)
|
|
require.Equal(t, uint64(LowMemDBCacheSize), config.DBCacheSize)
|
|
|
|
// Test --memory-profile=standard
|
|
v = viper.New()
|
|
v.Set(MemoryProfileKey, "standard")
|
|
config = GetLowMemoryConfig(v)
|
|
require.False(t, config.Enabled)
|
|
require.Equal(t, uint64(DefaultDBCacheSize), config.DBCacheSize)
|
|
|
|
// Test --memory-profile=max
|
|
v = viper.New()
|
|
v.Set(MemoryProfileKey, "max")
|
|
config = GetLowMemoryConfig(v)
|
|
require.False(t, config.Enabled)
|
|
require.Equal(t, uint64(MaxMemDBCacheSize), config.DBCacheSize)
|
|
}
|
|
|
|
func TestBuildDatabaseConfigBytes_Disabled(t *testing.T) {
|
|
v := viper.New()
|
|
// Low memory not enabled and no explicit DB settings
|
|
|
|
configBytes, err := buildDatabaseConfigBytes(v)
|
|
require.NoError(t, err)
|
|
require.Nil(t, configBytes)
|
|
}
|
|
|
|
func TestBuildDatabaseConfigBytes_LowMemoryEnabled(t *testing.T) {
|
|
v := viper.New()
|
|
v.Set(LowMemoryKey, true)
|
|
|
|
configBytes, err := buildDatabaseConfigBytes(v)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, configBytes)
|
|
|
|
// Verify JSON can be parsed and has expected structure
|
|
var cfg map[string]interface{}
|
|
err = json.Unmarshal(configBytes, &cfg)
|
|
require.NoError(t, err)
|
|
|
|
// Check that reduced memory settings are present
|
|
require.Contains(t, cfg, "memTableSize")
|
|
require.Contains(t, cfg, "blockCacheSize")
|
|
require.Contains(t, cfg, "indexCacheSize")
|
|
require.Contains(t, cfg, "numMemtables")
|
|
require.Contains(t, cfg, "numCompactors")
|
|
require.Contains(t, cfg, "bloomFalsePositive")
|
|
|
|
// Verify values are low memory settings
|
|
memTableSize := int64(cfg["memTableSize"].(float64))
|
|
require.Equal(t, int64(LowMemDBMemtableSize), memTableSize)
|
|
|
|
blockCacheSize := int64(cfg["blockCacheSize"].(float64))
|
|
require.Equal(t, int64(LowMemDBCacheSize), blockCacheSize)
|
|
|
|
numMemtables := int(cfg["numMemtables"].(float64))
|
|
require.Equal(t, 2, numMemtables) // Reduced from default 5
|
|
}
|
|
|
|
func TestBuildDatabaseConfigBytes_BloomFiltersDisabled(t *testing.T) {
|
|
v := viper.New()
|
|
v.Set(LowMemoryKey, true)
|
|
v.Set(DisableBloomFiltersKey, true)
|
|
|
|
configBytes, err := buildDatabaseConfigBytes(v)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, configBytes)
|
|
|
|
var cfg map[string]interface{}
|
|
err = json.Unmarshal(configBytes, &cfg)
|
|
require.NoError(t, err)
|
|
|
|
// Bloom false positive should be 1.0 (effectively disabled)
|
|
bloomFP := cfg["bloomFalsePositive"].(float64)
|
|
require.Equal(t, 1.0, bloomFP)
|
|
}
|
|
|
|
func TestBuildDatabaseConfigBytes_ExplicitOverrides(t *testing.T) {
|
|
v := viper.New()
|
|
v.Set(DBCacheSizeKey, uint64(16*MB))
|
|
v.Set(DBMemtableSizeKey, uint64(16*MB))
|
|
|
|
configBytes, err := buildDatabaseConfigBytes(v)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, configBytes)
|
|
|
|
var cfg map[string]interface{}
|
|
err = json.Unmarshal(configBytes, &cfg)
|
|
require.NoError(t, err)
|
|
|
|
// Verify explicit overrides are used
|
|
blockCacheSize := int64(cfg["blockCacheSize"].(float64))
|
|
require.Equal(t, int64(16*MB), blockCacheSize)
|
|
|
|
memTableSize := int64(cfg["memTableSize"].(float64))
|
|
require.Equal(t, int64(16*MB), memTableSize)
|
|
}
|