github.com/MetalBlockchain/metalgo@v1.11.9/network/p2p/gossip/handler.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package gossip 5 6 import ( 7 "context" 8 "time" 9 10 "go.uber.org/zap" 11 12 "github.com/MetalBlockchain/metalgo/ids" 13 "github.com/MetalBlockchain/metalgo/network/p2p" 14 "github.com/MetalBlockchain/metalgo/utils/bloom" 15 "github.com/MetalBlockchain/metalgo/utils/logging" 16 ) 17 18 var _ p2p.Handler = (*Handler[*testTx])(nil) 19 20 func NewHandler[T Gossipable]( 21 log logging.Logger, 22 marshaller Marshaller[T], 23 set Set[T], 24 metrics Metrics, 25 targetResponseSize int, 26 ) *Handler[T] { 27 return &Handler[T]{ 28 Handler: p2p.NoOpHandler{}, 29 log: log, 30 marshaller: marshaller, 31 set: set, 32 metrics: metrics, 33 targetResponseSize: targetResponseSize, 34 } 35 } 36 37 type Handler[T Gossipable] struct { 38 p2p.Handler 39 marshaller Marshaller[T] 40 log logging.Logger 41 set Set[T] 42 metrics Metrics 43 targetResponseSize int 44 } 45 46 func (h Handler[T]) AppRequest(_ context.Context, _ ids.NodeID, _ time.Time, requestBytes []byte) ([]byte, error) { 47 filter, salt, err := ParseAppRequest(requestBytes) 48 if err != nil { 49 return nil, err 50 } 51 52 responseSize := 0 53 gossipBytes := make([][]byte, 0) 54 h.set.Iterate(func(gossipable T) bool { 55 gossipID := gossipable.GossipID() 56 57 // filter out what the requesting peer already knows about 58 if bloom.Contains(filter, gossipID[:], salt[:]) { 59 return true 60 } 61 62 var bytes []byte 63 bytes, err = h.marshaller.MarshalGossip(gossipable) 64 if err != nil { 65 return false 66 } 67 68 // check that this doesn't exceed our maximum configured target response 69 // size 70 gossipBytes = append(gossipBytes, bytes) 71 responseSize += len(bytes) 72 73 return responseSize <= h.targetResponseSize 74 }) 75 if err != nil { 76 return nil, err 77 } 78 79 if err := h.metrics.observeMessage(sentPullLabels, len(gossipBytes), responseSize); err != nil { 80 return nil, err 81 } 82 83 return MarshalAppResponse(gossipBytes) 84 } 85 86 func (h Handler[_]) AppGossip(_ context.Context, nodeID ids.NodeID, gossipBytes []byte) { 87 gossip, err := ParseAppGossip(gossipBytes) 88 if err != nil { 89 h.log.Debug("failed to unmarshal gossip", zap.Error(err)) 90 return 91 } 92 93 receivedBytes := 0 94 for _, bytes := range gossip { 95 receivedBytes += len(bytes) 96 gossipable, err := h.marshaller.UnmarshalGossip(bytes) 97 if err != nil { 98 h.log.Debug("failed to unmarshal gossip", 99 zap.Stringer("nodeID", nodeID), 100 zap.Error(err), 101 ) 102 continue 103 } 104 105 if err := h.set.Add(gossipable); err != nil { 106 h.log.Debug( 107 "failed to add gossip to the known set", 108 zap.Stringer("nodeID", nodeID), 109 zap.Stringer("id", gossipable.GossipID()), 110 zap.Error(err), 111 ) 112 } 113 } 114 115 if err := h.metrics.observeMessage(receivedPushLabels, len(gossip), receivedBytes); err != nil { 116 h.log.Error("failed to update metrics", 117 zap.Error(err), 118 ) 119 } 120 }