github.com/ava-labs/avalanchego@v1.11.11/vms/avm/txs/executor/semantic_verifier.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package executor 5 6 import ( 7 "context" 8 "errors" 9 "reflect" 10 11 "github.com/ava-labs/avalanchego/ids" 12 "github.com/ava-labs/avalanchego/vms/avm/state" 13 "github.com/ava-labs/avalanchego/vms/avm/txs" 14 "github.com/ava-labs/avalanchego/vms/components/avax" 15 "github.com/ava-labs/avalanchego/vms/components/verify" 16 ) 17 18 var ( 19 _ txs.Visitor = (*SemanticVerifier)(nil) 20 21 errAssetIDMismatch = errors.New("asset IDs in the input don't match the utxo") 22 errNotAnAsset = errors.New("not an asset") 23 errIncompatibleFx = errors.New("incompatible feature extension") 24 errUnknownFx = errors.New("unknown feature extension") 25 ) 26 27 type SemanticVerifier struct { 28 *Backend 29 State state.ReadOnlyChain 30 Tx *txs.Tx 31 } 32 33 func (v *SemanticVerifier) BaseTx(tx *txs.BaseTx) error { 34 for i, in := range tx.Ins { 35 // Note: Verification of the length of [t.tx.Creds] happens during 36 // syntactic verification, which happens before semantic verification. 37 cred := v.Tx.Creds[i].Credential 38 if err := v.verifyTransfer(tx, in, cred); err != nil { 39 return err 40 } 41 } 42 43 for _, out := range tx.Outs { 44 fxIndex, err := v.getFx(out.Out) 45 if err != nil { 46 return err 47 } 48 49 assetID := out.AssetID() 50 if err := v.verifyFxUsage(fxIndex, assetID); err != nil { 51 return err 52 } 53 } 54 55 return nil 56 } 57 58 func (v *SemanticVerifier) CreateAssetTx(tx *txs.CreateAssetTx) error { 59 return v.BaseTx(&tx.BaseTx) 60 } 61 62 func (v *SemanticVerifier) OperationTx(tx *txs.OperationTx) error { 63 if err := v.BaseTx(&tx.BaseTx); err != nil { 64 return err 65 } 66 67 if !v.Bootstrapped || v.Tx.ID().String() == "MkvpJS13eCnEYeYi9B5zuWrU9goG9RBj7nr83U7BjrFV22a12" { 68 return nil 69 } 70 71 offset := len(tx.Ins) 72 for i, op := range tx.Ops { 73 // Note: Verification of the length of [t.tx.Creds] happens during 74 // syntactic verification, which happens before semantic verification. 75 cred := v.Tx.Creds[i+offset].Credential 76 if err := v.verifyOperation(tx, op, cred); err != nil { 77 return err 78 } 79 } 80 return nil 81 } 82 83 func (v *SemanticVerifier) ImportTx(tx *txs.ImportTx) error { 84 if err := v.BaseTx(&tx.BaseTx); err != nil { 85 return err 86 } 87 88 if !v.Bootstrapped { 89 return nil 90 } 91 92 if err := verify.SameSubnet(context.TODO(), v.Ctx, tx.SourceChain); err != nil { 93 return err 94 } 95 96 utxoIDs := make([][]byte, len(tx.ImportedIns)) 97 for i, in := range tx.ImportedIns { 98 inputID := in.UTXOID.InputID() 99 utxoIDs[i] = inputID[:] 100 } 101 102 allUTXOBytes, err := v.Ctx.SharedMemory.Get(tx.SourceChain, utxoIDs) 103 if err != nil { 104 return err 105 } 106 107 offset := len(tx.Ins) 108 for i, in := range tx.ImportedIns { 109 utxo := avax.UTXO{} 110 if _, err := v.Codec.Unmarshal(allUTXOBytes[i], &utxo); err != nil { 111 return err 112 } 113 114 // Note: Verification of the length of [t.tx.Creds] happens during 115 // syntactic verification, which happens before semantic verification. 116 cred := v.Tx.Creds[i+offset].Credential 117 if err := v.verifyTransferOfUTXO(tx, in, cred, &utxo); err != nil { 118 return err 119 } 120 } 121 return nil 122 } 123 124 func (v *SemanticVerifier) ExportTx(tx *txs.ExportTx) error { 125 if err := v.BaseTx(&tx.BaseTx); err != nil { 126 return err 127 } 128 129 if v.Bootstrapped { 130 if err := verify.SameSubnet(context.TODO(), v.Ctx, tx.DestinationChain); err != nil { 131 return err 132 } 133 } 134 135 for _, out := range tx.ExportedOuts { 136 fxIndex, err := v.getFx(out.Out) 137 if err != nil { 138 return err 139 } 140 141 assetID := out.AssetID() 142 if err := v.verifyFxUsage(fxIndex, assetID); err != nil { 143 return err 144 } 145 } 146 return nil 147 } 148 149 func (v *SemanticVerifier) verifyTransfer( 150 tx txs.UnsignedTx, 151 in *avax.TransferableInput, 152 cred verify.Verifiable, 153 ) error { 154 utxo, err := v.State.GetUTXO(in.UTXOID.InputID()) 155 if err != nil { 156 return err 157 } 158 return v.verifyTransferOfUTXO(tx, in, cred, utxo) 159 } 160 161 func (v *SemanticVerifier) verifyTransferOfUTXO( 162 tx txs.UnsignedTx, 163 in *avax.TransferableInput, 164 cred verify.Verifiable, 165 utxo *avax.UTXO, 166 ) error { 167 utxoAssetID := utxo.AssetID() 168 inAssetID := in.AssetID() 169 if utxoAssetID != inAssetID { 170 return errAssetIDMismatch 171 } 172 173 fxIndex, err := v.getFx(cred) 174 if err != nil { 175 return err 176 } 177 178 if err := v.verifyFxUsage(fxIndex, inAssetID); err != nil { 179 return err 180 } 181 182 fx := v.Fxs[fxIndex].Fx 183 return fx.VerifyTransfer(tx, in.In, cred, utxo.Out) 184 } 185 186 func (v *SemanticVerifier) verifyOperation( 187 tx *txs.OperationTx, 188 op *txs.Operation, 189 cred verify.Verifiable, 190 ) error { 191 var ( 192 opAssetID = op.AssetID() 193 numUTXOs = len(op.UTXOIDs) 194 utxos = make([]interface{}, numUTXOs) 195 ) 196 for i, utxoID := range op.UTXOIDs { 197 utxo, err := v.State.GetUTXO(utxoID.InputID()) 198 if err != nil { 199 return err 200 } 201 202 utxoAssetID := utxo.AssetID() 203 if utxoAssetID != opAssetID { 204 return errAssetIDMismatch 205 } 206 utxos[i] = utxo.Out 207 } 208 209 fxIndex, err := v.getFx(op.Op) 210 if err != nil { 211 return err 212 } 213 214 if err := v.verifyFxUsage(fxIndex, opAssetID); err != nil { 215 return err 216 } 217 218 fx := v.Fxs[fxIndex].Fx 219 return fx.VerifyOperation(tx, op.Op, cred, utxos) 220 } 221 222 func (v *SemanticVerifier) verifyFxUsage( 223 fxID int, 224 assetID ids.ID, 225 ) error { 226 tx, err := v.State.GetTx(assetID) 227 if err != nil { 228 return err 229 } 230 231 createAssetTx, ok := tx.Unsigned.(*txs.CreateAssetTx) 232 if !ok { 233 return errNotAnAsset 234 } 235 236 for _, state := range createAssetTx.States { 237 if state.FxIndex == uint32(fxID) { 238 return nil 239 } 240 } 241 242 return errIncompatibleFx 243 } 244 245 func (v *SemanticVerifier) getFx(val interface{}) (int, error) { 246 valType := reflect.TypeOf(val) 247 fx, exists := v.TypeToFxIndex[valType] 248 if !exists { 249 return 0, errUnknownFx 250 } 251 return fx, nil 252 }