mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
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:
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user