github.com/MetalBlockchain/metalgo@v1.11.9/vms/avm/txs/executor/executor.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  	"fmt"
     8  
     9  	"github.com/MetalBlockchain/metalgo/chains/atomic"
    10  	"github.com/MetalBlockchain/metalgo/codec"
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/utils/set"
    13  	"github.com/MetalBlockchain/metalgo/vms/avm/state"
    14  	"github.com/MetalBlockchain/metalgo/vms/avm/txs"
    15  	"github.com/MetalBlockchain/metalgo/vms/components/avax"
    16  )
    17  
    18  var _ txs.Visitor = (*Executor)(nil)
    19  
    20  type Executor struct {
    21  	Codec          codec.Manager
    22  	State          state.Chain // state will be modified
    23  	Tx             *txs.Tx
    24  	Inputs         set.Set[ids.ID]             // imported inputs
    25  	AtomicRequests map[ids.ID]*atomic.Requests // may be nil
    26  }
    27  
    28  func (e *Executor) BaseTx(tx *txs.BaseTx) error {
    29  	txID := e.Tx.ID()
    30  	avax.Consume(e.State, tx.Ins)
    31  	avax.Produce(e.State, txID, tx.Outs)
    32  	return nil
    33  }
    34  
    35  func (e *Executor) CreateAssetTx(tx *txs.CreateAssetTx) error {
    36  	if err := e.BaseTx(&tx.BaseTx); err != nil {
    37  		return err
    38  	}
    39  
    40  	txID := e.Tx.ID()
    41  	index := len(tx.Outs)
    42  	for _, state := range tx.States {
    43  		for _, out := range state.Outs {
    44  			e.State.AddUTXO(&avax.UTXO{
    45  				UTXOID: avax.UTXOID{
    46  					TxID:        txID,
    47  					OutputIndex: uint32(index),
    48  				},
    49  				Asset: avax.Asset{
    50  					ID: txID,
    51  				},
    52  				Out: out,
    53  			})
    54  			index++
    55  		}
    56  	}
    57  	return nil
    58  }
    59  
    60  func (e *Executor) OperationTx(tx *txs.OperationTx) error {
    61  	if err := e.BaseTx(&tx.BaseTx); err != nil {
    62  		return err
    63  	}
    64  
    65  	txID := e.Tx.ID()
    66  	index := len(tx.Outs)
    67  	for _, op := range tx.Ops {
    68  		for _, utxoID := range op.UTXOIDs {
    69  			e.State.DeleteUTXO(utxoID.InputID())
    70  		}
    71  		asset := op.AssetID()
    72  		for _, out := range op.Op.Outs() {
    73  			e.State.AddUTXO(&avax.UTXO{
    74  				UTXOID: avax.UTXOID{
    75  					TxID:        txID,
    76  					OutputIndex: uint32(index),
    77  				},
    78  				Asset: avax.Asset{ID: asset},
    79  				Out:   out,
    80  			})
    81  			index++
    82  		}
    83  	}
    84  	return nil
    85  }
    86  
    87  func (e *Executor) ImportTx(tx *txs.ImportTx) error {
    88  	if err := e.BaseTx(&tx.BaseTx); err != nil {
    89  		return err
    90  	}
    91  
    92  	utxoIDs := make([][]byte, len(tx.ImportedIns))
    93  	for i, in := range tx.ImportedIns {
    94  		utxoID := in.UTXOID.InputID()
    95  
    96  		e.Inputs.Add(utxoID)
    97  		utxoIDs[i] = utxoID[:]
    98  	}
    99  	e.AtomicRequests = map[ids.ID]*atomic.Requests{
   100  		tx.SourceChain: {
   101  			RemoveRequests: utxoIDs,
   102  		},
   103  	}
   104  	return nil
   105  }
   106  
   107  func (e *Executor) ExportTx(tx *txs.ExportTx) error {
   108  	if err := e.BaseTx(&tx.BaseTx); err != nil {
   109  		return err
   110  	}
   111  
   112  	txID := e.Tx.ID()
   113  	index := len(tx.Outs)
   114  	elems := make([]*atomic.Element, len(tx.ExportedOuts))
   115  	for i, out := range tx.ExportedOuts {
   116  		utxo := &avax.UTXO{
   117  			UTXOID: avax.UTXOID{
   118  				TxID:        txID,
   119  				OutputIndex: uint32(index),
   120  			},
   121  			Asset: avax.Asset{ID: out.AssetID()},
   122  			Out:   out.Out,
   123  		}
   124  		index++
   125  
   126  		utxoBytes, err := e.Codec.Marshal(txs.CodecVersion, utxo)
   127  		if err != nil {
   128  			return fmt.Errorf("failed to marshal UTXO: %w", err)
   129  		}
   130  		utxoID := utxo.InputID()
   131  		elem := &atomic.Element{
   132  			Key:   utxoID[:],
   133  			Value: utxoBytes,
   134  		}
   135  		if out, ok := utxo.Out.(avax.Addressable); ok {
   136  			elem.Traits = out.Addresses()
   137  		}
   138  
   139  		elems[i] = elem
   140  	}
   141  	e.AtomicRequests = map[ids.ID]*atomic.Requests{
   142  		tx.DestinationChain: {
   143  			PutRequests: elems,
   144  		},
   145  	}
   146  	return nil
   147  }