platformvm/txs/zap_native: invert env var — native ZAP default, legacy is opt-in

LUXD_DISABLE_LEGACY_CODEC → LUXD_ENABLE_LEGACY_CODEC (per user 2026-06-02
'should be LUXD_ENABLE_LEGACY_CODE=1 to turn it on').

Default: native ZAP for every read + write. codec.Codec.Marshal/Unmarshal
gone from hot path. Fresh deployments + post-activation production get a
smaller, faster binary with no legacy code reachable.

Operators with pre-activation history that needs reading set
LUXD_ENABLE_LEGACY_CODEC=1 to opt in to backward-compat. Without it, legacy
bytes return ErrLegacyCodecDisabled.

Tests updated for the inverted default; pass clean.
This commit is contained in:
Hanzo AI
2026-06-02 12:39:13 -07:00
parent 80e1881285
commit b4d325be6c
2 changed files with 69 additions and 42 deletions
@@ -78,21 +78,39 @@ func TestIsZAPBytes(t *testing.T) {
}
func TestShouldUseZAPForWrite(t *testing.T) {
cases := []struct {
name string
ts uint64
want bool
}{
{"pre-activation", 1782604800 - 1, false},
{"at activation", 1782604800, true},
{"post-activation", 1782604800 + 86400, true},
{"epoch", 0, false},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := ShouldUseZAPForWrite(c.ts); got != c.want {
t.Fatalf("ShouldUseZAPForWrite(%d) = %v, want %v", c.ts, got, c.want)
// Default: native ZAP for every timestamp. Legacy is opt-in via
// LUXD_ENABLE_LEGACY_CODEC. The package-level LegacyEnabled is read
// once at init from the env var; tests assert the default-false path
// and the explicitly-toggled path.
defer func(prev bool) { LegacyEnabled = prev }(LegacyEnabled)
t.Run("default (legacy disabled): ZAP always", func(t *testing.T) {
LegacyEnabled = false
for _, ts := range []uint64{0, 1, 1782604800 - 1, 1782604800, 1782604800 + 86400} {
if !ShouldUseZAPForWrite(ts) {
t.Fatalf("ShouldUseZAPForWrite(%d) = false, want true (ZAP default)", ts)
}
})
}
}
})
t.Run("legacy enabled: timestamp-gated", func(t *testing.T) {
LegacyEnabled = true
cases := []struct {
name string
ts uint64
want bool
}{
{"pre-activation", 1782604800 - 1, false},
{"at activation", 1782604800, true},
{"post-activation", 1782604800 + 86400, true},
{"epoch", 0, false},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := ShouldUseZAPForWrite(c.ts); got != c.want {
t.Fatalf("ShouldUseZAPForWrite(%d) = %v, want %v", c.ts, got, c.want)
}
})
}
})
}
+35 -26
View File
@@ -9,39 +9,40 @@ import (
)
// ZAPActivationUnix is the unix timestamp at which P-chain wire format
// switches from linearcodec (CodecVersionV0/V1) to native ZAP. Pre-activation
// blocks are accepted in their existing linearcodec encoding via the legacy
// codec.Manager path in ~/work/lux/node/vms/platformvm/txs/codec.go. Post-
// activation blocks MUST be ZAP. Validator coordination is documented in
// LP-023.
// switches from legacy linearcodec (CodecVersionV0/V1) to native ZAP. The
// switch governs the WRITE path: post-activation blocks MUST be ZAP-encoded.
// Validator coordination is documented in LP-023.
//
// Value chosen: 2026-07-01 00:00 UTC = 1782604800.
//
// This is ~30 days forward of the migration land date (2026-06-02). Sufficient
// notice for validator upgrades.
// Value: 2026-07-01 00:00 UTC = 1782604800.
const ZAPActivationUnix uint64 = 1782604800
// DisableLegacy is true when the operator has set LUXD_DISABLE_LEGACY_CODEC=1.
// When set:
// - The legacy linearcodec read path returns ErrLegacyCodecDisabled.
// - All write paths use ZAP regardless of block timestamp.
// LegacyEnabled is true when the operator has set LUXD_ENABLE_LEGACY_CODEC=1.
//
// Used for:
// - Benchmarking pure ZAP perf without legacy code in the binary's hot path.
// - Future post-activation production runs where backward compat is no
// longer required and the operator wants to drop the codec.Manager surface
// for a smaller, simpler, faster binary.
var DisableLegacy = os.Getenv("LUXD_DISABLE_LEGACY_CODEC") == "1"
// **Native ZAP is the default.** The codec.Codec{Marshal,Unmarshal} interface
// is gone from the platformvm hot path. New deployments, fresh syncs, and
// post-activation production binaries run ZAP-only by default — no legacy
// code in the read or write path.
//
// Operators MUST set LUXD_ENABLE_LEGACY_CODEC=1 if they need to read
// pre-activation historical blocks from disk (e.g. validators bootstrapping
// from a long-history snapshot that includes pre-2026-07-01 P-chain state).
// Without the flag, legacy-encoded bytes return ErrLegacyCodecDisabled.
//
// Once a validator has synced past the activation height, the flag can be
// dropped — all subsequent reads are ZAP.
var LegacyEnabled = os.Getenv("LUXD_ENABLE_LEGACY_CODEC") == "1"
// ErrLegacyCodecDisabled is returned by legacy-path parsers when the operator
// has disabled legacy codec support via the LUXD_DISABLE_LEGACY_CODEC env var.
var ErrLegacyCodecDisabled = errors.New("zap_native: legacy codec disabled (LUXD_DISABLE_LEGACY_CODEC=1)")
// has not enabled legacy codec support via the LUXD_ENABLE_LEGACY_CODEC env var.
// Native ZAP is the default; legacy is opt-in.
var ErrLegacyCodecDisabled = errors.New("zap_native: legacy codec not enabled (set LUXD_ENABLE_LEGACY_CODEC=1 to read pre-activation blocks)")
// IsZAPBytes reports whether the byte buffer is a ZAP-encoded message
// (recognised by the 4-byte "ZAP\x00" magic). Cheap O(1) check.
//
// Callers use this to discriminate ZAP-encoded txs/blocks from legacy
// linearcodec-encoded ones during the cross-activation read window.
// linearcodec-encoded ones during the cross-activation read window (which
// only happens when LUXD_ENABLE_LEGACY_CODEC=1).
func IsZAPBytes(b []byte) bool {
if len(b) < 4 {
return false
@@ -50,9 +51,17 @@ func IsZAPBytes(b []byte) bool {
}
// ShouldUseZAPForWrite reports whether new outgoing txs/blocks should be
// encoded as ZAP. True iff:
// - blockTimestamp >= ZAPActivationUnix (we're post-activation), OR
// - LUXD_DISABLE_LEGACY_CODEC=1 (operator opt-in)
// encoded as ZAP.
//
// Default behavior — native ZAP always. The block timestamp gate exists ONLY
// to maintain consensus with pre-activation peers during the cutover window;
// once activation passes, this function returns true unconditionally.
//
// When LUXD_ENABLE_LEGACY_CODEC=1, pre-activation timestamps still emit
// legacy linearcodec to preserve back-compat with un-upgraded peers.
func ShouldUseZAPForWrite(blockTimestamp uint64) bool {
return blockTimestamp >= ZAPActivationUnix || DisableLegacy
if !LegacyEnabled {
return true // native ZAP default
}
return blockTimestamp >= ZAPActivationUnix
}