Skip to content
Snippets Groups Projects
Unverified Commit cae647a5 authored by Wolfgang Welz's avatar Wolfgang Welz Committed by GitHub
Browse files

Fix: Only connect to valid neighbors (#182)

parent 3b62158d
No related branches found
No related tags found
No related merge requests found
......@@ -3,7 +3,7 @@ package selection
import (
"time"
"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
"github.com/iotaledger/goshimmer/packages/autopeering/peer"
"github.com/iotaledger/hive.go/logger"
)
......@@ -30,10 +30,22 @@ type Config struct {
Log *logger.Logger
// These settings are optional:
DropOnUpdate bool // set true to drop all neighbors when the salt is updated
RequiredServices []service.Key // services required in order to select/be selected during autopeering
DropOnUpdate bool // set true to drop all neighbors when the salt is updated
NeighborValidator Validator // potential neighbor validator
}
// A Validator checks whether a peer is a valid neighbor
type Validator interface {
IsValid(*peer.Peer) bool
}
// The ValidatorFunc type is an adapter to allow the use of ordinary functions as neighbor validators.
// If f is a function with the appropriate signature, ValidatorFunc(f) is a Validator that calls f.
type ValidatorFunc func(p *peer.Peer) bool
// IsValid calls f(p).
func (f ValidatorFunc) IsValid(p *peer.Peer) bool { return f(p) }
// Parameters holds the parameters that can be configured.
type Parameters struct {
InboundNeighborSize int // number of inbound neighbors
......
......@@ -5,7 +5,6 @@ import (
"time"
"github.com/iotaledger/goshimmer/packages/autopeering/peer"
"github.com/iotaledger/goshimmer/packages/autopeering/peer/service"
"github.com/iotaledger/goshimmer/packages/autopeering/salt"
"github.com/iotaledger/hive.go/logger"
)
......@@ -35,8 +34,8 @@ type manager struct {
net network
getPeersToConnect func() []*peer.Peer
log *logger.Logger
dropOnUpdate bool // set true to drop all neighbors when the salt is updated
requiredServices []service.Key // services required in order to select/be selected during autopeering
dropOnUpdate bool // set true to drop all neighbors when the salt is updated
neighborValidator Validator // potential neighbor validator
inbound *Neighborhood
outbound *Neighborhood
......@@ -57,7 +56,7 @@ func newManager(net network, peersFunc func() []*peer.Peer, log *logger.Logger,
getPeersToConnect: peersFunc,
log: log,
dropOnUpdate: config.DropOnUpdate,
requiredServices: config.RequiredServices,
neighborValidator: config.NeighborValidator,
inbound: NewNeighborhood(inboundNeighborSize),
outbound: NewNeighborhood(outboundNeighborSize),
rejectionFilter: NewFilter(),
......@@ -217,9 +216,12 @@ func (m *manager) updateOutbound(resultChan chan<- peer.PeerDistance) {
// filter out current neighbors
filter := m.getConnectedFilter()
filteredList := filter.Apply(distList)
if m.neighborValidator != nil {
filter.AddCondition(m.neighborValidator.IsValid)
}
// filter out previous rejections
filteredList = m.rejectionFilter.Apply(filteredList)
filteredList := m.rejectionFilter.Apply(filter.Apply(distList))
if len(filteredList) == 0 {
return
}
......@@ -340,13 +342,10 @@ func (m *manager) isValidNeighbor(p *peer.Peer) bool {
if m.getID() == p.ID() {
return false
}
// reject if required services are missing
for _, reqService := range m.requiredServices {
if p.Services().Get(reqService) == nil {
return false
}
if m.neighborValidator == nil {
return true
}
return true
return m.neighborValidator.IsValid(p)
}
func (m *manager) triggerPeeringEvent(isOut bool, p *peer.Peer, status bool) {
......
......@@ -11,8 +11,9 @@ type Selector interface {
}
type Filter struct {
internal map[peer.ID]bool
lock sync.RWMutex
internal map[peer.ID]bool
conditions []func(*peer.Peer) bool
lock sync.RWMutex
}
func NewFilter() *Filter {
......@@ -21,29 +22,23 @@ func NewFilter() *Filter {
}
}
func (f *Filter) Apply(list []peer.PeerDistance) (filteredList []peer.PeerDistance) {
func (f *Filter) Apply(list []peer.PeerDistance) (filtered []peer.PeerDistance) {
f.lock.RLock()
defer f.lock.RUnlock()
for _, p := range list {
if !f.internal[p.Remote.ID()] {
filteredList = append(filteredList, p)
}
}
return filteredList
}
func (f *Filter) PushBack(list []peer.PeerDistance) (filteredList []peer.PeerDistance) {
var head, tail []peer.PeerDistance
f.lock.RLock()
defer f.lock.RUnlock()
list:
for _, p := range list {
if f.internal[p.Remote.ID()] {
tail = append(tail, p)
} else {
head = append(head, p)
if _, contains := f.internal[p.Remote.ID()]; contains {
continue
}
for _, c := range f.conditions {
if !c(p.Remote) {
continue list
}
}
filtered = append(filtered, p)
}
return append(head, tail...)
return
}
func (f *Filter) AddPeers(n []*peer.Peer) {
......@@ -66,6 +61,10 @@ func (f *Filter) RemovePeer(peer peer.ID) {
f.lock.Unlock()
}
func (f *Filter) AddCondition(c func(p *peer.Peer) bool) {
f.conditions = append(f.conditions, c)
}
func (f *Filter) Clean() {
f.lock.Lock()
f.internal = make(map[peer.ID]bool)
......
......@@ -48,12 +48,32 @@ func configureAP() {
// enable peer selection only when gossip is enabled
if !node.IsSkipped(gossip.PLUGIN) {
Selection = selection.New(local.GetInstance(), Discovery, selection.Config{
Log: log.Named("sel"),
RequiredServices: []service.Key{service.GossipKey},
Log: log.Named("sel"),
NeighborValidator: selection.ValidatorFunc(isValidNeighbor),
})
}
}
// isValidNeighbor checks whether a peer is a valid neighbor.
func isValidNeighbor(p *peer.Peer) bool {
// gossip must be supported
gossipAddr := p.Services().Get(service.GossipKey)
if gossipAddr == nil {
return false
}
// the host for the gossip and peering service must be identical
gossipHost, _, err := net.SplitHostPort(gossipAddr.String())
if err != nil {
return false
}
peeringAddr := p.Services().Get(service.PeeringKey)
peeringHost, _, err := net.SplitHostPort(peeringAddr.String())
if err != nil {
return false
}
return gossipHost == peeringHost
}
func start(shutdownSignal <-chan struct{}) {
defer log.Info("Stopping " + name + " ... done")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment