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 }