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 }