mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
params/extras: relaunch-safety test + regenerate canonical upgrade fixtures
Round-2 follow-up to the luxfi/genesis upgrade.json reschedule fix (17 live-at-genesis precompiles pinned to blockTimestamp 0; warp two-step strict-PQ toggle moved after the zero-timestamp block; dead dexConfig 0x9010 dropped). - relaunch_safety_test.go (new): drives the node's REAL fork-application primitive extras.IsForkTransition (parent=nil reduces to fork <= genesisTime, exactly what GetActivatingPrecompileConfigs evaluates when a relaunched node builds its first rule set) against the embedded canonical fixtures. Asserts the invariant: every precompile that activates at/under the C-Chain genesis time (mainnet 1730446786 / testnet 1730517266) is in the live-at-block-0 set AND pinned to exactly 0; every other entry is strictly future; and all 17 live precompiles are present (no relaunch divergence). No entry sits in the (0, genesisTime] retroactive-reschedule window. - mainnet_upgrade_v46.json / testnet_upgrade_v47.json: regenerated byte-for-byte from the corrected canonical genesis configs (46 / 44 entries; the 25 timestamp diffs were the 1766708400 -> 0 normalization plus the warp reorder). - precompile_upgrade_rollout_test.go: WarpRequiresPrimaryNetworkSigners updated for the two-step toggle — warp is declared in the genesis chainConfig, and the schedule carries disable@strictPQ-1 then re-enable@strictPQ; the PQ signer-policy assertion targets the re-enable entry, and same-key strict-increase is enforced (mirrors verifyPrecompileUpgrades). - upgrade_unmarshal_test.go / testnet_upgrade_unmarshal_test.go: fixture doc comments rewritten to the live-at-0 / strict-PQ-toggle / BLS / Quasar-Edition tier layout; RegressionProof entry-count assertion 45 -> 46 to match the embedded fixture. Verified: go vet clean; CGO_ENABLED=0 go test ./params/extras/... ./params/extras_e2e_test/... — RelaunchSafe (mainnet+testnet), IsForwardCompatibleWithLiveActivations, WarpRequiresPrimaryNetworkSigners, PrecompileTimestampsAreMonotonic, RegressionProof all PASS.
This commit is contained in:
@@ -125,11 +125,24 @@ func TestMainnetUpgradeJSON_PrecompileTimestampsAreMonotonic(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestMainnetUpgradeJSON_WarpRequiresPrimaryNetworkSigners enforces the
|
||||
// Warp policy from red-review finding #8: the live mainnet warp config
|
||||
// pins requirePrimaryNetworkSigners=true, and the canonical upgrade.json
|
||||
// MUST keep it that way so every cross-chain warp message is signed by
|
||||
// primary-network validators (not just a subnet quorum).
|
||||
// Warp policy from red-review finding #8: the canonical upgrade.json must
|
||||
// schedule warp so that, once the strict-PQ fork lands, every cross-chain
|
||||
// warp message is signed by primary-network validators (not just a subnet
|
||||
// quorum).
|
||||
//
|
||||
// Warp lives in the genesis chainConfig (cchain.json config.warpConfig at
|
||||
// the genesis timestamp, with requirePrimaryNetworkSigners=false during the
|
||||
// classical era). The upgrade schedule then carries a two-step toggle at the
|
||||
// strict-PQ fork: disable@strictPQ-1, then re-enable@strictPQ with the
|
||||
// PQ-hardened policy. Both toggles are strictly AFTER genesis time, so this
|
||||
// is a genuine future upgrade — NOT a reschedule of the genesis warp (that
|
||||
// would be the relaunch fork hazard; see relaunch_safety_test.go). The
|
||||
// policy assertion therefore targets the RE-ENABLE entry (the one that
|
||||
// carries quorumNumerator + requirePrimaryNetworkSigners); the disable entry
|
||||
// carries only {blockTimestamp, disable:true}.
|
||||
func TestMainnetUpgradeJSON_WarpRequiresPrimaryNetworkSigners(t *testing.T) {
|
||||
const strictPQ uint64 = 1766708400
|
||||
|
||||
raw := readCanonicalMainnetUpgradeJSONRaw(t)
|
||||
|
||||
var doc struct {
|
||||
@@ -137,26 +150,62 @@ func TestMainnetUpgradeJSON_WarpRequiresPrimaryNetworkSigners(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, json.Unmarshal(raw, &doc))
|
||||
|
||||
var found bool
|
||||
for _, entry := range doc.PrecompileUpgrades {
|
||||
var (
|
||||
foundDisable bool
|
||||
foundReEnable bool
|
||||
prevWarpTs *uint64
|
||||
)
|
||||
for i, entry := range doc.PrecompileUpgrades {
|
||||
warpRaw, ok := entry["warpConfig"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
var warp struct {
|
||||
BlockTimestamp uint64 `json:"blockTimestamp"`
|
||||
Disable bool `json:"disable"`
|
||||
QuorumNumerator uint64 `json:"quorumNumerator"`
|
||||
RequirePrimaryNetworkSigners bool `json:"requirePrimaryNetworkSigners"`
|
||||
}
|
||||
require.NoError(t, json.Unmarshal(warpRaw, &warp))
|
||||
require.Equal(t, uint64(0), warp.BlockTimestamp, "warpConfig blockTimestamp must be 0")
|
||||
|
||||
// Every warp upgrade entry must be strictly after genesis time —
|
||||
// rescheduling the genesis warp into the (0, genesisTime] window is
|
||||
// the relaunch fork hazard.
|
||||
require.Greaterf(t, warp.BlockTimestamp, uint64(0),
|
||||
"warpConfig upgrade entry at index %d has blockTimestamp 0 — warp is declared in the genesis chainConfig; an upgrade entry pinned to 0 would collide with the genesis warp and fail verifyPrecompileUpgrades",
|
||||
i,
|
||||
)
|
||||
// Same-key strict increase (mirrors verifyPrecompileUpgrades).
|
||||
if prevWarpTs != nil {
|
||||
require.Greaterf(t, warp.BlockTimestamp, *prevWarpTs,
|
||||
"warpConfig entries must strictly increase in blockTimestamp (got %d after %d)",
|
||||
warp.BlockTimestamp, *prevWarpTs,
|
||||
)
|
||||
}
|
||||
ts := warp.BlockTimestamp
|
||||
prevWarpTs = &ts
|
||||
|
||||
if warp.Disable {
|
||||
foundDisable = true
|
||||
require.Equalf(t, strictPQ-1, warp.BlockTimestamp,
|
||||
"warpConfig disable must fire one second before the strict-PQ fork (%d), got %d",
|
||||
strictPQ-1, warp.BlockTimestamp,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// Re-enable entry: carries the PQ-hardened policy.
|
||||
foundReEnable = true
|
||||
require.Equalf(t, strictPQ, warp.BlockTimestamp,
|
||||
"warpConfig re-enable must fire at the strict-PQ fork (%d), got %d", strictPQ, warp.BlockTimestamp,
|
||||
)
|
||||
require.Equal(t, uint64(67), warp.QuorumNumerator, "warpConfig quorumNumerator must be 67")
|
||||
require.Truef(t, warp.RequirePrimaryNetworkSigners,
|
||||
"warpConfig.requirePrimaryNetworkSigners must be true on lux-mainnet — every cross-chain warp message MUST be signed by primary-network validators (red-review finding #8)",
|
||||
)
|
||||
}
|
||||
require.True(t, found, "warpConfig must be present in canonical upgrade.json")
|
||||
require.True(t, foundDisable, "warpConfig disable entry must be present in canonical upgrade.json")
|
||||
require.True(t, foundReEnable, "warpConfig re-enable entry (with PQ signer policy) must be present in canonical upgrade.json")
|
||||
}
|
||||
|
||||
// TestMainnetUpgradeJSON_HasStrictPQActivation enforces that the
|
||||
|
||||
@@ -8,59 +8,243 @@
|
||||
"strictPQTimestamp": 1766708400
|
||||
},
|
||||
"precompileUpgrades": [
|
||||
{"warpConfig": {"blockTimestamp": 0, "quorumNumerator": 67, "requirePrimaryNetworkSigners": true}},
|
||||
|
||||
{"aiMiningConfig": {"blockTimestamp": 0}},
|
||||
{"blake3Config": {"blockTimestamp": 0}},
|
||||
{"cggmp21Verify": {"blockTimestamp": 0}},
|
||||
{"deadZeroConfig": {"blockTimestamp": 0}},
|
||||
{"deadConfig": {"blockTimestamp": 0}},
|
||||
{"deadFullConfig": {"blockTimestamp": 0}},
|
||||
{"routerConfig": {
|
||||
"blockTimestamp": 0,
|
||||
"v3QuoterAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v3FactoryAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v2RouterAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v2FactoryAddress": "0x0000000000000000000000000000000000000000"
|
||||
}},
|
||||
{"fheConfig": {"blockTimestamp": 0}},
|
||||
{"frostVerify": {"blockTimestamp": 0}},
|
||||
{"graphConfig": {"blockTimestamp": 0}},
|
||||
{"hpkeConfig": {"blockTimestamp": 0}},
|
||||
{"mldsaVerify": {"blockTimestamp": 0}},
|
||||
{"mlkemConfig": {"blockTimestamp": 0}},
|
||||
{"pqcryptoConfig": {"blockTimestamp": 0}},
|
||||
{"ringConfig": {"blockTimestamp": 0}},
|
||||
{"slhdsaVerify": {"blockTimestamp": 0}},
|
||||
{"zkConfig": {"blockTimestamp": 0}},
|
||||
|
||||
{"pulsarVerify": {"blockTimestamp": 1782864000}},
|
||||
{"magnetarVerify": {"blockTimestamp": 1782864000}},
|
||||
{"p3qVerify": {"blockTimestamp": 1782864000}},
|
||||
{"coronaThreshold": {"blockTimestamp": 1782864000}},
|
||||
{"hqcEncapsulate": {"blockTimestamp": 1782864000}},
|
||||
{"bls12381G1AddConfig": {"blockTimestamp": 1782864000}},
|
||||
{"bls12381G1MulConfig": {"blockTimestamp": 1782864000}},
|
||||
{"bls12381G1MSMConfig": {"blockTimestamp": 1782864000}},
|
||||
{"bls12381G2AddConfig": {"blockTimestamp": 1782864000}},
|
||||
{"bls12381G2MulConfig": {"blockTimestamp": 1782864000}},
|
||||
{"bls12381G2MSMConfig": {"blockTimestamp": 1782864000}},
|
||||
{"bls12381PairingConfig": {"blockTimestamp": 1782864000}},
|
||||
{"curve25519Config": {"blockTimestamp": 1782864000}},
|
||||
{"x25519Config": {"blockTimestamp": 1782864000}},
|
||||
{"sr25519Verify": {"blockTimestamp": 1782864000}},
|
||||
{"babyjubjubConfig": {"blockTimestamp": 1782864000}},
|
||||
{"pedersenConfig": {"blockTimestamp": 1782864000}},
|
||||
{"poseidonConfig": {"blockTimestamp": 1782864000}},
|
||||
{"pastaConfig": {"blockTimestamp": 1782864000}},
|
||||
{"xwingConfig": {"blockTimestamp": 1782864000}},
|
||||
{"computeMarketConfig": {"blockTimestamp": 1782864000}},
|
||||
{"bridgeRegistrarConfig": {"blockTimestamp": 1782864000}},
|
||||
{"stableSwapConfig": {"blockTimestamp": 1782864000}},
|
||||
{"vrfConfig": {"blockTimestamp": 1782864000}},
|
||||
{"attestationConfig": {"blockTimestamp": 1782864000}},
|
||||
{"anchorConfig": {"blockTimestamp": 1782864000}},
|
||||
{"fixedPointMathConfig": {"blockTimestamp": 1782864000}}
|
||||
{
|
||||
"aiMiningConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"blake3Config": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"cggmp21Verify": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"deadZeroConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"deadConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"deadFullConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"routerConfig": {
|
||||
"blockTimestamp": 0,
|
||||
"v3QuoterAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v3FactoryAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v2RouterAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v2FactoryAddress": "0x0000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fheConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"frostVerify": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"graphConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"hpkeConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"mldsaVerify": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"mlkemConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"pqcryptoConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"ringConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"slhdsaVerify": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"zkConfig": {
|
||||
"blockTimestamp": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"warpConfig": {
|
||||
"blockTimestamp": 1766708399,
|
||||
"disable": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"warpConfig": {
|
||||
"blockTimestamp": 1766708400,
|
||||
"quorumNumerator": 67,
|
||||
"requirePrimaryNetworkSigners": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"bls12381G1AddConfig": {
|
||||
"blockTimestamp": 1766708400
|
||||
}
|
||||
},
|
||||
{
|
||||
"bls12381G1MulConfig": {
|
||||
"blockTimestamp": 1766708400
|
||||
}
|
||||
},
|
||||
{
|
||||
"bls12381G1MSMConfig": {
|
||||
"blockTimestamp": 1766708400
|
||||
}
|
||||
},
|
||||
{
|
||||
"bls12381G2AddConfig": {
|
||||
"blockTimestamp": 1766708400
|
||||
}
|
||||
},
|
||||
{
|
||||
"bls12381G2MulConfig": {
|
||||
"blockTimestamp": 1766708400
|
||||
}
|
||||
},
|
||||
{
|
||||
"bls12381G2MSMConfig": {
|
||||
"blockTimestamp": 1766708400
|
||||
}
|
||||
},
|
||||
{
|
||||
"bls12381PairingConfig": {
|
||||
"blockTimestamp": 1766708400
|
||||
}
|
||||
},
|
||||
{
|
||||
"pulsarVerify": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"magnetarVerify": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"p3qVerify": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"coronaThreshold": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"hqcEncapsulate": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"curve25519Config": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"x25519Config": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"sr25519Verify": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"babyjubjubConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"pedersenConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"poseidonConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"pastaConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"xwingConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"computeMarketConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"bridgeRegistrarConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"stableSwapConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"vrfConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"attestationConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"anchorConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
},
|
||||
{
|
||||
"fixedPointMathConfig": {
|
||||
"blockTimestamp": 1782864000
|
||||
}
|
||||
}
|
||||
],
|
||||
"stateUpgrades": []
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
// Copyright (C) 2019-2026, Lux Industries, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// Relaunch-safety gate for the canonical primary-network C-Chain
|
||||
// upgrade.json files.
|
||||
//
|
||||
// Threat addressed (Red HIGH, pre-existing): a mainnet/testnet relaunch
|
||||
// from the canonical genesis must NOT re-trigger an activation that was
|
||||
// already applied at block 0 on the running chain. A precompile that is
|
||||
// live at genesis is a GENESIS property; only strictly-future activations
|
||||
// belong in upgrade.json's precompileUpgrades schedule. Putting an
|
||||
// already-live precompile at a post-genesis timestamp reschedules an
|
||||
// already-applied activation, which on relaunch either (a) makes the
|
||||
// relaunched node treat the precompile as INACTIVE from block 0 —
|
||||
// diverging from the canonical chain where it is active at block 0
|
||||
// (a consensus fork) — or (b) trips checkPrecompileCompatible
|
||||
// ("missing"/"cannot retroactively enable") and refuses boot.
|
||||
//
|
||||
// This test drives the node's REAL fork-application primitive
|
||||
// (extras.IsForkTransition, the same predicate GetActivatingPrecompileConfigs
|
||||
// uses) against the embedded canonical fixtures and asserts the invariant:
|
||||
//
|
||||
// For the genesis -> first-block transition (parent = nil), the set of
|
||||
// precompiles that activate AT genesis (blockTimestamp <= genesisTime)
|
||||
// is EXACTLY the set of precompiles already live at block 0 on the
|
||||
// running chain, and every other scheduled activation is strictly in
|
||||
// the future (blockTimestamp > genesisTime). No entry sits in the
|
||||
// (0, genesisTime] window, which is the only window that could
|
||||
// retroactively re-fire an already-applied activation on relaunch.
|
||||
package extras_e2e_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/luxfi/evm/params/extras"
|
||||
)
|
||||
|
||||
// cChainGenesisTime is the C-Chain (chainId 96369 mainnet / 96368 testnet)
|
||||
// genesis BLOCK timestamp baked into the frozen canonical genesis. It is
|
||||
// NOT the P-chain network startTime of a relaunch; the EVM genesis block
|
||||
// keeps this timestamp across relaunches, so it is the boundary that
|
||||
// IsForkTransition(fork, nil, genesisTime) uses to decide which precompiles
|
||||
// are active at block 0.
|
||||
//
|
||||
// Source of truth:
|
||||
//
|
||||
// luxfi/genesis configs/mainnet/cchain.json -> "timestamp": "0x672485c2"
|
||||
// luxfi/genesis configs/testnet/cchain.json -> "timestamp": "0x67259912"
|
||||
const (
|
||||
mainnetCChainGenesisTime uint64 = 0x672485c2 // 1730446786 = 2024-11-01 07:39:46 UTC
|
||||
testnetCChainGenesisTime uint64 = 0x67259912 // 1730517266 = 2024-11-02 03:14:26 UTC
|
||||
)
|
||||
|
||||
// liveAtBlockZero is the exact set of precompile config keys that the
|
||||
// running mainnet AND testnet C-Chains have active at block 0. Source of
|
||||
// truth: the UPGRADE_JSON heredoc in luxfi/universe
|
||||
// k8s/lux-{mainnet,testnet}/luxd-startup.yaml (both carry these 17 at
|
||||
// blockTimestamp:0). warpConfig is NOT in this set: it is declared in the
|
||||
// genesis chainConfig itself (cchain.json config.warpConfig), not in
|
||||
// upgrade.json's precompileUpgrades, so it is handled by the genesis path
|
||||
// rather than the upgrade schedule.
|
||||
var liveAtBlockZero = map[string]bool{
|
||||
"aiMiningConfig": true,
|
||||
"blake3Config": true,
|
||||
"cggmp21Verify": true,
|
||||
"deadZeroConfig": true,
|
||||
"deadConfig": true,
|
||||
"deadFullConfig": true,
|
||||
"routerConfig": true,
|
||||
"fheConfig": true,
|
||||
"frostVerify": true,
|
||||
"graphConfig": true,
|
||||
"hpkeConfig": true,
|
||||
"mldsaVerify": true,
|
||||
"mlkemConfig": true,
|
||||
"pqcryptoConfig": true,
|
||||
"ringConfig": true,
|
||||
"slhdsaVerify": true,
|
||||
"zkConfig": true,
|
||||
}
|
||||
|
||||
func TestMainnetUpgradeJSON_RelaunchSafe(t *testing.T) {
|
||||
assertRelaunchSafe(t, readCanonicalMainnetUpgradeJSONRaw(t), mainnetCChainGenesisTime)
|
||||
}
|
||||
|
||||
func TestTestnetUpgradeJSON_RelaunchSafe(t *testing.T) {
|
||||
assertRelaunchSafe(t, readCanonicalTestnetUpgradeJSONRaw(t), testnetCChainGenesisTime)
|
||||
}
|
||||
|
||||
// assertRelaunchSafe parses the canonical upgrade.json and proves the
|
||||
// relaunch-safety invariant using the node's own IsForkTransition predicate.
|
||||
func assertRelaunchSafe(t *testing.T, raw []byte, genesisTime uint64) {
|
||||
t.Helper()
|
||||
|
||||
var cfg extras.UpgradeConfig
|
||||
require.NoError(t, json.Unmarshal(raw, &cfg),
|
||||
"canonical upgrade.json failed to parse — see TestMainnetUpgradeJSON_UnmarshalsAgainstRegistry")
|
||||
|
||||
activeAtGenesis := map[string]bool{}
|
||||
|
||||
for i, upg := range cfg.PrecompileUpgrades {
|
||||
key := upg.Key()
|
||||
ts := upg.Timestamp()
|
||||
require.NotNilf(t, ts, "precompileUpgrades[%d] key=%q has nil blockTimestamp", i, key)
|
||||
|
||||
// The node decides "active at the genesis block" via
|
||||
// IsForkTransition(fork, parent=nil, current=genesisTime). With a
|
||||
// nil parent this reduces to (fork <= genesisTime). This is exactly
|
||||
// what GetActivatingPrecompileConfigs(addr, nil, genesisTime, ...)
|
||||
// evaluates when a relaunched node builds its first rule set.
|
||||
activatesAtGenesis := extras.IsForkTransition(ts, nil, genesisTime)
|
||||
|
||||
if activatesAtGenesis {
|
||||
// An entry that activates at/under genesis MUST be one of the
|
||||
// already-live precompiles, AND it MUST be pinned to exactly 0.
|
||||
// Any value in (0, genesisTime] is a reschedule of an
|
||||
// already-applied activation into the retroactive window — the
|
||||
// precise fork/boot-refusal hazard Red flagged.
|
||||
require.Truef(t, liveAtBlockZero[key],
|
||||
"RELAUNCH FORK RISK: precompileUpgrades[%d] key=%q activates at genesis "+
|
||||
"(blockTimestamp=%d <= genesisTime=%d) but is NOT in the set of precompiles "+
|
||||
"live at block 0 on the running chain. Either remove it (if it is genuinely "+
|
||||
"future, give it blockTimestamp > %d) or, if it really is live at genesis, add "+
|
||||
"it to liveAtBlockZero and pin it to 0.",
|
||||
i, key, *ts, genesisTime, genesisTime)
|
||||
|
||||
require.Equalf(t, uint64(0), *ts,
|
||||
"RELAUNCH FORK RISK: live-at-genesis precompile %q is scheduled at blockTimestamp=%d "+
|
||||
"instead of 0. A non-zero timestamp <= genesisTime reschedules an already-applied "+
|
||||
"activation; on relaunch the node would treat it as inactive before %d and diverge "+
|
||||
"from the canonical chain (or checkPrecompileCompatible refuses boot). Pin it to 0.",
|
||||
key, *ts, *ts)
|
||||
|
||||
activeAtGenesis[key] = true
|
||||
} else {
|
||||
// Strictly-future activation: must be > genesisTime. (Guaranteed
|
||||
// by !activatesAtGenesis, but assert explicitly so the failure
|
||||
// message is unambiguous for an operator reading the log.)
|
||||
require.Greaterf(t, *ts, genesisTime,
|
||||
"precompileUpgrades[%d] key=%q is treated as future but blockTimestamp=%d <= genesisTime=%d",
|
||||
i, key, *ts, genesisTime)
|
||||
}
|
||||
}
|
||||
|
||||
// Completeness: every precompile known to be live at block 0 on the
|
||||
// running chain MUST appear (pinned to 0) in the relaunch config.
|
||||
// A missing one would make the relaunched chain LOSE a block-0
|
||||
// precompile relative to the canonical chain — also a divergence.
|
||||
for key := range liveAtBlockZero {
|
||||
require.Truef(t, activeAtGenesis[key],
|
||||
"RELAUNCH DIVERGENCE: precompile %q is live at block 0 on the running chain but is "+
|
||||
"absent from (or not pinned to 0 in) the canonical relaunch upgrade.json. A relaunch "+
|
||||
"would drop it from genesis state.", key)
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,18 @@ import (
|
||||
|
||||
// canonicalTestnetUpgradeV47 is the byte-for-byte vendored copy of
|
||||
// luxfi/genesis configs/testnet/upgrade.json at the v47 precompile-set
|
||||
// freeze (warpConfig + 19 forward-dated 1766708400 net-new + 27 more
|
||||
// safe-subset cryptography precompiles also at 1766708400). The
|
||||
// testnet schedule front-loads all activations to the strict-PQ
|
||||
// timestamp because there is no live testnet validator state to keep
|
||||
// backwards-compatible against — it's the experimentation lane.
|
||||
// freeze. Layout (44 entries, monotonic by blockTimestamp):
|
||||
// - 17 already-live precompiles pinned to blockTimestamp:0 — these are
|
||||
// active at block 0 on the running testnet (see the UPGRADE_JSON in
|
||||
// luxfi/universe k8s/lux-testnet/luxd-startup.yaml). They MUST stay at
|
||||
// 0 so a relaunch from genesis treats them as already-applied and
|
||||
// checkPrecompileCompatible does not refuse boot.
|
||||
// - 27 net-new safe-subset cryptography precompiles forward-dated to the
|
||||
// strict-PQ timestamp 1766708400 (strictly after testnet genesis time
|
||||
// 1730517266), so the strict-PQ gate is in force when they activate.
|
||||
// Unlike mainnet there is no separate Quasar-Edition tier — testnet
|
||||
// front-loads its net-new activations to the strict-PQ fork because it's
|
||||
// the experimentation lane.
|
||||
//
|
||||
// Sync contract: if luxfi/genesis configs/testnet/upgrade.json changes,
|
||||
// regenerate this file:
|
||||
|
||||
@@ -8,45 +8,29 @@
|
||||
"strictPQTimestamp": 1766708400
|
||||
},
|
||||
"precompileUpgrades": [
|
||||
{"warpConfig": {"blockTimestamp": 0, "quorumNumerator": 67, "requirePrimaryNetworkSigners": true}},
|
||||
{"aiMiningConfig": {"blockTimestamp": 1766708400}},
|
||||
{"blake3Config": {"blockTimestamp": 1766708400}},
|
||||
{"cggmp21Verify": {"blockTimestamp": 1766708400}},
|
||||
{"deadZeroConfig": {"blockTimestamp": 1766708400}},
|
||||
{"deadConfig": {"blockTimestamp": 1766708400}},
|
||||
{"deadFullConfig": {"blockTimestamp": 1766708400}},
|
||||
{"aiMiningConfig": {"blockTimestamp": 0}},
|
||||
{"blake3Config": {"blockTimestamp": 0}},
|
||||
{"cggmp21Verify": {"blockTimestamp": 0}},
|
||||
{"deadZeroConfig": {"blockTimestamp": 0}},
|
||||
{"deadConfig": {"blockTimestamp": 0}},
|
||||
{"deadFullConfig": {"blockTimestamp": 0}},
|
||||
{"routerConfig": {
|
||||
"blockTimestamp": 1766708400,
|
||||
"blockTimestamp": 0,
|
||||
"v3QuoterAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v3FactoryAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v2RouterAddress": "0x0000000000000000000000000000000000000000",
|
||||
"v2FactoryAddress": "0x0000000000000000000000000000000000000000"
|
||||
}},
|
||||
{"fheConfig": {"blockTimestamp": 1766708400}},
|
||||
{"frostVerify": {"blockTimestamp": 1766708400}},
|
||||
{"graphConfig": {"blockTimestamp": 1766708400}},
|
||||
{"hpkeConfig": {"blockTimestamp": 1766708400}},
|
||||
{"mldsaVerify": {"blockTimestamp": 1766708400}},
|
||||
{"mlkemConfig": {"blockTimestamp": 1766708400}},
|
||||
{"pqcryptoConfig": {"blockTimestamp": 1766708400}},
|
||||
{"ringConfig": {"blockTimestamp": 1766708400}},
|
||||
{"slhdsaVerify": {"blockTimestamp": 1766708400}},
|
||||
{"zkConfig": {"blockTimestamp": 1766708400}},
|
||||
{"feeManagerConfig": {
|
||||
"blockTimestamp": 900000000,
|
||||
"adminAddresses": ["0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"],
|
||||
"enabledAddresses": [],
|
||||
"initialFeeConfig": {
|
||||
"gasLimit": 20000000,
|
||||
"minBaseFee": 25000000000,
|
||||
"targetGas": 15000000,
|
||||
"baseFeeChangeDenominator": 36,
|
||||
"minBlockGasCost": 0,
|
||||
"maxBlockGasCost": 10000000,
|
||||
"targetBlockRate": 2,
|
||||
"blockGasCostStep": 500000
|
||||
}
|
||||
}},
|
||||
{"fheConfig": {"blockTimestamp": 0}},
|
||||
{"frostVerify": {"blockTimestamp": 0}},
|
||||
{"graphConfig": {"blockTimestamp": 0}},
|
||||
{"hpkeConfig": {"blockTimestamp": 0}},
|
||||
{"mldsaVerify": {"blockTimestamp": 0}},
|
||||
{"mlkemConfig": {"blockTimestamp": 0}},
|
||||
{"pqcryptoConfig": {"blockTimestamp": 0}},
|
||||
{"ringConfig": {"blockTimestamp": 0}},
|
||||
{"slhdsaVerify": {"blockTimestamp": 0}},
|
||||
{"zkConfig": {"blockTimestamp": 0}},
|
||||
{"pulsarVerify": {"blockTimestamp": 1766708400}},
|
||||
{"magnetarVerify": {"blockTimestamp": 1766708400}},
|
||||
{"p3qVerify": {"blockTimestamp": 1766708400}},
|
||||
|
||||
@@ -48,12 +48,22 @@ import (
|
||||
|
||||
// canonicalMainnetUpgradeV46 is the byte-for-byte vendored copy of
|
||||
// luxfi/genesis configs/mainnet/upgrade.json at the v46 precompile-set
|
||||
// freeze (warpConfig + 17 live-at-block-0 + 27 forward-dated to the
|
||||
// Quasar Edition activation timestamp). The dead dexConfig 0x9010 key
|
||||
// was removed when node v1.30.27 dropped that precompile (its config
|
||||
// key is no longer registered → it would brick the C-Chain on boot).
|
||||
// Vendoring it removes runtime CWD-walking and makes this
|
||||
// regression-proof hermetic in CI runners that clone only luxfi/evm.
|
||||
// freeze. Layout (46 entries, monotonic by blockTimestamp):
|
||||
// - 17 already-live precompiles pinned to blockTimestamp:0 — these are
|
||||
// active at block 0 on the running mainnet (see the UPGRADE_JSON in
|
||||
// luxfi/universe k8s/lux-mainnet/luxd-startup.yaml). They MUST stay at
|
||||
// 0 so a relaunch from genesis treats them as already-applied and
|
||||
// checkPrecompileCompatible does not refuse boot.
|
||||
// - warpConfig disable@1766708399 then re-enable@1766708400 (PQ warp
|
||||
// params at the strict-PQ fork; both strictly after genesis time).
|
||||
// - 7 bls12381 family @1766708400.
|
||||
// - 20 forward-dated @1782864000 (Quasar Edition activation; strictly
|
||||
// after the strict-PQ gate so every classical primitive is gated).
|
||||
// The dead dexConfig 0x9010 key was removed when node v1.30.27 dropped
|
||||
// that precompile (its config key is no longer registered → it would
|
||||
// brick the C-Chain on boot). Vendoring it removes runtime CWD-walking
|
||||
// and makes this regression-proof hermetic in CI runners that clone only
|
||||
// luxfi/evm.
|
||||
//
|
||||
// Sync contract: if luxfi/genesis configs/mainnet/upgrade.json changes,
|
||||
// regenerate this file:
|
||||
@@ -215,12 +225,16 @@ func TestRegressionProof_SimulatedFortyNineEntryCanonicalFails(t *testing.T) {
|
||||
require.NoError(t, json.Unmarshal(raw, &ok),
|
||||
"post-patch canonical (45 entries) must parse cleanly — see TestMainnetUpgradeJSON_UnmarshalsAgainstRegistry",
|
||||
)
|
||||
require.Lenf(t, ok.PrecompileUpgrades, 45,
|
||||
"canonical entry count drifted: this regression-proof test was authored against 45 entries (warpConfig + the live + forward-dated set, after the dead dexConfig 0x9010 key was removed). If the canonical count legitimately changed, update this assertion alongside.",
|
||||
require.Lenf(t, ok.PrecompileUpgrades, 46,
|
||||
"canonical entry count drifted: this regression-proof test was authored against 46 entries "+
|
||||
"(17 live-at-block-0 pinned to blockTimestamp:0 + warpConfig disable@1766708399 + "+
|
||||
"warpConfig re-enable@1766708400 + 7 bls12381 family@1766708400 + 20 forward-dated@1782864000, "+
|
||||
"after the dead dexConfig 0x9010 key was removed). If the canonical count legitimately "+
|
||||
"changed, update this assertion alongside.",
|
||||
)
|
||||
|
||||
// Build a "pre-patch" 49-entry probe by injecting three
|
||||
// guaranteed-unregistered sentinel keys at a forward-date.
|
||||
// guaranteed-unregistered sentinel keys at a forward-date (46 + 3 = 49).
|
||||
var asObj map[string]any
|
||||
require.NoError(t, json.Unmarshal(raw, &asObj))
|
||||
upgrades, _ := asObj["precompileUpgrades"].([]any)
|
||||
|
||||
Reference in New Issue
Block a user