github.com/MetalBlockchain/metalgo@v1.11.9/vms/avm/txs/operation.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package txs 5 6 import ( 7 "bytes" 8 "errors" 9 "sort" 10 11 "github.com/MetalBlockchain/metalgo/codec" 12 "github.com/MetalBlockchain/metalgo/ids" 13 "github.com/MetalBlockchain/metalgo/utils" 14 "github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1" 15 "github.com/MetalBlockchain/metalgo/vms/avm/fxs" 16 "github.com/MetalBlockchain/metalgo/vms/components/avax" 17 "github.com/MetalBlockchain/metalgo/vms/components/verify" 18 ) 19 20 var ( 21 ErrNilOperation = errors.New("nil operation is not valid") 22 ErrNilFxOperation = errors.New("nil fx operation is not valid") 23 ErrNotSortedAndUniqueUTXOIDs = errors.New("utxo IDs not sorted and unique") 24 ) 25 26 type Operation struct { 27 avax.Asset `serialize:"true"` 28 UTXOIDs []*avax.UTXOID `serialize:"true" json:"inputIDs"` 29 FxID ids.ID `serialize:"false" json:"fxID"` 30 Op fxs.FxOperation `serialize:"true" json:"operation"` 31 } 32 33 func (op *Operation) Verify() error { 34 switch { 35 case op == nil: 36 return ErrNilOperation 37 case op.Op == nil: 38 return ErrNilFxOperation 39 case !utils.IsSortedAndUnique(op.UTXOIDs): 40 return ErrNotSortedAndUniqueUTXOIDs 41 default: 42 return verify.All(&op.Asset, op.Op) 43 } 44 } 45 46 type operationAndCodec struct { 47 op *Operation 48 codec codec.Manager 49 } 50 51 func (o *operationAndCodec) Compare(other *operationAndCodec) int { 52 oBytes, err := o.codec.Marshal(CodecVersion, o.op) 53 if err != nil { 54 return 0 55 } 56 otherBytes, err := o.codec.Marshal(CodecVersion, other.op) 57 if err != nil { 58 return 0 59 } 60 return bytes.Compare(oBytes, otherBytes) 61 } 62 63 func SortOperations(ops []*Operation, c codec.Manager) { 64 sortableOps := make([]*operationAndCodec, len(ops)) 65 for i, op := range ops { 66 sortableOps[i] = &operationAndCodec{ 67 op: op, 68 codec: c, 69 } 70 } 71 72 utils.Sort(sortableOps) 73 for i, sortableOp := range sortableOps { 74 ops[i] = sortableOp.op 75 } 76 } 77 78 func IsSortedAndUniqueOperations(ops []*Operation, c codec.Manager) bool { 79 sortableOps := make([]*operationAndCodec, len(ops)) 80 for i, op := range ops { 81 sortableOps[i] = &operationAndCodec{ 82 op: op, 83 codec: c, 84 } 85 } 86 return utils.IsSortedAndUnique(sortableOps) 87 } 88 89 type innerSortOperationsWithSigners struct { 90 ops []*Operation 91 signers [][]*secp256k1.PrivateKey 92 codec codec.Manager 93 } 94 95 func (ops *innerSortOperationsWithSigners) Less(i, j int) bool { 96 iOp := ops.ops[i] 97 jOp := ops.ops[j] 98 99 iBytes, err := ops.codec.Marshal(CodecVersion, iOp) 100 if err != nil { 101 return false 102 } 103 jBytes, err := ops.codec.Marshal(CodecVersion, jOp) 104 if err != nil { 105 return false 106 } 107 return bytes.Compare(iBytes, jBytes) == -1 108 } 109 110 func (ops *innerSortOperationsWithSigners) Len() int { 111 return len(ops.ops) 112 } 113 114 func (ops *innerSortOperationsWithSigners) Swap(i, j int) { 115 ops.ops[j], ops.ops[i] = ops.ops[i], ops.ops[j] 116 ops.signers[j], ops.signers[i] = ops.signers[i], ops.signers[j] 117 } 118 119 func SortOperationsWithSigners(ops []*Operation, signers [][]*secp256k1.PrivateKey, codec codec.Manager) { 120 sort.Sort(&innerSortOperationsWithSigners{ops: ops, signers: signers, codec: codec}) 121 }