mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
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.
131 lines
4.0 KiB
Go
131 lines
4.0 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package txs
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"sort"
|
|
|
|
"github.com/luxfi/crypto/secp256k1"
|
|
"github.com/luxfi/node/vms/components/verify"
|
|
"github.com/luxfi/node/vms/pcodecs"
|
|
"github.com/luxfi/utils"
|
|
lux "github.com/luxfi/utxo"
|
|
"github.com/luxfi/utxo/secp256k1fx"
|
|
)
|
|
|
|
// Operation expresses an action against a previously-minted asset's UTXOs
|
|
// (transfer, mint, burn, NFT-style state op). PlatformVM exposes only the
|
|
// secp256k1fx Fx so [Op] is a secp256k1fx-compatible verifiable input.
|
|
type Operation struct {
|
|
lux.Asset `serialize:"true"`
|
|
|
|
// UTXOIDs of UTXOs this operation consumes.
|
|
UTXOIDs []*lux.UTXOID `serialize:"true" json:"inputIDs"`
|
|
|
|
// Op is the action to perform. On P-Chain this is always a
|
|
// secp256k1fx-flavoured operation; the codec keeps the door open for
|
|
// additional Fx flavours by storing a verify.Verifiable.
|
|
Op verify.Verifiable `serialize:"true" json:"operation"`
|
|
}
|
|
|
|
var (
|
|
ErrNilOperation = errors.New("nil operation is not valid")
|
|
ErrNilFxOperation = errors.New("nil fx operation is not valid")
|
|
ErrNotSortedAndUniqueUTXOIDs = errors.New("utxo ids on operation are not sorted and unique")
|
|
// ErrUnsupportedOpType pins [Op] to the single Fx PlatformVM ships
|
|
// (secp256k1fx). Anything else — propertyfx, nftfx, a future Fx an
|
|
// attacker tries to slip in — is rejected at syntactic verification
|
|
// time before any state-modifying executor sees it.
|
|
ErrUnsupportedOpType = errors.New("operation op type is not supported on PlatformVM (secp256k1fx only)")
|
|
)
|
|
|
|
// Verify returns nil iff this Operation is well formed.
|
|
func (op *Operation) Verify() error {
|
|
switch {
|
|
case op == nil:
|
|
return ErrNilOperation
|
|
case op.Op == nil:
|
|
return ErrNilFxOperation
|
|
case !utils.IsSortedAndUnique(op.UTXOIDs):
|
|
return ErrNotSortedAndUniqueUTXOIDs
|
|
}
|
|
if _, ok := op.Op.(*secp256k1fx.MintOperation); !ok {
|
|
return ErrUnsupportedOpType
|
|
}
|
|
return verify.All(&op.Asset, op.Op)
|
|
}
|
|
|
|
// secp256k1fx is the only Fx on PlatformVM. The compile-time check guards
|
|
// against drift if a developer tries to wire a non-secp256k1fx operation in.
|
|
var _ = secp256k1fx.ID
|
|
|
|
// SortOperations sorts the given operations by their codec-marshalled bytes.
|
|
type operationAndCodec struct {
|
|
op *Operation
|
|
codec pcodecs.Manager
|
|
}
|
|
|
|
func (o *operationAndCodec) Compare(other *operationAndCodec) int {
|
|
oBytes, err := o.codec.Marshal(CodecVersion, o.op)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
otherBytes, err := o.codec.Marshal(CodecVersion, other.op)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return bytes.Compare(oBytes, otherBytes)
|
|
}
|
|
|
|
func SortOperations(ops []*Operation, c pcodecs.Manager) {
|
|
wrapped := make([]*operationAndCodec, len(ops))
|
|
for i, op := range ops {
|
|
wrapped[i] = &operationAndCodec{op: op, codec: c}
|
|
}
|
|
utils.Sort(wrapped)
|
|
for i, w := range wrapped {
|
|
ops[i] = w.op
|
|
}
|
|
}
|
|
|
|
// IsSortedAndUniqueOperations reports whether [ops] is sorted by codec bytes
|
|
// and contains no duplicates.
|
|
func IsSortedAndUniqueOperations(ops []*Operation, c pcodecs.Manager) bool {
|
|
wrapped := make([]*operationAndCodec, len(ops))
|
|
for i, op := range ops {
|
|
wrapped[i] = &operationAndCodec{op: op, codec: c}
|
|
}
|
|
return utils.IsSortedAndUnique(wrapped)
|
|
}
|
|
|
|
type innerSortOperationsWithSigners struct {
|
|
ops []*Operation
|
|
signers [][]*secp256k1.PrivateKey
|
|
codec pcodecs.Manager
|
|
}
|
|
|
|
func (s *innerSortOperationsWithSigners) Less(i, j int) bool {
|
|
iBytes, err := s.codec.Marshal(CodecVersion, s.ops[i])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
jBytes, err := s.codec.Marshal(CodecVersion, s.ops[j])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return bytes.Compare(iBytes, jBytes) == -1
|
|
}
|
|
|
|
func (s *innerSortOperationsWithSigners) Len() int { return len(s.ops) }
|
|
func (s *innerSortOperationsWithSigners) Swap(i, j int) {
|
|
s.ops[j], s.ops[i] = s.ops[i], s.ops[j]
|
|
s.signers[j], s.signers[i] = s.signers[i], s.signers[j]
|
|
}
|
|
|
|
func SortOperationsWithSigners(ops []*Operation, signers [][]*secp256k1.PrivateKey, c pcodecs.Manager) {
|
|
sort.Sort(&innerSortOperationsWithSigners{ops: ops, signers: signers, codec: c})
|
|
}
|