github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/avalanche/vertex/stateless_vertex.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package vertex 5 6 import ( 7 "errors" 8 "fmt" 9 10 "github.com/MetalBlockchain/metalgo/ids" 11 "github.com/MetalBlockchain/metalgo/utils" 12 "github.com/MetalBlockchain/metalgo/vms/components/verify" 13 ) 14 15 const ( 16 // maxNumParents is the max number of parents a vertex may have 17 maxNumParents = 128 18 19 // maxTxsPerVtx is the max number of transactions a vertex may have 20 maxTxsPerVtx = 128 21 ) 22 23 var ( 24 errBadVersion = errors.New("invalid version") 25 errBadEpoch = errors.New("invalid epoch") 26 errTooManyParentIDs = fmt.Errorf("vertex contains more than %d parentIDs", maxNumParents) 27 errNoOperations = errors.New("vertex contains no operations") 28 errTooManyTxs = fmt.Errorf("vertex contains more than %d transactions", maxTxsPerVtx) 29 errInvalidParents = errors.New("vertex contains non-sorted or duplicated parentIDs") 30 errInvalidTxs = errors.New("vertex contains non-sorted or duplicated transactions") 31 32 _ StatelessVertex = statelessVertex{} 33 ) 34 35 type StatelessVertex interface { 36 verify.Verifiable 37 ID() ids.ID 38 Bytes() []byte 39 Version() uint16 40 ChainID() ids.ID 41 StopVertex() bool 42 Height() uint64 43 Epoch() uint32 44 ParentIDs() []ids.ID 45 Txs() [][]byte 46 } 47 48 type statelessVertex struct { 49 // This wrapper exists so that the function calls aren't ambiguous 50 innerStatelessVertex 51 52 // cache the ID of this vertex 53 id ids.ID 54 55 // cache the binary format of this vertex 56 bytes []byte 57 } 58 59 func (v statelessVertex) ID() ids.ID { 60 return v.id 61 } 62 63 func (v statelessVertex) Bytes() []byte { 64 return v.bytes 65 } 66 67 func (v statelessVertex) Version() uint16 { 68 return v.innerStatelessVertex.Version 69 } 70 71 func (v statelessVertex) ChainID() ids.ID { 72 return v.innerStatelessVertex.ChainID 73 } 74 75 func (v statelessVertex) StopVertex() bool { 76 return v.innerStatelessVertex.Version == CodecVersionWithStopVtx 77 } 78 79 func (v statelessVertex) Height() uint64 { 80 return v.innerStatelessVertex.Height 81 } 82 83 func (v statelessVertex) Epoch() uint32 { 84 return v.innerStatelessVertex.Epoch 85 } 86 87 func (v statelessVertex) ParentIDs() []ids.ID { 88 return v.innerStatelessVertex.ParentIDs 89 } 90 91 func (v statelessVertex) Txs() [][]byte { 92 return v.innerStatelessVertex.Txs 93 } 94 95 type innerStatelessVertex struct { 96 Version uint16 `json:"version"` 97 ChainID ids.ID `json:"chainID" serializeV0:"true" serializeV1:"true"` 98 Height uint64 `json:"height" serializeV0:"true" serializeV1:"true"` 99 Epoch uint32 `json:"epoch" serializeV0:"true"` 100 ParentIDs []ids.ID `json:"parentIDs" serializeV0:"true" serializeV1:"true"` 101 Txs [][]byte `json:"txs" serializeV0:"true"` 102 } 103 104 func (v innerStatelessVertex) Verify() error { 105 if v.Version == CodecVersionWithStopVtx { 106 return v.verifyStopVertex() 107 } 108 return v.verify() 109 } 110 111 func (v innerStatelessVertex) verify() error { 112 switch { 113 case v.Version != CodecVersion: 114 return errBadVersion 115 case v.Epoch != 0: 116 return errBadEpoch 117 case len(v.ParentIDs) > maxNumParents: 118 return errTooManyParentIDs 119 case len(v.Txs) == 0: 120 return errNoOperations 121 case len(v.Txs) > maxTxsPerVtx: 122 return errTooManyTxs 123 case !utils.IsSortedAndUnique(v.ParentIDs): 124 return errInvalidParents 125 case !utils.IsSortedAndUniqueByHash(v.Txs): 126 return errInvalidTxs 127 default: 128 return nil 129 } 130 } 131 132 func (v innerStatelessVertex) verifyStopVertex() error { 133 switch { 134 case v.Version != CodecVersionWithStopVtx: 135 return errBadVersion 136 case v.Epoch != 0: 137 return errBadEpoch 138 case len(v.ParentIDs) > maxNumParents: 139 return errTooManyParentIDs 140 case len(v.Txs) != 0: 141 return errTooManyTxs 142 case !utils.IsSortedAndUnique(v.ParentIDs): 143 return errInvalidParents 144 default: 145 return nil 146 } 147 }