mirror of
https://github.com/luxfi/genesis.git
synced 2026-07-27 05:54:08 +00:00
chainid: add EVMChainIDFor(brand, env string) string-input helper
LP-018 §Canonical EVM chainID map specifies the (brand × env) → uint64
table. The existing typed lookup EVMChainID(family, env) takes a
NetworkFamily + uint32; CRD validators, admission webhooks, and
operator-side helpers often hold brand+env as raw strings instead.
EVMChainIDFor wraps EVMChainID with case-insensitive string parsing for
both brand and env ("mainnet"|"main", "testnet"|"test", etc.). No
parallel data table — one source of truth.
Also retire stale "sovereign=true|false per LP-182" docstrings on
Family* constants; the locked NetworkSpec carries only networkID +
validators, and FamilyLiquid/FamilyPars can run as either Anchored
(validators > 0 on a Lux primary) or Independent (own networkID).
Update LP-182 references to LP-018 (LP-182 archived).
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
// Copyright (C) 2024-2026, Lux Partners Limited. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// LP-182 §Appendix A — canonical EVM chainID map per (network family,
|
||||
// environment) tuple. This is the source of truth that operator CRs
|
||||
// and per-network genesis blobs must agree with; a misconfigured
|
||||
// `NetworkSpec.EVMChainID` that does not appear in this map is an
|
||||
// authoring error.
|
||||
// LP-018 §Canonical EVM chainID map — per (network family, environment)
|
||||
// tuple. This is the source of truth that operator CRs and per-network
|
||||
// genesis blobs must agree with; a misconfigured `NetworkSpec.EVMChainID`
|
||||
// that does not appear in this map is an authoring error.
|
||||
//
|
||||
// One source of truth, one way to look up: pass a (family, env) pair,
|
||||
// get back the EVMChainID (or 0 for "unknown / TBD"). The map covers
|
||||
// every brand-X-environment cell at LP-182 publication time; new cells
|
||||
// every brand-X-environment cell at LP-018 publication time; new cells
|
||||
// land here when the corresponding genesis configs land in the
|
||||
// embedded tree.
|
||||
|
||||
@@ -27,27 +26,28 @@ const (
|
||||
// FamilyLux is the Lux primary network family (C-Chain).
|
||||
FamilyLux NetworkFamily = "lux"
|
||||
// FamilyHanzo is the Hanzo L2 family hosted on the Lux primary
|
||||
// network's validator set (sovereign=false per LP-182).
|
||||
// network's validator set (validators==0 per LP-018).
|
||||
FamilyHanzo NetworkFamily = "hanzo"
|
||||
// FamilyZoo is the Zoo L2 family hosted on the Lux primary network's
|
||||
// validator set (sovereign=false per LP-182).
|
||||
// validator set (validators==0 per LP-018).
|
||||
FamilyZoo NetworkFamily = "zoo"
|
||||
// FamilySPC is the SPC L2 family hosted on the Lux primary network's
|
||||
// validator set (sovereign=false per LP-182).
|
||||
// validator set (validators==0 per LP-018).
|
||||
FamilySPC NetworkFamily = "spc"
|
||||
// FamilyLiquid is the Liquid sovereign L1 family with its own
|
||||
// validator set (sovereign=true per LP-182).
|
||||
// FamilyLiquid is the Liquid network family. Runs as Anchored on a
|
||||
// Lux primary (validators>0 with networkID in {1,2,3,1337}) or as
|
||||
// Independent (own networkID = 8675309/8675310/8675312 per env).
|
||||
FamilyFamily = "liquid"
|
||||
// FamilyPars is the Pars sovereign L1 family with its own validator
|
||||
// set (sovereign=true per LP-182).
|
||||
// FamilyPars is the Pars network family. Runs as Anchored on a Lux
|
||||
// primary or as Independent — same dual-mode option as Liquid.
|
||||
FamilyPars NetworkFamily = "pars"
|
||||
// FamilyOsage is the Osage sovereign L1 family (placeholder pending
|
||||
// FamilyOsage is the Osage network family (placeholder pending
|
||||
// genesis publication).
|
||||
FamilyOsage NetworkFamily = "osage"
|
||||
)
|
||||
|
||||
// EVMChainID returns the canonical EVM chainID for a (family, env)
|
||||
// tuple per LP-182 §Appendix A. The env argument MUST be one of
|
||||
// tuple per LP-018 §Canonical EVM chainID map. The env argument MUST be one of
|
||||
// MainnetID / TestnetID / DevnetID / LocalID (the four canonical
|
||||
// primary network IDs). Any other value returns (0, false).
|
||||
//
|
||||
@@ -118,14 +118,14 @@ func EVMChainID(family NetworkFamily, env uint32) (uint64, bool) {
|
||||
case DevnetID:
|
||||
return 494951, true
|
||||
}
|
||||
// Osage cells are TBD as of LP-182 publication; lookup returns
|
||||
// Osage cells are TBD as of LP-018 publication; lookup returns
|
||||
// (0, false) until the genesis configs land here.
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// NetworkFamilyOf returns the canonical NetworkFamily for a chainID,
|
||||
// per LP-182 §Appendix A. The first uint64 → family mapping that
|
||||
// per LP-018 §Canonical EVM chainID map. The first uint64 → family mapping that
|
||||
// matches wins. The boolean is false when no family claims the
|
||||
// chainID (caller must surface this as an authoring error).
|
||||
//
|
||||
@@ -174,3 +174,32 @@ func ParseNetworkFamily(s string) (NetworkFamily, bool) {
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// EVMChainIDFor is the string-input convenience over EVMChainID for
|
||||
// callers that hold brand+env as text (CRD validators, operator-side
|
||||
// helpers, k8s admission webhooks). Case-insensitive on brand.
|
||||
//
|
||||
// env must be one of "mainnet", "testnet", "devnet", "localnet" (case-
|
||||
// insensitive). Any other env or unknown brand returns (0, false). One
|
||||
// way to look up by string; delegates to the typed EVMChainID — there
|
||||
// is no parallel data table.
|
||||
func EVMChainIDFor(brand, env string) (uint64, bool) {
|
||||
fam, ok := ParseNetworkFamily(brand)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
var envID uint32
|
||||
switch strings.ToLower(env) {
|
||||
case "mainnet", "main":
|
||||
envID = MainnetID
|
||||
case "testnet", "test":
|
||||
envID = TestnetID
|
||||
case "devnet", "dev":
|
||||
envID = DevnetID
|
||||
case "localnet", "local":
|
||||
envID = LocalID
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
return EVMChainID(fam, envID)
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ package configs
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestEVMChainID_KnownCells locks the canonical map per LP-182
|
||||
// §Appendix A. Any change to these values is a backward-incompatible
|
||||
// chainID rebrand and would replay-protect-conflict with
|
||||
// already-deployed contracts; this test is the protective floor.
|
||||
// TestEVMChainID_KnownCells locks the canonical map per LP-018
|
||||
// §Canonical EVM chainID map. Any change to these values is a
|
||||
// backward-incompatible chainID rebrand and would replay-protect-conflict
|
||||
// with already-deployed contracts; this test is the protective floor.
|
||||
func TestEVMChainID_KnownCells(t *testing.T) {
|
||||
cases := []struct {
|
||||
family NetworkFamily
|
||||
@@ -50,6 +50,9 @@ func TestEVMChainID_KnownCells(t *testing.T) {
|
||||
// TestEVMChainID_UnknownReturnsFalse — an unknown family or an env
|
||||
// outside the canonical four must return (0, false), not a silent
|
||||
// default. This protects against typos in operator CRs.
|
||||
//
|
||||
// (Filename retains lp182_ prefix because that was the file's name at
|
||||
// commit time and the rename produces churn unrelated to behavior.)
|
||||
func TestEVMChainID_UnknownReturnsFalse(t *testing.T) {
|
||||
if got, ok := EVMChainID(NetworkFamily("bogus"), MainnetID); ok || got != 0 {
|
||||
t.Errorf("EVMChainID(bogus, mainnet) = (%d, %v), want (0, false)", got, ok)
|
||||
@@ -123,3 +126,60 @@ func TestParseNetworkFamily_CaseInsensitive(t *testing.T) {
|
||||
t.Errorf("ParseNetworkFamily(bogus) = (%q, %v), want (\"\", false)", got, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// TestEVMChainIDFor_StringInputs locks the string-input convenience
|
||||
// wrapper to the full LP-182 §Appendix A table. This is the API
|
||||
// CRD validators / operator webhooks call.
|
||||
func TestEVMChainIDFor_StringInputs(t *testing.T) {
|
||||
cases := []struct {
|
||||
brand, env string
|
||||
want uint64
|
||||
}{
|
||||
{"lux", "mainnet", 96369},
|
||||
{"lux", "testnet", 96368},
|
||||
{"lux", "devnet", 96370},
|
||||
{"lux", "localnet", 31337},
|
||||
{"LUX", "MAINNET", 96369},
|
||||
{"Lux", "Main", 96369},
|
||||
{"hanzo", "mainnet", 36963},
|
||||
{"hanzo", "testnet", 36962},
|
||||
{"hanzo", "devnet", 36964},
|
||||
{"zoo", "mainnet", 200200},
|
||||
{"zoo", "testnet", 200201},
|
||||
{"zoo", "devnet", 200202},
|
||||
{"spc", "mainnet", 36911},
|
||||
{"spc", "testnet", 36910},
|
||||
{"spc", "devnet", 36912},
|
||||
{"liquid", "mainnet", 8675309},
|
||||
{"liquid", "testnet", 8675310},
|
||||
{"liquid", "devnet", 8675312},
|
||||
{"pars", "mainnet", 7070},
|
||||
{"pars", "testnet", 494950},
|
||||
{"pars", "devnet", 494951},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got, ok := EVMChainIDFor(c.brand, c.env)
|
||||
if !ok {
|
||||
t.Errorf("EVMChainIDFor(%q,%q) = (_, false), want (%d, true)", c.brand, c.env, c.want)
|
||||
continue
|
||||
}
|
||||
if got != c.want {
|
||||
t.Errorf("EVMChainIDFor(%q,%q) = %d, want %d", c.brand, c.env, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestEVMChainIDFor_UnknownReturnsFalse — typos and TBD cells return
|
||||
// (0, false) instead of a silent default.
|
||||
func TestEVMChainIDFor_UnknownReturnsFalse(t *testing.T) {
|
||||
for _, c := range []struct{ brand, env string }{
|
||||
{"bogus", "mainnet"},
|
||||
{"lux", "bogus"},
|
||||
{"hanzo", "localnet"}, // hanzo has no localnet cell
|
||||
{"", ""},
|
||||
} {
|
||||
if got, ok := EVMChainIDFor(c.brand, c.env); ok || got != 0 {
|
||||
t.Errorf("EVMChainIDFor(%q,%q) = (%d, %v), want (0, false)", c.brand, c.env, got, ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user