Files
zeekayandHanzo Dev 9ababce758 A precompile's config key names the precompile
Forty-five of the fifty-six suite modules keyed off <name>Config and eleven did
not, in three other spellings: Verify, Threshold, Encapsulate. The LP-4200
unified PQCrypto block carried four of those conventions across its eight
addresses — two KEMs named differently (mlkemConfig beside hqcEncapsulate) and
two threshold schemes named differently (pulsarVerify beside coronaThreshold) —
so the block that exists to be one thing did not read as one thing.

The deviations also named an OPERATION where a precompile belongs. HQC
decapsulates as well as encapsulates and the Verify precompiles do more than
verify, so hqcEncapsulate was the name of one entry point standing in for the
whole module. A config key selects a precompile; it is not a method selector.

All fifty-six are <name>Config now. There is no compatibility shim: an
upgrade.json naming an old key is naming something that does not exist, which
luxd already refuses loudly, and every chain config in the estate moves with this.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 19:27:25 -07:00

103 lines
4.1 KiB
Go

// Copyright (C) 2025-2026, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package magnetar
import (
"testing"
"github.com/luxfi/precompile/modules"
"github.com/luxfi/precompile/precompileconfig"
"github.com/stretchr/testify/require"
)
// fakeConfig is a Config-shaped value from another precompile. Equal must
// refuse it: two precompiles whose configs compared equal would let an upgrade
// for one be accepted as an upgrade for the other.
type fakeConfig struct{}
func (f *fakeConfig) Key() string { return "fake" }
func (f *fakeConfig) Timestamp() *uint64 { return nil }
func (f *fakeConfig) IsDisabled() bool { return false }
func (f *fakeConfig) Equal(precompileconfig.Config) bool { return false }
func (f *fakeConfig) Verify(precompileconfig.ChainConfig) error { return nil }
type testChainCfg struct{}
func (t *testChainCfg) IsDurango(uint64) bool { return true }
// TestConfigLifecycle covers the upgrade surface the chain config machinery
// drives: the key it is filed under, the activation timestamp, the disable
// switch, and the equality the upgrade reconciler uses to decide whether a
// config changed.
func TestConfigLifecycle(t *testing.T) {
cfg := &Config{}
require.Equal(t, ConfigKey, cfg.Key())
require.Equal(t, "magnetarConfig", cfg.Key())
require.Nil(t, cfg.Timestamp())
require.False(t, cfg.IsDisabled())
require.NoError(t, cfg.Verify(&testChainCfg{}))
require.True(t, cfg.Equal(&Config{}))
require.False(t, cfg.Equal(&fakeConfig{}), "a foreign config type is never equal")
require.False(t, cfg.Equal(nil), "a nil config is never equal")
ts := uint64(42)
at := &Config{Upgrade: precompileconfig.Upgrade{BlockTimestamp: &ts}}
require.Equal(t, &ts, at.Timestamp())
require.False(t, at.IsDisabled())
require.False(t, cfg.Equal(at), "configs activating at different times differ")
require.False(t, at.Equal(cfg))
other := uint64(43)
require.False(t, at.Equal(&Config{Upgrade: precompileconfig.Upgrade{BlockTimestamp: &other}}))
require.True(t, at.Equal(&Config{Upgrade: precompileconfig.Upgrade{BlockTimestamp: &ts}}))
off := &Config{Upgrade: precompileconfig.Upgrade{Disable: true}}
require.True(t, off.IsDisabled())
require.False(t, cfg.Equal(off), "a disabling config differs from an enabling one")
}
// TestConfigurator covers the two calls the module machinery makes: minting a
// fresh config to decode JSON into, and applying it at the activation block.
// Magnetar is a pure verifier with no genesis state, so Configure writes
// nothing and must succeed even with a nil StateDB.
func TestConfigurator(t *testing.T) {
c := &configurator{}
cfg := c.MakeConfig()
require.NotNil(t, cfg)
require.IsType(t, &Config{}, cfg)
require.Equal(t, ConfigKey, cfg.Key())
require.NotSame(t, cfg, c.MakeConfig(), "each call must mint a fresh config")
require.NoError(t, c.Configure(&testChainCfg{}, cfg, nil, nil))
}
// TestModuleRegistration checks that init put the precompile in the registry
// under its own key and its own address, and that both lookups return the same
// module -- the address is what the EVM dispatches on, the key is what the
// chain config names.
func TestModuleRegistration(t *testing.T) {
byKey, ok := modules.GetPrecompileModule(ConfigKey)
require.True(t, ok, "module %q is not registered", ConfigKey)
require.Equal(t, ContractMagnetarVerifyAddress, byKey.Address)
require.Equal(t, MagnetarVerifyPrecompile, byKey.Contract)
byAddr, ok := modules.GetPrecompileModuleByAddress(ContractMagnetarVerifyAddress)
require.True(t, ok, "no module at slot 0x012207")
require.Equal(t, ConfigKey, byAddr.ConfigKey)
require.Equal(t, byKey, byAddr)
require.IsType(t, &Config{}, byKey.Configurator.MakeConfig())
// The registry refuses a second module on the same key or address, which
// is what makes init's panic arm the right response to a collision.
require.Error(t, modules.RegisterModule(modules.Module{
ConfigKey: ConfigKey,
Address: ContractMagnetarVerifyAddress,
Contract: MagnetarVerifyPrecompile,
Configurator: &configurator{},
}), "registering the same key twice must be refused")
}