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  }