github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/txs/base_tx.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 "errors" 8 "fmt" 9 10 "github.com/MetalBlockchain/metalgo/ids" 11 "github.com/MetalBlockchain/metalgo/snow" 12 "github.com/MetalBlockchain/metalgo/utils" 13 "github.com/MetalBlockchain/metalgo/utils/set" 14 "github.com/MetalBlockchain/metalgo/vms/components/avax" 15 "github.com/MetalBlockchain/metalgo/vms/secp256k1fx" 16 ) 17 18 var ( 19 _ UnsignedTx = (*BaseTx)(nil) 20 21 ErrNilTx = errors.New("tx is nil") 22 23 errOutputsNotSorted = errors.New("outputs not sorted") 24 errInputsNotSortedUnique = errors.New("inputs not sorted and unique") 25 ) 26 27 // BaseTx contains fields common to many transaction types. It should be 28 // embedded in transaction implementations. 29 type BaseTx struct { 30 avax.BaseTx `serialize:"true"` 31 32 // true iff this transaction has already passed syntactic verification 33 SyntacticallyVerified bool `json:"-"` 34 35 unsignedBytes []byte // Unsigned byte representation of this data 36 } 37 38 func (tx *BaseTx) SetBytes(unsignedBytes []byte) { 39 tx.unsignedBytes = unsignedBytes 40 } 41 42 func (tx *BaseTx) Bytes() []byte { 43 return tx.unsignedBytes 44 } 45 46 func (tx *BaseTx) InputIDs() set.Set[ids.ID] { 47 inputIDs := set.NewSet[ids.ID](len(tx.Ins)) 48 for _, in := range tx.Ins { 49 inputIDs.Add(in.InputID()) 50 } 51 return inputIDs 52 } 53 54 func (tx *BaseTx) Outputs() []*avax.TransferableOutput { 55 return tx.Outs 56 } 57 58 // InitCtx sets the FxID fields in the inputs and outputs of this [BaseTx]. Also 59 // sets the [ctx] to the given [vm.ctx] so that the addresses can be json 60 // marshalled into human readable format 61 func (tx *BaseTx) InitCtx(ctx *snow.Context) { 62 for _, in := range tx.BaseTx.Ins { 63 in.FxID = secp256k1fx.ID 64 } 65 for _, out := range tx.BaseTx.Outs { 66 out.FxID = secp256k1fx.ID 67 out.InitCtx(ctx) 68 } 69 } 70 71 // SyntacticVerify returns nil iff this tx is well formed 72 func (tx *BaseTx) SyntacticVerify(ctx *snow.Context) error { 73 switch { 74 case tx == nil: 75 return ErrNilTx 76 case tx.SyntacticallyVerified: // already passed syntactic verification 77 return nil 78 } 79 if err := tx.BaseTx.Verify(ctx); err != nil { 80 return fmt.Errorf("metadata failed verification: %w", err) 81 } 82 for _, out := range tx.Outs { 83 if err := out.Verify(); err != nil { 84 return fmt.Errorf("output failed verification: %w", err) 85 } 86 } 87 for _, in := range tx.Ins { 88 if err := in.Verify(); err != nil { 89 return fmt.Errorf("input failed verification: %w", err) 90 } 91 } 92 switch { 93 case !avax.IsSortedTransferableOutputs(tx.Outs, Codec): 94 return errOutputsNotSorted 95 case !utils.IsSortedAndUnique(tx.Ins): 96 return errInputsNotSortedUnique 97 default: 98 return nil 99 } 100 } 101 102 func (tx *BaseTx) Visit(visitor Visitor) error { 103 return visitor.BaseTx(tx) 104 }