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  }