github.com/MetalBlockchain/metalgo@v1.11.9/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/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/vms/avm/state"
    13  	"github.com/MetalBlockchain/metalgo/vms/avm/txs"
    14  	"github.com/MetalBlockchain/metalgo/vms/components/avax"
    15  	"github.com/MetalBlockchain/metalgo/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  }