Commit 9f10c3e5 authored by Adrian Sutton's avatar Adrian Sutton

op-node: Use an adapter to reduce the number of dependencies passed to PeerMonitor

parent dcb24286
package monitor
import (
"fmt"
"time"
"github.com/ethereum-optimism/optimism/op-node/p2p/store"
"github.com/libp2p/go-libp2p/core/connmgr"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
)
// PeerManagerAdapter implements the PeerManager interface by delegating to a variety of different p2p components
type PeerManagerAdapter struct {
n network.Network
connMgr connmgr.ConnManager
scores store.ScoreDatastore
// TODO: something to do banning but its not merged yet...
}
func NewPeerManagerAdapter(n network.Network, connMgr connmgr.ConnManager, scores store.ScoreDatastore) *PeerManagerAdapter {
return &PeerManagerAdapter{
n: n,
connMgr: connMgr,
scores: scores,
}
}
func (p *PeerManagerAdapter) Peers() []peer.ID {
return p.n.Peers()
}
func (p *PeerManagerAdapter) GetPeerScore(id peer.ID) (float64, error) {
scores, err := p.scores.GetPeerScores(id)
if err != nil {
return 0, err
}
return scores.Gossip.Total, nil
}
func (p *PeerManagerAdapter) IsProtected(id peer.ID) bool {
if p.connMgr == nil {
return false
}
// TODO: Need a constant for the tag somewhere
return p.connMgr.IsProtected(id, "static")
}
func (p *PeerManagerAdapter) ClosePeer(id peer.ID) error {
return p.n.ClosePeer(id)
}
func (p *PeerManagerAdapter) BanPeer(id peer.ID, banDuration time.Time) error {
//TODO implement me
return fmt.Errorf("peer banning not implemented")
}
var _ PeerManager = (*PeerManagerAdapter)(nil)
// Code generated by mockery v2.28.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// ConnectedPeers is an autogenerated mock type for the ConnectedPeers type
type ConnectedPeers struct {
mock.Mock
}
type ConnectedPeers_Expecter struct {
mock *mock.Mock
}
func (_m *ConnectedPeers) EXPECT() *ConnectedPeers_Expecter {
return &ConnectedPeers_Expecter{mock: &_m.Mock}
}
// ClosePeer provides a mock function with given fields: _a0
func (_m *ConnectedPeers) ClosePeer(_a0 peer.ID) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(peer.ID) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// ConnectedPeers_ClosePeer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClosePeer'
type ConnectedPeers_ClosePeer_Call struct {
*mock.Call
}
// ClosePeer is a helper method to define mock.On call
// - _a0 peer.ID
func (_e *ConnectedPeers_Expecter) ClosePeer(_a0 interface{}) *ConnectedPeers_ClosePeer_Call {
return &ConnectedPeers_ClosePeer_Call{Call: _e.mock.On("ClosePeer", _a0)}
}
func (_c *ConnectedPeers_ClosePeer_Call) Run(run func(_a0 peer.ID)) *ConnectedPeers_ClosePeer_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *ConnectedPeers_ClosePeer_Call) Return(_a0 error) *ConnectedPeers_ClosePeer_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *ConnectedPeers_ClosePeer_Call) RunAndReturn(run func(peer.ID) error) *ConnectedPeers_ClosePeer_Call {
_c.Call.Return(run)
return _c
}
// Peers provides a mock function with given fields:
func (_m *ConnectedPeers) Peers() []peer.ID {
ret := _m.Called()
var r0 []peer.ID
if rf, ok := ret.Get(0).(func() []peer.ID); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]peer.ID)
}
}
return r0
}
// ConnectedPeers_Peers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Peers'
type ConnectedPeers_Peers_Call struct {
*mock.Call
}
// Peers is a helper method to define mock.On call
func (_e *ConnectedPeers_Expecter) Peers() *ConnectedPeers_Peers_Call {
return &ConnectedPeers_Peers_Call{Call: _e.mock.On("Peers")}
}
func (_c *ConnectedPeers_Peers_Call) Run(run func()) *ConnectedPeers_Peers_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *ConnectedPeers_Peers_Call) Return(_a0 []peer.ID) *ConnectedPeers_Peers_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *ConnectedPeers_Peers_Call) RunAndReturn(run func() []peer.ID) *ConnectedPeers_Peers_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewConnectedPeers interface {
mock.TestingT
Cleanup(func())
}
// NewConnectedPeers creates a new instance of ConnectedPeers. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewConnectedPeers(t mockConstructorTestingTNewConnectedPeers) *ConnectedPeers {
mock := &ConnectedPeers{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// Code generated by mockery v2.28.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
time "time"
)
// PeerBlocker is an autogenerated mock type for the PeerBlocker type
type PeerBlocker struct {
mock.Mock
}
type PeerBlocker_Expecter struct {
mock *mock.Mock
}
func (_m *PeerBlocker) EXPECT() *PeerBlocker_Expecter {
return &PeerBlocker_Expecter{mock: &_m.Mock}
}
// BanPeer provides a mock function with given fields: _a0, _a1
func (_m *PeerBlocker) BanPeer(_a0 peer.ID, _a1 time.Time) error {
ret := _m.Called(_a0, _a1)
var r0 error
if rf, ok := ret.Get(0).(func(peer.ID, time.Time) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
}
return r0
}
// PeerBlocker_BanPeer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BanPeer'
type PeerBlocker_BanPeer_Call struct {
*mock.Call
}
// BanPeer is a helper method to define mock.On call
// - _a0 peer.ID
// - _a1 time.Time
func (_e *PeerBlocker_Expecter) BanPeer(_a0 interface{}, _a1 interface{}) *PeerBlocker_BanPeer_Call {
return &PeerBlocker_BanPeer_Call{Call: _e.mock.On("BanPeer", _a0, _a1)}
}
func (_c *PeerBlocker_BanPeer_Call) Run(run func(_a0 peer.ID, _a1 time.Time)) *PeerBlocker_BanPeer_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID), args[1].(time.Time))
})
return _c
}
func (_c *PeerBlocker_BanPeer_Call) Return(_a0 error) *PeerBlocker_BanPeer_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerBlocker_BanPeer_Call) RunAndReturn(run func(peer.ID, time.Time) error) *PeerBlocker_BanPeer_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewPeerBlocker interface {
mock.TestingT
Cleanup(func())
}
// NewPeerBlocker creates a new instance of PeerBlocker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewPeerBlocker(t mockConstructorTestingTNewPeerBlocker) *PeerBlocker {
mock := &PeerBlocker{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// Code generated by mockery v2.28.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
time "time"
)
// PeerManager is an autogenerated mock type for the PeerManager type
type PeerManager struct {
mock.Mock
}
type PeerManager_Expecter struct {
mock *mock.Mock
}
func (_m *PeerManager) EXPECT() *PeerManager_Expecter {
return &PeerManager_Expecter{mock: &_m.Mock}
}
// BanPeer provides a mock function with given fields: _a0, _a1
func (_m *PeerManager) BanPeer(_a0 peer.ID, _a1 time.Time) error {
ret := _m.Called(_a0, _a1)
var r0 error
if rf, ok := ret.Get(0).(func(peer.ID, time.Time) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
}
return r0
}
// PeerManager_BanPeer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BanPeer'
type PeerManager_BanPeer_Call struct {
*mock.Call
}
// BanPeer is a helper method to define mock.On call
// - _a0 peer.ID
// - _a1 time.Time
func (_e *PeerManager_Expecter) BanPeer(_a0 interface{}, _a1 interface{}) *PeerManager_BanPeer_Call {
return &PeerManager_BanPeer_Call{Call: _e.mock.On("BanPeer", _a0, _a1)}
}
func (_c *PeerManager_BanPeer_Call) Run(run func(_a0 peer.ID, _a1 time.Time)) *PeerManager_BanPeer_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID), args[1].(time.Time))
})
return _c
}
func (_c *PeerManager_BanPeer_Call) Return(_a0 error) *PeerManager_BanPeer_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerManager_BanPeer_Call) RunAndReturn(run func(peer.ID, time.Time) error) *PeerManager_BanPeer_Call {
_c.Call.Return(run)
return _c
}
// ClosePeer provides a mock function with given fields: _a0
func (_m *PeerManager) ClosePeer(_a0 peer.ID) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(peer.ID) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// PeerManager_ClosePeer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClosePeer'
type PeerManager_ClosePeer_Call struct {
*mock.Call
}
// ClosePeer is a helper method to define mock.On call
// - _a0 peer.ID
func (_e *PeerManager_Expecter) ClosePeer(_a0 interface{}) *PeerManager_ClosePeer_Call {
return &PeerManager_ClosePeer_Call{Call: _e.mock.On("ClosePeer", _a0)}
}
func (_c *PeerManager_ClosePeer_Call) Run(run func(_a0 peer.ID)) *PeerManager_ClosePeer_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *PeerManager_ClosePeer_Call) Return(_a0 error) *PeerManager_ClosePeer_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerManager_ClosePeer_Call) RunAndReturn(run func(peer.ID) error) *PeerManager_ClosePeer_Call {
_c.Call.Return(run)
return _c
}
// GetPeerScore provides a mock function with given fields: id
func (_m *PeerManager) GetPeerScore(id peer.ID) (float64, error) {
ret := _m.Called(id)
var r0 float64
var r1 error
if rf, ok := ret.Get(0).(func(peer.ID) (float64, error)); ok {
return rf(id)
}
if rf, ok := ret.Get(0).(func(peer.ID) float64); ok {
r0 = rf(id)
} else {
r0 = ret.Get(0).(float64)
}
if rf, ok := ret.Get(1).(func(peer.ID) error); ok {
r1 = rf(id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// PeerManager_GetPeerScore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPeerScore'
type PeerManager_GetPeerScore_Call struct {
*mock.Call
}
// GetPeerScore is a helper method to define mock.On call
// - id peer.ID
func (_e *PeerManager_Expecter) GetPeerScore(id interface{}) *PeerManager_GetPeerScore_Call {
return &PeerManager_GetPeerScore_Call{Call: _e.mock.On("GetPeerScore", id)}
}
func (_c *PeerManager_GetPeerScore_Call) Run(run func(id peer.ID)) *PeerManager_GetPeerScore_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *PeerManager_GetPeerScore_Call) Return(_a0 float64, _a1 error) *PeerManager_GetPeerScore_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *PeerManager_GetPeerScore_Call) RunAndReturn(run func(peer.ID) (float64, error)) *PeerManager_GetPeerScore_Call {
_c.Call.Return(run)
return _c
}
// IsProtected provides a mock function with given fields: _a0
func (_m *PeerManager) IsProtected(_a0 peer.ID) bool {
ret := _m.Called(_a0)
var r0 bool
if rf, ok := ret.Get(0).(func(peer.ID) bool); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// PeerManager_IsProtected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsProtected'
type PeerManager_IsProtected_Call struct {
*mock.Call
}
// IsProtected is a helper method to define mock.On call
// - _a0 peer.ID
func (_e *PeerManager_Expecter) IsProtected(_a0 interface{}) *PeerManager_IsProtected_Call {
return &PeerManager_IsProtected_Call{Call: _e.mock.On("IsProtected", _a0)}
}
func (_c *PeerManager_IsProtected_Call) Run(run func(_a0 peer.ID)) *PeerManager_IsProtected_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *PeerManager_IsProtected_Call) Return(_a0 bool) *PeerManager_IsProtected_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerManager_IsProtected_Call) RunAndReturn(run func(peer.ID) bool) *PeerManager_IsProtected_Call {
_c.Call.Return(run)
return _c
}
// Peers provides a mock function with given fields:
func (_m *PeerManager) Peers() []peer.ID {
ret := _m.Called()
var r0 []peer.ID
if rf, ok := ret.Get(0).(func() []peer.ID); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]peer.ID)
}
}
return r0
}
// PeerManager_Peers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Peers'
type PeerManager_Peers_Call struct {
*mock.Call
}
// Peers is a helper method to define mock.On call
func (_e *PeerManager_Expecter) Peers() *PeerManager_Peers_Call {
return &PeerManager_Peers_Call{Call: _e.mock.On("Peers")}
}
func (_c *PeerManager_Peers_Call) Run(run func()) *PeerManager_Peers_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *PeerManager_Peers_Call) Return(_a0 []peer.ID) *PeerManager_Peers_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerManager_Peers_Call) RunAndReturn(run func() []peer.ID) *PeerManager_Peers_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewPeerManager interface {
mock.TestingT
Cleanup(func())
}
// NewPeerManager creates a new instance of PeerManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewPeerManager(t mockConstructorTestingTNewPeerManager) *PeerManager {
mock := &PeerManager{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// Code generated by mockery v2.28.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// PeerProtector is an autogenerated mock type for the PeerProtector type
type PeerProtector struct {
mock.Mock
}
type PeerProtector_Expecter struct {
mock *mock.Mock
}
func (_m *PeerProtector) EXPECT() *PeerProtector_Expecter {
return &PeerProtector_Expecter{mock: &_m.Mock}
}
// IsProtected provides a mock function with given fields: _a0
func (_m *PeerProtector) IsProtected(_a0 peer.ID) bool {
ret := _m.Called(_a0)
var r0 bool
if rf, ok := ret.Get(0).(func(peer.ID) bool); ok {
r0 = rf(_a0)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// PeerProtector_IsProtected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsProtected'
type PeerProtector_IsProtected_Call struct {
*mock.Call
}
// IsProtected is a helper method to define mock.On call
// - _a0 peer.ID
func (_e *PeerProtector_Expecter) IsProtected(_a0 interface{}) *PeerProtector_IsProtected_Call {
return &PeerProtector_IsProtected_Call{Call: _e.mock.On("IsProtected", _a0)}
}
func (_c *PeerProtector_IsProtected_Call) Run(run func(_a0 peer.ID)) *PeerProtector_IsProtected_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *PeerProtector_IsProtected_Call) Return(_a0 bool) *PeerProtector_IsProtected_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *PeerProtector_IsProtected_Call) RunAndReturn(run func(peer.ID) bool) *PeerProtector_IsProtected_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewPeerProtector interface {
mock.TestingT
Cleanup(func())
}
// NewPeerProtector creates a new instance of PeerProtector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewPeerProtector(t mockConstructorTestingTNewPeerProtector) *PeerProtector {
mock := &PeerProtector{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// Code generated by mockery v2.28.0. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
peer "github.com/libp2p/go-libp2p/core/peer"
)
// Scores is an autogenerated mock type for the Scores type
type Scores struct {
mock.Mock
}
type Scores_Expecter struct {
mock *mock.Mock
}
func (_m *Scores) EXPECT() *Scores_Expecter {
return &Scores_Expecter{mock: &_m.Mock}
}
// GetPeerScore provides a mock function with given fields: id
func (_m *Scores) GetPeerScore(id peer.ID) (float64, error) {
ret := _m.Called(id)
var r0 float64
var r1 error
if rf, ok := ret.Get(0).(func(peer.ID) (float64, error)); ok {
return rf(id)
}
if rf, ok := ret.Get(0).(func(peer.ID) float64); ok {
r0 = rf(id)
} else {
r0 = ret.Get(0).(float64)
}
if rf, ok := ret.Get(1).(func(peer.ID) error); ok {
r1 = rf(id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Scores_GetPeerScore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPeerScore'
type Scores_GetPeerScore_Call struct {
*mock.Call
}
// GetPeerScore is a helper method to define mock.On call
// - id peer.ID
func (_e *Scores_Expecter) GetPeerScore(id interface{}) *Scores_GetPeerScore_Call {
return &Scores_GetPeerScore_Call{Call: _e.mock.On("GetPeerScore", id)}
}
func (_c *Scores_GetPeerScore_Call) Run(run func(id peer.ID)) *Scores_GetPeerScore_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(peer.ID))
})
return _c
}
func (_c *Scores_GetPeerScore_Call) Return(_a0 float64, _a1 error) *Scores_GetPeerScore_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *Scores_GetPeerScore_Call) RunAndReturn(run func(peer.ID) (float64, error)) *Scores_GetPeerScore_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewScores interface {
mock.TestingT
Cleanup(func())
}
// NewScores creates a new instance of Scores. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewScores(t mockConstructorTestingTNewScores) *Scores {
mock := &Scores{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
......@@ -16,38 +16,25 @@ const (
checkInterval = 1 * time.Second
)
//go:generate mockery --name Scores --output mocks/ --with-expecter=true
type Scores interface {
GetPeerScore(id peer.ID) (float64, error)
}
// ConnectedPeers enables querying the set of currently connected peers and disconnecting peers
//
//go:generate mockery --name ConnectedPeers --output mocks/ --with-expecter=true
type ConnectedPeers interface {
//go:generate mockery --name PeerManager --output mocks/ --with-expecter=true
type PeerManager interface {
Peers() []peer.ID
ClosePeer(peer.ID) error
}
//go:generate mockery --name PeerProtector --output mocks/ --with-expecter=true
type PeerProtector interface {
GetPeerScore(id peer.ID) (float64, error)
IsProtected(peer.ID) bool
}
//go:generate mockery --name PeerBlocker --output mocks/ --with-expecter=true
type PeerBlocker interface {
// TODO: Consider combining Close and Ban into a single call and have the adapter deal with the two calls
ClosePeer(peer.ID) error
BanPeer(peer.ID, time.Time) error
}
// PeerMonitor runs a background process to periodically check for peers with scores below a minimum.
// When it finds bad peers, it disconnects and bans them.
// A delay is introduced between each peer being checked to avoid spikes in system load.
type PeerMonitor struct {
ctx context.Context
cancelFn context.CancelFunc
l log.Logger
clock clock.Clock
peers ConnectedPeers
protector PeerProtector
scores Scores
blocker PeerBlocker
manager PeerManager
minScore float64
banDuration time.Duration
......@@ -58,17 +45,14 @@ type PeerMonitor struct {
nextPeerIdx int
}
func NewPeerMonitor(ctx context.Context, l log.Logger, clock clock.Clock, peers ConnectedPeers, protector PeerProtector, scores Scores, blocker PeerBlocker, minScore float64, banDuration time.Duration) *PeerMonitor {
func NewPeerMonitor(ctx context.Context, l log.Logger, clock clock.Clock, manager PeerManager, minScore float64, banDuration time.Duration) *PeerMonitor {
ctx, cancelFn := context.WithCancel(ctx)
return &PeerMonitor{
ctx: ctx,
cancelFn: cancelFn,
l: l,
clock: clock,
peers: peers,
protector: protector,
scores: scores,
blocker: blocker,
manager: manager,
minScore: minScore,
banDuration: banDuration,
}
......@@ -90,25 +74,25 @@ func (k *PeerMonitor) Stop() {
func (k *PeerMonitor) checkNextPeer() error {
// Get a new list of peers to check if we've checked all peers in the previous list
if k.nextPeerIdx >= len(k.peerList) {
k.peerList = k.peers.Peers()
k.peerList = k.manager.Peers()
k.nextPeerIdx = 0
}
id := k.peerList[k.nextPeerIdx]
k.nextPeerIdx++
score, err := k.scores.GetPeerScore(id)
score, err := k.manager.GetPeerScore(id)
if err != nil {
return fmt.Errorf("retrieve score for peer %v: %w", id, err)
}
if score > k.minScore {
return nil
}
if k.protector.IsProtected(id) {
if k.manager.IsProtected(id) {
return nil
}
if err := k.peers.ClosePeer(id); err != nil {
if err := k.manager.ClosePeer(id); err != nil {
return fmt.Errorf("disconnecting peer %v: %w", id, err)
}
if err := k.blocker.BanPeer(id, k.clock.Now().Add(k.banDuration)); err != nil {
if err := k.manager.BanPeer(id, k.clock.Now().Add(k.banDuration)); err != nil {
return fmt.Errorf("banning peer %v: %w", id, err)
}
......
......@@ -17,19 +17,16 @@ import (
const kickerBanDuration = 10 * time.Minute
func peerKickerSetup(t *testing.T) (*PeerMonitor, *clock2.DeterministicClock, *mocks.ConnectedPeers, *mocks.PeerProtector, *mocks.Scores, *mocks.PeerBlocker) {
func peerKickerSetup(t *testing.T) (*PeerMonitor, *clock2.DeterministicClock, *mocks.PeerManager) {
l := testlog.Logger(t, log.LvlInfo)
clock := clock2.NewDeterministicClock(time.UnixMilli(10000))
peers := mocks.NewConnectedPeers(t)
protector := mocks.NewPeerProtector(t)
blocker := mocks.NewPeerBlocker(t)
scores := mocks.NewScores(t)
kicker := NewPeerMonitor(context.Background(), l, clock, peers, protector, scores, blocker, -100, kickerBanDuration)
return kicker, clock, peers, protector, scores, blocker
manager := mocks.NewPeerManager(t)
kicker := NewPeerMonitor(context.Background(), l, clock, manager, -100, kickerBanDuration)
return kicker, clock, manager
}
func TestPeriodicallyCheckNextPeer(t *testing.T) {
kicker, clock, _, _, _, _ := peerKickerSetup(t)
kicker, clock, _ := peerKickerSetup(t)
// Each time a step is performed, it calls Done on the wait group so we can wait for it to be performed
stepCh := make(chan struct{}, 10)
kicker.bgTasks.Add(1)
......@@ -66,10 +63,10 @@ func TestCheckNextPeer(t *testing.T) {
}
t.Run("Check each peer then refresh list", func(t *testing.T) {
kicker, _, peers, _, scores, _ := peerKickerSetup(t)
peers.EXPECT().Peers().Return(peerIDs).Once()
kicker, _, manager := peerKickerSetup(t)
manager.EXPECT().Peers().Return(peerIDs).Once()
for _, id := range peerIDs {
scores.EXPECT().GetPeerScore(id).Return(1, nil).Once()
manager.EXPECT().GetPeerScore(id).Return(1, nil).Once()
require.NoError(t, kicker.checkNextPeer())
}
......@@ -80,32 +77,32 @@ func TestCheckNextPeer(t *testing.T) {
peer.ID("z"),
peer.ID("a"),
}
peers.EXPECT().Peers().Return(updatedPeers).Once()
manager.EXPECT().Peers().Return(updatedPeers).Once()
for _, id := range updatedPeers {
scores.EXPECT().GetPeerScore(id).Return(1, nil).Once()
manager.EXPECT().GetPeerScore(id).Return(1, nil).Once()
require.NoError(t, kicker.checkNextPeer())
}
})
t.Run("Close and ban peer when below min score", func(t *testing.T) {
kicker, clock, peers, protector, scores, blocker := peerKickerSetup(t)
kicker, clock, manager := peerKickerSetup(t)
id := peerIDs[0]
peers.EXPECT().Peers().Return(peerIDs).Once()
scores.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
protector.EXPECT().IsProtected(id).Return(false).Once()
peers.EXPECT().ClosePeer(id).Return(nil).Once()
blocker.EXPECT().BanPeer(id, clock.Now().Add(kickerBanDuration)).Return(nil).Once()
manager.EXPECT().Peers().Return(peerIDs).Once()
manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
manager.EXPECT().IsProtected(id).Return(false).Once()
manager.EXPECT().ClosePeer(id).Return(nil).Once()
manager.EXPECT().BanPeer(id, clock.Now().Add(kickerBanDuration)).Return(nil).Once()
require.NoError(t, kicker.checkNextPeer())
})
t.Run("Do not close protected peer when below min score", func(t *testing.T) {
kicker, _, peers, protector, scores, _ := peerKickerSetup(t)
kicker, _, manager := peerKickerSetup(t)
id := peerIDs[0]
peers.EXPECT().Peers().Return(peerIDs).Once()
scores.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
protector.EXPECT().IsProtected(id).Return(true)
manager.EXPECT().Peers().Return(peerIDs).Once()
manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
manager.EXPECT().IsProtected(id).Return(true)
require.NoError(t, kicker.checkNextPeer())
})
......
......@@ -126,7 +126,10 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l
n.scorer.OnDisconnect(conn.RemotePeer())
},
})
n.peerMonitor = monitor.NewPeerMonitor(resourcesCtx, log, clock.SystemClock, n.host.Network(), n.connMgr, eps, n, -100, 1*time.Hour)
peerManager := monitor.NewPeerManagerAdapter(n.host.Network(), n.connMgr, eps)
// TODO: minScore shouldn't just be hard coded here
// TODO: Ban duration needs to be set sensibly and probably should be a magic number here
n.peerMonitor = monitor.NewPeerMonitor(resourcesCtx, log, clock.SystemClock, peerManager, -100, 1*time.Hour)
n.peerMonitor.Start()
// notify of any new connections/streams/etc.
n.host.Network().Notify(NewNetworkNotifier(log, metrics))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment