package behaviour import ( "errors" tmsync "github.com/tendermint/tendermint/libs/sync" "github.com/tendermint/tendermint/p2p" ) // Reporter provides an interface for reactors to report the behaviour // of peers synchronously to other components. type Reporter interface { Report(behaviour PeerBehaviour) error } // SwitchReporter reports peer behaviour to an internal Switch. type SwitchReporter struct { sw *p2p.Switch } // NewSwitchReporter return a new SwitchReporter instance which wraps the Switch. func NewSwitchReporter(sw *p2p.Switch) *SwitchReporter { return &SwitchReporter{ sw: sw, } } // Report reports the behaviour of a peer to the Switch. func (spbr *SwitchReporter) Report(behaviour PeerBehaviour) error { peer := spbr.sw.Peers().Get(behaviour.peerID) if peer == nil { return errors.New("peer not found") } switch reason := behaviour.reason.(type) { case consensusVote, blockPart: spbr.sw.MarkPeerAsGood(peer) case badMessage: spbr.sw.StopPeerForError(peer, reason.explanation) case messageOutOfOrder: spbr.sw.StopPeerForError(peer, reason.explanation) default: return errors.New("unknown reason reported") } return nil } // MockReporter is a concrete implementation of the Reporter // interface used in reactor tests to ensure reactors report the correct // behaviour in manufactured scenarios. type MockReporter struct { mtx tmsync.RWMutex pb map[p2p.NodeID][]PeerBehaviour } // NewMockReporter returns a Reporter which records all reported // behaviours in memory. func NewMockReporter() *MockReporter { return &MockReporter{ pb: map[p2p.NodeID][]PeerBehaviour{}, } } // Report stores the PeerBehaviour produced by the peer identified by peerID. func (mpbr *MockReporter) Report(behaviour PeerBehaviour) error { mpbr.mtx.Lock() defer mpbr.mtx.Unlock() mpbr.pb[behaviour.peerID] = append(mpbr.pb[behaviour.peerID], behaviour) return nil } // GetBehaviours returns all behaviours reported on the peer identified by peerID. func (mpbr *MockReporter) GetBehaviours(peerID p2p.NodeID) []PeerBehaviour { mpbr.mtx.RLock() defer mpbr.mtx.RUnlock() if items, ok := mpbr.pb[peerID]; ok { result := make([]PeerBehaviour, len(items)) copy(result, items) return result } return []PeerBehaviour{} }