package network import ( "context" "github.com/ledgerwatch/erigon-lib/gointerfaces/sentinel" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" "github.com/ledgerwatch/erigon/cl/cltypes/ssz" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/log/v3" ) type GossipReceiver interface { ReceiveGossip(ssz.Unmarshaler) } type GossipManager struct { ctx context.Context receivers map[sentinel.GossipType][]GossipReceiver sentinel sentinel.SentinelClient } func NewGossipReceiver(ctx context.Context, s sentinel.SentinelClient) *GossipManager { return &GossipManager{ sentinel: s, receivers: make(map[sentinel.GossipType][]GossipReceiver), ctx: ctx, } } func (g *GossipManager) AddReceiver(t sentinel.GossipType, receiver GossipReceiver) { if _, ok := g.receivers[t]; !ok { g.receivers[t] = make([]GossipReceiver, 0) } g.receivers[t] = append(g.receivers[t], receiver) } func (g *GossipManager) Loop() { subscription, err := g.sentinel.SubscribeGossip(g.ctx, &sentinel.EmptyMessage{}) if err != nil { return } for { data, err := subscription.Recv() if err != nil { log.Warn("[Beacon Gossip] Failure in receiving", "err", err) continue } // Depending on the type of the received data, we create an instance of a specific type that implements the ObjectSSZ interface, // then attempts to deserialize the received data into it. //If the deserialization fails, an error is logged and the loop continues to the next iteration. //If the deserialization is successful, the object is set to the deserialized value and the loop continues to the next iteration. receivers := g.receivers[data.Type] var object ssz.Unmarshaler switch data.Type { case sentinel.GossipType_BeaconBlockGossipType: object = &cltypes.SignedBeaconBlock{} if err := object.DecodeSSZWithVersion(common.CopyBytes(data.Data), int(clparams.BellatrixVersion)); err != nil { log.Debug("[Beacon Gossip] Failure in decoding block", "err", err) g.sentinel.BanPeer(g.ctx, data.Peer) continue } case sentinel.GossipType_VoluntaryExitGossipType: object = &cltypes.SignedVoluntaryExit{} if err := object.DecodeSSZWithVersion(data.Data, int(clparams.BellatrixVersion)); err != nil { log.Debug("[Beacon Gossip] Failure in decoding exit", "err", err) g.sentinel.BanPeer(g.ctx, data.Peer) continue } case sentinel.GossipType_ProposerSlashingGossipType: object = &cltypes.ProposerSlashing{} if err := object.DecodeSSZWithVersion(data.Data, int(clparams.BellatrixVersion)); err != nil { log.Debug("[Beacon Gossip] Failure in decoding proposer slashing", "err", err) g.sentinel.BanPeer(g.ctx, data.Peer) continue } case sentinel.GossipType_AttesterSlashingGossipType: object = &cltypes.AttesterSlashing{} if err := object.DecodeSSZWithVersion(data.Data, int(clparams.BellatrixVersion)); err != nil { log.Debug("[Beacon Gossip] Failure in decoding attester slashing", "err", err) g.sentinel.BanPeer(g.ctx, data.Peer) continue } case sentinel.GossipType_AggregateAndProofGossipType: object = &cltypes.SignedAggregateAndProof{} if err := object.DecodeSSZWithVersion(data.Data, int(clparams.BellatrixVersion)); err != nil { log.Debug("[Beacon Gossip] Failure in decoding proof", "err", err) g.sentinel.BanPeer(g.ctx, data.Peer) continue } } // If we received a valid object give it to our receiver if object != nil { for _, receiver := range receivers { receiver.ReceiveGossip(object) } } } }