github.com/ava-labs/avalanchego@v1.11.11/vms/components/avax/utxo_id.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package avax
     5  
     6  import (
     7  	"bytes"
     8  	"cmp"
     9  	"errors"
    10  	"fmt"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/ava-labs/avalanchego/ids"
    15  	"github.com/ava-labs/avalanchego/utils"
    16  	"github.com/ava-labs/avalanchego/vms/components/verify"
    17  )
    18  
    19  var (
    20  	errNilUTXOID                 = errors.New("nil utxo ID is not valid")
    21  	errMalformedUTXOIDString     = errors.New("unexpected number of tokens in string")
    22  	errFailedDecodingUTXOIDTxID  = errors.New("failed decoding UTXOID TxID")
    23  	errFailedDecodingUTXOIDIndex = errors.New("failed decoding UTXOID index")
    24  
    25  	_ verify.Verifiable       = (*UTXOID)(nil)
    26  	_ utils.Sortable[*UTXOID] = (*UTXOID)(nil)
    27  )
    28  
    29  type UTXOID struct {
    30  	// Serialized:
    31  	TxID        ids.ID `serialize:"true" json:"txID"`
    32  	OutputIndex uint32 `serialize:"true" json:"outputIndex"`
    33  
    34  	// Symbol is false if the UTXO should be part of the DB
    35  	Symbol bool `json:"-"`
    36  	// id is the unique ID of a UTXO, it is calculated from TxID and OutputIndex
    37  	id ids.ID
    38  }
    39  
    40  // InputSource returns the source of the UTXO that this input is spending
    41  func (utxo *UTXOID) InputSource() (ids.ID, uint32) {
    42  	return utxo.TxID, utxo.OutputIndex
    43  }
    44  
    45  // InputID returns a unique ID of the UTXO that this input is spending
    46  func (utxo *UTXOID) InputID() ids.ID {
    47  	if utxo.id == ids.Empty {
    48  		utxo.id = utxo.TxID.Prefix(uint64(utxo.OutputIndex))
    49  	}
    50  	return utxo.id
    51  }
    52  
    53  // Symbolic returns if this is the ID of a UTXO in the DB, or if it is a
    54  // symbolic input
    55  func (utxo *UTXOID) Symbolic() bool {
    56  	return utxo.Symbol
    57  }
    58  
    59  func (utxo *UTXOID) String() string {
    60  	return fmt.Sprintf("%s:%d", utxo.TxID, utxo.OutputIndex)
    61  }
    62  
    63  // UTXOIDFromString attempts to parse a string into a UTXOID
    64  func UTXOIDFromString(s string) (*UTXOID, error) {
    65  	ss := strings.Split(s, ":")
    66  	if len(ss) != 2 {
    67  		return nil, errMalformedUTXOIDString
    68  	}
    69  
    70  	txID, err := ids.FromString(ss[0])
    71  	if err != nil {
    72  		return nil, fmt.Errorf("%w: %w", errFailedDecodingUTXOIDTxID, err)
    73  	}
    74  
    75  	idx, err := strconv.ParseUint(ss[1], 10, 32)
    76  	if err != nil {
    77  		return nil, fmt.Errorf("%w: %w", errFailedDecodingUTXOIDIndex, err)
    78  	}
    79  
    80  	return &UTXOID{
    81  		TxID:        txID,
    82  		OutputIndex: uint32(idx),
    83  	}, nil
    84  }
    85  
    86  func (utxo *UTXOID) Verify() error {
    87  	switch {
    88  	case utxo == nil:
    89  		return errNilUTXOID
    90  	default:
    91  		return nil
    92  	}
    93  }
    94  
    95  func (utxo *UTXOID) Compare(other *UTXOID) int {
    96  	utxoID, utxoIndex := utxo.InputSource()
    97  	otherID, otherIndex := other.InputSource()
    98  	if txIDComp := bytes.Compare(utxoID[:], otherID[:]); txIDComp != 0 {
    99  		return txIDComp
   100  	}
   101  	return cmp.Compare(utxoIndex, otherIndex)
   102  }