github.com/MetalBlockchain/metalgo@v1.11.9/vms/avm/txs/initial_state.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  	"bytes"
     8  	"cmp"
     9  	"errors"
    10  	"sort"
    11  
    12  	"github.com/MetalBlockchain/metalgo/codec"
    13  	"github.com/MetalBlockchain/metalgo/ids"
    14  	"github.com/MetalBlockchain/metalgo/snow"
    15  	"github.com/MetalBlockchain/metalgo/utils"
    16  	"github.com/MetalBlockchain/metalgo/vms/components/verify"
    17  )
    18  
    19  var (
    20  	ErrNilInitialState  = errors.New("nil initial state is not valid")
    21  	ErrNilFxOutput      = errors.New("nil feature extension output is not valid")
    22  	ErrOutputsNotSorted = errors.New("outputs not sorted")
    23  	ErrUnknownFx        = errors.New("unknown feature extension")
    24  
    25  	_ utils.Sortable[*InitialState] = (*InitialState)(nil)
    26  )
    27  
    28  type InitialState struct {
    29  	FxIndex uint32         `serialize:"true"  json:"fxIndex"`
    30  	FxID    ids.ID         `serialize:"false" json:"fxID"`
    31  	Outs    []verify.State `serialize:"true"  json:"outputs"`
    32  }
    33  
    34  func (is *InitialState) InitCtx(ctx *snow.Context) {
    35  	for _, out := range is.Outs {
    36  		out.InitCtx(ctx)
    37  	}
    38  }
    39  
    40  func (is *InitialState) Verify(c codec.Manager, numFxs int) error {
    41  	switch {
    42  	case is == nil:
    43  		return ErrNilInitialState
    44  	case is.FxIndex >= uint32(numFxs):
    45  		return ErrUnknownFx
    46  	}
    47  
    48  	for _, out := range is.Outs {
    49  		if out == nil {
    50  			return ErrNilFxOutput
    51  		}
    52  		if err := out.Verify(); err != nil {
    53  			return err
    54  		}
    55  	}
    56  	if !isSortedState(is.Outs, c) {
    57  		return ErrOutputsNotSorted
    58  	}
    59  
    60  	return nil
    61  }
    62  
    63  func (is *InitialState) Compare(other *InitialState) int {
    64  	return cmp.Compare(is.FxIndex, other.FxIndex)
    65  }
    66  
    67  func (is *InitialState) Sort(c codec.Manager) {
    68  	sortState(is.Outs, c)
    69  }
    70  
    71  type innerSortState struct {
    72  	vers  []verify.State
    73  	codec codec.Manager
    74  }
    75  
    76  func (vers *innerSortState) Less(i, j int) bool {
    77  	iVer := vers.vers[i]
    78  	jVer := vers.vers[j]
    79  
    80  	iBytes, err := vers.codec.Marshal(CodecVersion, &iVer)
    81  	if err != nil {
    82  		return false
    83  	}
    84  	jBytes, err := vers.codec.Marshal(CodecVersion, &jVer)
    85  	if err != nil {
    86  		return false
    87  	}
    88  	return bytes.Compare(iBytes, jBytes) == -1
    89  }
    90  
    91  func (vers *innerSortState) Len() int {
    92  	return len(vers.vers)
    93  }
    94  
    95  func (vers *innerSortState) Swap(i, j int) {
    96  	v := vers.vers
    97  	v[j], v[i] = v[i], v[j]
    98  }
    99  
   100  func sortState(vers []verify.State, c codec.Manager) {
   101  	sort.Sort(&innerSortState{vers: vers, codec: c})
   102  }
   103  
   104  func isSortedState(vers []verify.State, c codec.Manager) bool {
   105  	return sort.IsSorted(&innerSortState{vers: vers, codec: c})
   106  }