You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.5 KiB

p2p: PeerBehaviour implementation (#3539) (#3552) * p2p: initial implementation of peer behaviour * [p2p] re-use newMockPeer * p2p: add inline docs for peer_behaviour interface * [p2p] Align PeerBehaviour interface (#3558) * [p2p] make switchedPeerHebaviour private * [p2p] make storePeerHebaviour private * [p2p] Add CHANGELOG_PENDING entry for PeerBehaviour * [p2p] Adjustment naming for PeerBehaviour * [p2p] Add coarse lock around storedPeerBehaviour * [p2p]: Fix non-pointer methods in storedPeerBehaviour + Structs with embeded locks must specify all methods with pointer receivers to avoid creating a copy of the embeded lock. * [p2p] Thorough refactoring based on comments in #3552 + Decouple PeerBehaviour interface from Peer by parametrizing methods with `p2p.ID` instead of `p2p.Peer` + Setter methods wrapped in a write lock + Getter methods wrapped in a read lock + Getter methods on storedPeerBehaviour now take a `p2p.ID` + Getter methods return a copy of underlying stored behaviours + Add doc strings to public types and methods * [p2p] make structs public * [p2p] Test empty StoredPeerBehaviour * [p2p] typo fix * [p2p] add TestStoredPeerBehaviourConcurrency + Add a test which uses StoredPeerBehaviour in multiple goroutines to ensure thread-safety. * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour_test.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * [p2p] field ordering convention * p2p: peer behaviour refactor + Change naming of reporting behaviour to `Report` + Remove the responsibility of distinguishing between the categories of good and bad behaviour and instead focus on reporting behaviour. * p2p: rename PeerReporter -> PeerBehaviourReporter
6 years ago
  1. package p2p
  2. import (
  3. "errors"
  4. "sync"
  5. )
  6. // PeerBehaviour are types of reportable behaviours about peers.
  7. type PeerBehaviour int
  8. const (
  9. PeerBehaviourBadMessage = iota
  10. PeerBehaviourMessageOutOfOrder
  11. PeerBehaviourVote
  12. PeerBehaviourBlockPart
  13. )
  14. // PeerBehaviourReporter provides an interface for reactors to report the behaviour
  15. // of peers synchronously to other components.
  16. type PeerBehaviourReporter interface {
  17. Report(peerID ID, behaviour PeerBehaviour) error
  18. }
  19. // SwitchPeerBehaviouReporter reports peer behaviour to an internal Switch
  20. type SwitchPeerBehaviourReporter struct {
  21. sw *Switch
  22. }
  23. // Return a new SwitchPeerBehaviourReporter instance which wraps the Switch.
  24. func NewSwitchPeerBehaviourReporter(sw *Switch) *SwitchPeerBehaviourReporter {
  25. return &SwitchPeerBehaviourReporter{
  26. sw: sw,
  27. }
  28. }
  29. // Report reports the behaviour of a peer to the Switch
  30. func (spbr *SwitchPeerBehaviourReporter) Report(peerID ID, behaviour PeerBehaviour) error {
  31. peer := spbr.sw.Peers().Get(peerID)
  32. if peer == nil {
  33. return errors.New("Peer not found")
  34. }
  35. switch behaviour {
  36. case PeerBehaviourVote, PeerBehaviourBlockPart:
  37. spbr.sw.MarkPeerAsGood(peer)
  38. case PeerBehaviourBadMessage:
  39. spbr.sw.StopPeerForError(peer, "Bad message")
  40. case PeerBehaviourMessageOutOfOrder:
  41. spbr.sw.StopPeerForError(peer, "Message out of order")
  42. default:
  43. return errors.New("Unknown behaviour")
  44. }
  45. return nil
  46. }
  47. // MockPeerBehaviourReporter serves a mock concrete implementation of the
  48. // PeerBehaviourReporter interface used in reactor tests to ensure reactors
  49. // report the correct behaviour in manufactured scenarios.
  50. type MockPeerBehaviourReporter struct {
  51. mtx sync.RWMutex
  52. pb map[ID][]PeerBehaviour
  53. }
  54. // NewMockPeerBehaviourReporter returns a PeerBehaviourReporter which records all reported
  55. // behaviours in memory.
  56. func NewMockPeerBehaviourReporter() *MockPeerBehaviourReporter {
  57. return &MockPeerBehaviourReporter{
  58. pb: map[ID][]PeerBehaviour{},
  59. }
  60. }
  61. // Report stores the PeerBehaviour produced by the peer identified by peerID.
  62. func (mpbr *MockPeerBehaviourReporter) Report(peerID ID, behaviour PeerBehaviour) {
  63. mpbr.mtx.Lock()
  64. defer mpbr.mtx.Unlock()
  65. mpbr.pb[peerID] = append(mpbr.pb[peerID], behaviour)
  66. }
  67. // GetBehaviours returns all behaviours reported on the peer identified by peerID.
  68. func (mpbr *MockPeerBehaviourReporter) GetBehaviours(peerID ID) []PeerBehaviour {
  69. mpbr.mtx.RLock()
  70. defer mpbr.mtx.RUnlock()
  71. if items, ok := mpbr.pb[peerID]; ok {
  72. result := make([]PeerBehaviour, len(items))
  73. copy(result, items)
  74. return result
  75. } else {
  76. return []PeerBehaviour{}
  77. }
  78. }