Files
node/vms/platformvm/state/codec_helpers.go
T
Hanzo AI b4f240d285 vms/platformvm: rip luxfi/codec via pcodecs (wave 2D — final)
Thirty platformvm files migrated. Every codec.Manager / codec.Registry /
linearcodec / wrappers / zapcodec reference inside vms/platformvm now
flows through node/vms/pcodecs, completing wave 2D of the codec rip
(#101). zero direct luxfi/codec imports remain anywhere in node/vms
outside vms/pcodecs/{pcodecs.go,pcodecsmock/manager.go}.

Codec construction sites (singletons preserved for external API
compatibility — wallet, indexer, network — pcodecs is the construction
layer only):
  platformvm/txs/codec.go       — V0+V1 linearcodec + V2 zapcodec
                                   via pcodecs.NewLinearCodec /
                                   NewZAPCodec / NewDefaultManager /
                                   NewMaxInt32Manager helpers
  platformvm/block/codec.go     — v1 + v0 read-only + GenesisCodec
                                   via pcodecs helpers
  platformvm/warp/codec.go      — Codec via pcodecs.NewMaxIntManager
  platformvm/warp/message/codec.go — Codec via pcodecs.NewMaxIntManager
  platformvm/warp/payload/codec.go — Codec via pcodecs.NewManager
  platformvm/state/metadata_codec.go — MetadataCodec via pcodecs

Production code typed through pcodecs:
  platformvm/txs/{tx,initial_state,operation}.go — codec.Manager →
                                                   pcodecs.Manager
  platformvm/txs/fee/complexity.go — wrappers.{LongLen,IntLen,ShortLen,
                                     ByteLen} + codec.VersionSize →
                                     pcodecs.{LongLen,IntLen,ShortLen,
                                     ByteLen,VersionSize}
  platformvm/state/{state,codec_helpers,metadata_validator}.go —
                                   pcodecs.Manager / pcodecs.Registry /
                                   pcodecs.{VersionSize,LongLen,IntLen,
                                   BoolLen}
  platformvm/block/{parse,v0/block}.go — pcodecs.Manager + LinearCodec
                                          + Errs
  platformvm/metrics/metrics.go — wrappers.Errs → pcodecs.Errs
  platformvm/vm.go — codec.Registry / linearcodec.NewDefault →
                     pcodecs.Registry / pcodecs.NewLinearCodec

Tests:
  platformvm/block/codec_multiversion_test.go — codec.ErrUnknownVersion
                                                 → pcodecs
  platformvm/state/{codec_helpers,metadata_validator,
                    metadata_delegator,state_v0_codec}_test.go —
                                   codec sentinel errors → pcodecs;
                                   linearcodec.NewDefault /
                                   codec.NewDefaultManager → pcodecs
                                   helpers
  platformvm/txs/{fee/complexity,tx_fuzz}_test.go — pcodecs.VersionSize
                                                    / NewLinearCodec /
                                                    Packer
  platformvm/warp/{message,unsigned_message}_test.go — pcodecs.ErrUnknownVersion
  platformvm/warp/message/payload_test.go — pcodecs.ErrUnknownVersion
  platformvm/warp/payload/{addressed_call,hash,payload}_test.go —
                                   pcodecs.ErrUnknownVersion

Build: go build ./vms/...
Tests: go test ./vms/platformvm/... — all green.

Pre-existing failures in vms/xvm (TestTxAcceptAfterParseTx,
TestIssueImportTx, TestIssueNFT, TestIssueProperty, TestVerifyFxUsage)
are unrelated to wave 2D — they fail on the baseline branch without any
change to xvm. Independent fix.

Wave 2D complete:
  - Components:  8 files migrated
  - Proposervm:  9 files migrated
  - EVM:         5 files migrated
  - XSVM:        2 files migrated
  - RPCchainvm:  1 file migrated
  - XVM:        18 files migrated
  - Platformvm: 30 files migrated
  --
  Total:        73 files migrated to pcodecs.

vms/pcodecs is the single canonical construction site.
2026-06-06 02:55:23 -07:00

63 lines
2.5 KiB
Go

// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package state
import (
"sync"
"github.com/luxfi/log"
"github.com/luxfi/node/vms/pcodecs"
)
// probe is a flat struct chosen so its codec walk is the empty walk
// (size 0) and therefore Marshal cannot fail for any reason other than
// the requested version being absent. This is what makes the probe a
// reliable boolean test of "is version V registered on c".
type probe struct{}
// multiVersionUnmarshal is the canonical state-side codec read entry
// point. It wraps codec.Manager.Unmarshal with a one-shot post-condition
// check: if the codec is missing the v0 read-only slot map, a structured
// warning is logged the FIRST time it is observed, so a canary boot of
// a v0-on-disk database surfaces every missing-version slot in a single
// log scrape rather than failing piecemeal across iterations.
//
// This is a soft guard, not a hard one — successful Unmarshal of a v1
// payload through a v1-only codec still succeeds. The warning fires
// when (a) a single-version codec is observed AND (b) the failure mode
// it implies (v0 prefix → ErrUnknownVersion) would have triggered on a
// pre-codec-v1 database row. The intent is to make the v1.28.x
// codec-migration convergence iteration-light: future patches can grep
// for this log line in canary stderr and see every remaining gap.
//
// Implementation note: we identify a codec as "missing the v0 slot" by
// attempting to Marshal a one-byte probe at CodecVersionV0. codec.Manager
// returns ErrUnknownVersion if and only if version 0 is not registered
// in its map. The probe is cheap (a 10-byte Marshal at most) and only
// happens on the first observation of each distinct codec pointer.
func multiVersionUnmarshal(c pcodecs.Manager, b []byte, dest interface{}) (uint16, error) {
checkMultiVersion(c)
return c.Unmarshal(b, dest)
}
var (
multiVersionProbeOnce sync.Map // codec.Manager -> struct{}
)
func checkMultiVersion(c pcodecs.Manager) {
if _, observed := multiVersionProbeOnce.LoadOrStore(c, struct{}{}); observed {
return
}
// Probe: can this codec Marshal at v0? An empty struct has zero
// codec-walk size, so the only way Marshal can fail is if version 0
// itself is not registered — which is exactly the failure mode we
// want the warning to fire on.
if _, err := c.Marshal(0, probe{}); err != nil {
log.Warn("state-side codec is single-version; reads of v0-prefixed bytes will fail",
"err", err,
"hint", "register the v0 read-only slot map on this codec.Manager",
)
}
}