diff --git a/vms/components/lux/utxo_parser.go b/vms/components/lux/utxo_parser.go index abcaae624..6fe4750b5 100644 --- a/vms/components/lux/utxo_parser.go +++ b/vms/components/lux/utxo_parser.go @@ -177,6 +177,15 @@ func wrapOutput(b []byte, tk wire.TypeKind, sk wire.ShapeKind) (verify.State, er return nil, fmt.Errorf("zap utxo dispatch: unknown (TypeKind=0x%02x, ShapeKind=0x%02x)", tk, sk) } +// WrapInputBytes is the public entry to the fx-aware input dispatcher — the +// input-side counterpart of WrapOutputBytes. It reconstructs the polymorphic +// fx Input from its wire envelope; the concrete type (e.g. +// *secp256k1fx.TransferInput) also satisfies luxfi/utxo's TransferableIn, so +// consumers holding the utxo type tree (xvm/txs) can type-assert across. +func WrapInputBytes(b []byte) (TransferableIn, error) { + return wrapInputBytes(b) +} + // wrapInputBytes is the input-side counterpart of wrapOutput: it // reconstructs a TransferableIn from its fx wire envelope, dispatching on // the (TypeKind, ShapeKind) discriminator. Each branch calls exactly one diff --git a/vms/pcodecs/pcodecs.go b/vms/pcodecs/pcodecs.go deleted file mode 100644 index 8d6544049..000000000 --- a/vms/pcodecs/pcodecs.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (C) 2019-2026, Lux Industries, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -// Package pcodecs is the canonical construction site for every -// codec.Manager + codec instance under node/vms. Wave 2G-Internal of -// the codec rip (#101) replaces the previous direct imports of -// github.com/luxfi/codec / linearcodec / zapcodec with a single -// import of github.com/luxfi/proto/zap_codec — the proto-layer wire -// codec entry point established in Wave 2G-Wallet. -// -// Layout: -// -// - Type aliases re-export the proto/zap_codec surfaces every VM -// consumer needs (Manager, Registry, LinearCodec, ZAPCodec, Errs, -// Packer, VersionSize, sentinel errors). -// - Constructor helpers return fresh Manager / Codec instances at -// canonical size budgets (Default, MaxInt32, MaxInt, Sized). They -// are wire-agnostic — each VM's own codec.go layer registers its -// type set on top. -// -// pcodecs has NO knowledge of any specific VM's type set. VM-specific -// registration stays in the VM's own codec.go (e.g. -// vms/platformvm/txs/codec.go). This split keeps pcodecs a leaf package -// — every node/vms subpackage is free to import it without closing an -// import cycle. -// -// Wire format: ZAP-native (little-endian) — the underlying impl is -// luxfi/codec/zapcodec routed through proto/zap_codec. The "Linear" -// name on LinearCodec / NewLinearCodec refers to LINEAR TYPE-ID -// ASSIGNMENT (sequential ids assigned in registration order), NOT to -// the historical linearcodec big-endian wire format. Activation -// per LP-023 (proto/zap_native/codec_select.go: ZAPActivationUnix=0). -package pcodecs - -import ( - "math" - - "github.com/luxfi/proto/zap_codec" -) - -// Manager is the multi-version wire codec surface every node/vms -// consumer holds. Aliased to zap_codec.MultiManager so the rest of -// node/vms references pcodecs.Manager rather than reaching into -// proto/zap_codec or luxfi/codec directly. -type Manager = zap_codec.MultiManager - -// Registry is the type-registration surface. Aliased to -// zap_codec.Registry — structurally identical to the legacy -// codec.Registry interface (RegisterType only). -type Registry = zap_codec.Registry - -// LinearCodec is the union of Registry + Codec + SkipRegistrations. -// Used by VMs that need SkipRegistrations on their per-version codec -// to preserve historical type-id slot layouts (Apricot / Banff / -// Durango / Quasar registration sequences). -// -// Despite the name, this codec is backed by luxfi/codec/zapcodec — the -// "Linear" refers to LINEAR TYPE-ID ASSIGNMENT, not to the legacy -// linearcodec big-endian wire layout. -type LinearCodec = zap_codec.LinearCodec - -// ZAPCodec is an explicit alias for the same zapcodec-backed Codec -// surface — used by post-cutover wire layouts (currently platformvm -// txs V2) that want to emphasise the ZAP-native wire layout. Same -// backing type as LinearCodec; the alias exists for readability. -type ZAPCodec = zap_codec.ZAPCodec - -// Errs is the multi-error accumulator used by per-VM codec.go files -// that fan in many RegisterCodec / RegisterType calls under a single -// error tap. -type Errs = zap_codec.Errs - -// Packer is the wire-byte packer used by VM tests that drive -// MarshalInto / UnmarshalFrom byte streams directly. -type Packer = zap_codec.Packer - -// VersionSize is the on-wire length of the codec-version prefix -// (2 bytes). VM fee-complexity calculations subtract this from -// observed byte sizes to isolate the payload component. -const VersionSize = zap_codec.VersionSize - -// Sentinel errors re-exported from proto/zap_codec so VM packages can -// assert on them without importing proto/zap_codec themselves. -var ( - ErrCantPackVersion = zap_codec.ErrCantPackVersion - ErrCantUnpackVersion = zap_codec.ErrCantUnpackVersion - ErrUnknownVersion = zap_codec.ErrUnknownVersion - ErrMaxSliceLenExceeded = zap_codec.ErrMaxSliceLenExceeded - ErrMaxSizeExceeded = zap_codec.ErrMaxSizeExceeded - ErrMarshalNil = zap_codec.ErrMarshalNil - ErrUnmarshalNil = zap_codec.ErrUnmarshalNil - ErrDoesNotImplementInterface = zap_codec.ErrDoesNotImplementInterface - ErrExtraSpace = zap_codec.ErrExtraSpace - - ErrInsufficientLength = zap_codec.ErrInsufficientLength -) - -// LongLen is the on-wire length of a uint64 (8 bytes). Used by index -// code to size cursor buffers. -const LongLen = zap_codec.LongLen - -// IntLen is the on-wire length of a uint32 (4 bytes). Used by p2p -// response-size accounting code. -const IntLen = zap_codec.IntLen - -// ShortLen is the on-wire length of a uint16 (2 bytes). -const ShortLen = zap_codec.ShortLen - -// ByteLen is the on-wire length of a uint8 (1 byte). -const ByteLen = zap_codec.ByteLen - -// BoolLen is the on-wire length of a bool (1 byte). -const BoolLen = zap_codec.BoolLen - -// NewLinearCodec returns a fresh ZAP-native Codec instance with the -// default ("serialize") struct tag. The "Linear" name refers to -// LINEAR TYPE-ID ASSIGNMENT (sequential ids assigned in registration -// order), NOT to the legacy linearcodec big-endian wire format. -func NewLinearCodec() LinearCodec { - return zap_codec.NewLinearCodec() -} - -// NewLinearCodecWithTags returns a fresh ZAP-native Codec instance -// that honours the supplied struct-tag names. Used by the metadata -// codec wiring where v0:"true" / v1:"true" tags select per-version -// field sets. -func NewLinearCodecWithTags(tags ...string) LinearCodec { - return zap_codec.NewLinearCodecWithTags(tags...) -} - -// NewZAPCodec returns a fresh ZAP-native Codec instance. Alias for -// NewLinearCodec — both return the same zapcodec-backed Codec; the -// name exists for call sites that want to emphasise the ZAP-native -// wire layout (e.g. platformvm txs V2). -func NewZAPCodec() ZAPCodec { - return zap_codec.NewZAPCodec() -} - -// NewDefaultManager returns a fresh multi-version Manager with the -// default 1 MiB wire-payload size. -func NewDefaultManager() Manager { - return zap_codec.NewDefaultManager() -} - -// NewManager returns a fresh multi-version Manager with the supplied -// max wire-payload size. -func NewManager(maxSize uint64) Manager { - return zap_codec.NewManager(maxSize) -} - -// NewMaxInt32Manager returns a fresh multi-version Manager sized for -// genesis-style blobs (math.MaxInt32 budget). VM genesis codec wiring -// reaches for this rather than re-deriving the budget at every call -// site. -func NewMaxInt32Manager() Manager { - return zap_codec.NewMaxInt32Manager() -} - -// NewMaxIntManager returns a fresh multi-version Manager sized for -// warp / proposervm-block style payloads (math.MaxInt budget — -// effectively unbounded). The p2p layer caps real-world wire sizes -// well below this. -func NewMaxIntManager() Manager { - return zap_codec.NewManager(uint64(math.MaxInt)) -} diff --git a/vms/pcodecs/pcodecsmock/manager.go b/vms/pcodecs/pcodecsmock/manager.go deleted file mode 100644 index 2d0334a90..000000000 --- a/vms/pcodecs/pcodecsmock/manager.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (C) 2019-2026, Lux Industries, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -// Package pcodecsmock provides a gomock-driven mock of the -// pcodecs.Manager interface (= proto/zap_codec.MultiManager) so -// node/vms test files can program codec expectations without -// importing proto/zap_codec or luxfi/codec directly. -// -// Wave 2G-Internal of the codec rip (#101) replaces the previous -// re-export of luxfi/codec/codecmock with an in-tree mock of the -// proto/zap_codec.MultiManager interface. The mock satisfies -// pcodecs.Manager by shape — RegisterCodec / Marshal / Unmarshal / -// Size — and is independent of the underlying codec wire format. -package pcodecsmock - -import ( - "reflect" - - "github.com/luxfi/proto/zap_codec" - gomock "go.uber.org/mock/gomock" -) - -// Compile-time check: Manager satisfies zap_codec.MultiManager (the -// interface pcodecs.Manager aliases). Keeps the mock in sync with the -// underlying interface — any new method on MultiManager fails this -// assertion until the mock is updated. -var _ zap_codec.MultiManager = (*Manager)(nil) - -// Manager is the gomock-driven mock of pcodecs.Manager (= -// zap_codec.MultiManager). Tests reach for pcodecsmock.NewManager(ctrl) -// to obtain a mock that satisfies pcodecs.Manager by shape. -type Manager struct { - ctrl *gomock.Controller - recorder *ManagerRecorder -} - -// ManagerRecorder is the gomock recorder for Manager. Tests program -// expectations via mock.EXPECT().(...).Return(...). -type ManagerRecorder struct { - mock *Manager -} - -// NewManager constructs a fresh Manager mock against the supplied -// gomock controller. -func NewManager(ctrl *gomock.Controller) *Manager { - m := &Manager{ctrl: ctrl} - m.recorder = &ManagerRecorder{mock: m} - return m -} - -// EXPECT returns the recorder so tests can program expectations. -func (m *Manager) EXPECT() *ManagerRecorder { - return m.recorder -} - -// RegisterCodec mocks the corresponding MultiManager method. -func (m *Manager) RegisterCodec(version uint16, codec zap_codec.Codec) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RegisterCodec", version, codec) - ret0, _ := ret[0].(error) - return ret0 -} - -// RegisterCodec expectation. -func (mr *ManagerRecorder) RegisterCodec(version, codec any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterCodec", reflect.TypeOf((*Manager)(nil).RegisterCodec), version, codec) -} - -// Marshal mocks the corresponding MultiManager method. -func (m *Manager) Marshal(version uint16, source interface{}) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Marshal", version, source) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Marshal expectation. -func (mr *ManagerRecorder) Marshal(version, source any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Marshal", reflect.TypeOf((*Manager)(nil).Marshal), version, source) -} - -// Unmarshal mocks the corresponding MultiManager method. -func (m *Manager) Unmarshal(source []byte, destination interface{}) (uint16, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Unmarshal", source, destination) - ret0, _ := ret[0].(uint16) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Unmarshal expectation. -func (mr *ManagerRecorder) Unmarshal(source, destination any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unmarshal", reflect.TypeOf((*Manager)(nil).Unmarshal), source, destination) -} - -// Size mocks the corresponding MultiManager method. -func (m *Manager) Size(version uint16, value interface{}) (int, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Size", version, value) - ret0, _ := ret[0].(int) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Size expectation. -func (mr *ManagerRecorder) Size(version, value any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Size", reflect.TypeOf((*Manager)(nil).Size), version, value) -} diff --git a/wallet/chain/x/builder.go b/wallet/chain/x/builder.go index 07687da24..a6a509139 100644 --- a/wallet/chain/x/builder.go +++ b/wallet/chain/x/builder.go @@ -252,14 +252,13 @@ func (b *txBuilder) NewCreateAssetTx( return nil, err } - codec := Parser.Codec() states := make([]*txs.InitialState, 0, len(initialState)) for fxIndex, outs := range initialState { state := &txs.InitialState{ FxIndex: fxIndex, Outs: outs, } - state.Sort(codec) // sort the outputs + state.Sort() // sort the outputs states = append(states, state) } @@ -293,7 +292,7 @@ func (b *txBuilder) NewOperationTx( return nil, err } - txs.SortOperations(operations, Parser.Codec()) + txs.SortOperations(operations) return &txs.OperationTx{ BaseTx: txs.BaseTx{BaseTx: lux.BaseTx{ NetworkID: b.backend.Context().NetworkID, diff --git a/wallet/chain/x/builder/builder.go b/wallet/chain/x/builder/builder.go index 7afd30f93..944641ae7 100644 --- a/wallet/chain/x/builder/builder.go +++ b/wallet/chain/x/builder/builder.go @@ -254,7 +254,6 @@ func (b *builder) NewCreateAssetTx( return nil, err } - codec := Parser.Codec() states := make([]*txs.InitialState, 0, len(initialState)) for fxIndex, outs := range initialState { state := &txs.InitialState{ @@ -262,7 +261,7 @@ func (b *builder) NewCreateAssetTx( FxID: fxIndexToID[fxIndex], Outs: outs, } - state.Sort(codec) // sort the outputs + state.Sort() // sort the outputs states = append(states, state) } @@ -296,7 +295,7 @@ func (b *builder) NewOperationTx( return nil, err } - txs.SortOperations(operations, Parser.Codec()) + txs.SortOperations(operations) tx := &txs.OperationTx{ BaseTx: txs.BaseTx{BaseTx: lux.BaseTx{ NetworkID: b.context.NetworkID, diff --git a/wallet/chain/x/signer/visitor.go b/wallet/chain/x/signer/visitor.go index 287ca913f..642a2e369 100644 --- a/wallet/chain/x/signer/visitor.go +++ b/wallet/chain/x/signer/visitor.go @@ -16,7 +16,6 @@ import ( "github.com/luxfi/node/vms/components/verify" "github.com/luxfi/node/vms/xvm/fxs" "github.com/luxfi/node/vms/xvm/txs" - "github.com/luxfi/node/wallet/chain/x/builder" "github.com/luxfi/utxo/nftfx" "github.com/luxfi/utxo/propertyfx" "github.com/luxfi/utxo/secp256k1fx" @@ -219,8 +218,7 @@ func (s *visitor) getOpsSigners(ctx context.Context, sourceChainID ids.ID, ops [ } func sign(tx *txs.Tx, creds []verify.Verifiable, txSigners [][]keychain.Signer) error { - codec := builder.Parser.Codec() - unsignedBytes, err := codec.Marshal(txs.CodecVersion, &tx.Unsigned) + unsignedBytes, err := txs.UnsignedBytes(tx.Unsigned) if err != nil { return fmt.Errorf("couldn't marshal unsigned tx: %w", err) } @@ -291,10 +289,8 @@ func sign(tx *txs.Tx, creds []verify.Verifiable, txSigners [][]keychain.Signer) } } - signedBytes, err := codec.Marshal(txs.CodecVersion, tx) - if err != nil { - return fmt.Errorf("couldn't marshal tx: %w", err) - } - tx.SetBytes(unsignedBytes, signedBytes) - return nil + // Rebuild the signed wire bytes (unsigned ‖ fx credential envelopes) and + // bind TxID = hash(signedBytes). The unsigned bytes are already cached, so + // Initialize reuses the exact bytes just signed over. + return tx.Initialize() } diff --git a/wallet/chain/x/signer_visitor.go b/wallet/chain/x/signer_visitor.go index 86fd35fc2..b0018f6f6 100644 --- a/wallet/chain/x/signer_visitor.go +++ b/wallet/chain/x/signer_visitor.go @@ -219,8 +219,7 @@ func (s *signerVisitor) getOpsSigners(ctx stdcontext.Context, sourceChainID ids. } func sign(tx *txs.Tx, creds []verify.Verifiable, txSigners [][]keychain.Signer) error { - codec := Parser.Codec() - unsignedBytes, err := codec.Marshal(txs.CodecVersion, &tx.Unsigned) + unsignedBytes, err := txs.UnsignedBytes(tx.Unsigned) if err != nil { return fmt.Errorf("couldn't marshal unsigned tx: %w", err) } @@ -288,10 +287,8 @@ func sign(tx *txs.Tx, creds []verify.Verifiable, txSigners [][]keychain.Signer) } } - signedBytes, err := codec.Marshal(txs.CodecVersion, tx) - if err != nil { - return fmt.Errorf("couldn't marshal tx: %w", err) - } - tx.SetBytes(unsignedBytes, signedBytes) - return nil + // Rebuild the signed wire bytes (unsigned ‖ fx credential envelopes) and + // bind TxID = hash(signedBytes). The unsigned bytes are already cached, so + // Initialize reuses the exact bytes just signed over. + return tx.Initialize() }