github.com/MetalBlockchain/metalgo@v1.11.9/snow/engine/avalanche/getter/getter.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package getter 5 6 import ( 7 "context" 8 "time" 9 10 "github.com/prometheus/client_golang/prometheus" 11 "go.uber.org/zap" 12 13 "github.com/MetalBlockchain/metalgo/ids" 14 "github.com/MetalBlockchain/metalgo/message" 15 "github.com/MetalBlockchain/metalgo/snow/choices" 16 "github.com/MetalBlockchain/metalgo/snow/consensus/avalanche" 17 "github.com/MetalBlockchain/metalgo/snow/engine/avalanche/vertex" 18 "github.com/MetalBlockchain/metalgo/snow/engine/common" 19 "github.com/MetalBlockchain/metalgo/utils/constants" 20 "github.com/MetalBlockchain/metalgo/utils/logging" 21 "github.com/MetalBlockchain/metalgo/utils/metric" 22 "github.com/MetalBlockchain/metalgo/utils/set" 23 "github.com/MetalBlockchain/metalgo/utils/wrappers" 24 ) 25 26 // Get requests are always served, regardless node state (bootstrapping or normal operations). 27 var _ common.AllGetsServer = (*getter)(nil) 28 29 func New( 30 storage vertex.Storage, 31 sender common.Sender, 32 log logging.Logger, 33 maxTimeGetAncestors time.Duration, 34 maxContainersGetAncestors int, 35 reg prometheus.Registerer, 36 ) (common.AllGetsServer, error) { 37 gh := &getter{ 38 storage: storage, 39 sender: sender, 40 log: log, 41 maxTimeGetAncestors: maxTimeGetAncestors, 42 maxContainersGetAncestors: maxContainersGetAncestors, 43 } 44 45 var err error 46 gh.getAncestorsVtxs, err = metric.NewAverager( 47 "bs_get_ancestors_vtxs", 48 "vertices fetched in a call to GetAncestors", 49 reg, 50 ) 51 return gh, err 52 } 53 54 type getter struct { 55 storage vertex.Storage 56 sender common.Sender 57 log logging.Logger 58 maxTimeGetAncestors time.Duration 59 maxContainersGetAncestors int 60 61 getAncestorsVtxs metric.Averager 62 } 63 64 func (gh *getter) GetStateSummaryFrontier(_ context.Context, nodeID ids.NodeID, requestID uint32) error { 65 gh.log.Debug("dropping request", 66 zap.String("reason", "unhandled by this gear"), 67 zap.Stringer("messageOp", message.GetStateSummaryFrontierOp), 68 zap.Stringer("nodeID", nodeID), 69 zap.Uint32("requestID", requestID), 70 ) 71 return nil 72 } 73 74 func (gh *getter) GetAcceptedStateSummary(_ context.Context, nodeID ids.NodeID, requestID uint32, _ set.Set[uint64]) error { 75 gh.log.Debug("dropping request", 76 zap.String("reason", "unhandled by this gear"), 77 zap.Stringer("messageOp", message.GetAcceptedStateSummaryOp), 78 zap.Stringer("nodeID", nodeID), 79 zap.Uint32("requestID", requestID), 80 ) 81 return nil 82 } 83 84 func (gh *getter) GetAcceptedFrontier(_ context.Context, nodeID ids.NodeID, requestID uint32) error { 85 gh.log.Debug("dropping request", 86 zap.String("reason", "unhandled by this gear"), 87 zap.Stringer("messageOp", message.GetAcceptedFrontierOp), 88 zap.Stringer("nodeID", nodeID), 89 zap.Uint32("requestID", requestID), 90 ) 91 return nil 92 } 93 94 func (gh *getter) GetAccepted(_ context.Context, nodeID ids.NodeID, requestID uint32, _ set.Set[ids.ID]) error { 95 gh.log.Debug("dropping request", 96 zap.String("reason", "unhandled by this gear"), 97 zap.Stringer("messageOp", message.GetAcceptedOp), 98 zap.Stringer("nodeID", nodeID), 99 zap.Uint32("requestID", requestID), 100 ) 101 return nil 102 } 103 104 func (gh *getter) GetAncestors(ctx context.Context, nodeID ids.NodeID, requestID uint32, vtxID ids.ID) error { 105 startTime := time.Now() 106 gh.log.Verbo("called GetAncestors", 107 zap.Stringer("nodeID", nodeID), 108 zap.Uint32("requestID", requestID), 109 zap.Stringer("vtxID", vtxID), 110 ) 111 vertex, err := gh.storage.GetVtx(ctx, vtxID) 112 if err != nil || vertex.Status() == choices.Unknown { 113 gh.log.Verbo("dropping getAncestors") 114 return nil // Don't have the requested vertex. Drop message. 115 } 116 117 queue := make([]avalanche.Vertex, 1, gh.maxContainersGetAncestors) // for BFS 118 queue[0] = vertex 119 ancestorsBytesLen := 0 // length, in bytes, of vertex and its ancestors 120 ancestorsBytes := make([][]byte, 0, gh.maxContainersGetAncestors) // vertex and its ancestors in BFS order 121 visited := set.Of(vertex.ID()) // IDs of vertices that have been in queue before 122 123 for len(ancestorsBytes) < gh.maxContainersGetAncestors && len(queue) > 0 && time.Since(startTime) < gh.maxTimeGetAncestors { 124 var vtx avalanche.Vertex 125 vtx, queue = queue[0], queue[1:] // pop 126 vtxBytes := vtx.Bytes() 127 // Ensure response size isn't too large. Include wrappers.IntLen because the size of the message 128 // is included with each container, and the size is repr. by an int. 129 newLen := wrappers.IntLen + ancestorsBytesLen + len(vtxBytes) 130 if newLen > constants.MaxContainersLen { 131 // reached maximum response size 132 break 133 } 134 ancestorsBytes = append(ancestorsBytes, vtxBytes) 135 ancestorsBytesLen = newLen 136 parents, err := vtx.Parents() 137 if err != nil { 138 return err 139 } 140 for _, parent := range parents { 141 if parent.Status() == choices.Unknown { // Don't have this vertex;ignore 142 continue 143 } 144 if parentID := parent.ID(); !visited.Contains(parentID) { // If already visited, ignore 145 queue = append(queue, parent) 146 visited.Add(parentID) 147 } 148 } 149 } 150 151 gh.getAncestorsVtxs.Observe(float64(len(ancestorsBytes))) 152 gh.sender.SendAncestors(ctx, nodeID, requestID, ancestorsBytes) 153 return nil 154 } 155 156 func (gh *getter) Get(_ context.Context, nodeID ids.NodeID, requestID uint32, _ ids.ID) error { 157 gh.log.Debug("dropping request", 158 zap.String("reason", "unhandled by this gear"), 159 zap.Stringer("messageOp", message.GetOp), 160 zap.Stringer("nodeID", nodeID), 161 zap.Uint32("requestID", requestID), 162 ) 163 return nil 164 }