github.com/ethereum-optimism/optimism@v1.7.2/op-node/p2p/monitor/peer_monitor_test.go (about)

     1  package monitor
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/ethereum-optimism/optimism/op-node/p2p/monitor/mocks"
    11  	clock2 "github.com/ethereum-optimism/optimism/op-service/clock"
    12  	"github.com/ethereum-optimism/optimism/op-service/testlog"
    13  	"github.com/ethereum/go-ethereum/log"
    14  	"github.com/libp2p/go-libp2p/core/peer"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  const testBanDuration = 2 * time.Hour
    19  
    20  func peerMonitorSetup(t *testing.T) (*PeerMonitor, *clock2.DeterministicClock, *mocks.PeerManager) {
    21  	l := testlog.Logger(t, log.LevelInfo)
    22  	clock := clock2.NewDeterministicClock(time.UnixMilli(10000))
    23  	manager := mocks.NewPeerManager(t)
    24  	monitor := NewPeerMonitor(context.Background(), l, clock, manager, -100, testBanDuration)
    25  	return monitor, clock, manager
    26  }
    27  
    28  func TestPeriodicallyCheckNextPeer(t *testing.T) {
    29  	monitor, clock, _ := peerMonitorSetup(t)
    30  	// Each time a step is performed, it calls Done on the wait group so we can wait for it to be performed
    31  	stepCh := make(chan struct{}, 10)
    32  	monitor.bgTasks.Add(1)
    33  	var actionErr error
    34  	go monitor.background(func() error {
    35  		stepCh <- struct{}{}
    36  		return actionErr
    37  	})
    38  	defer monitor.Stop()
    39  	// Wait for the step ticker to be started
    40  	clock.WaitForNewPendingTaskWithTimeout(30 * time.Second)
    41  
    42  	// Should perform another step after each interval
    43  	for i := 0; i < 5; i++ {
    44  		clock.AdvanceTime(checkInterval)
    45  		waitForChan(t, stepCh, fmt.Sprintf("Did not perform step %v", i))
    46  		require.Len(t, stepCh, 0)
    47  	}
    48  
    49  	// Should continue executing periodically even after an error
    50  	actionErr = errors.New("boom")
    51  	for i := 0; i < 5; i++ {
    52  		clock.AdvanceTime(checkInterval)
    53  		waitForChan(t, stepCh, fmt.Sprintf("Did not perform step %v", i))
    54  		require.Len(t, stepCh, 0)
    55  	}
    56  }
    57  
    58  func TestCheckNextPeer(t *testing.T) {
    59  	peerIDs := []peer.ID{
    60  		peer.ID("a"),
    61  		peer.ID("b"),
    62  		peer.ID("c"),
    63  	}
    64  
    65  	t.Run("No peers", func(t *testing.T) {
    66  		monitor, _, manager := peerMonitorSetup(t)
    67  		manager.EXPECT().Peers().Return(nil).Once()
    68  		require.NoError(t, monitor.checkNextPeer())
    69  	})
    70  
    71  	t.Run("Check each peer then refresh list", func(t *testing.T) {
    72  		monitor, _, manager := peerMonitorSetup(t)
    73  		manager.EXPECT().Peers().Return(peerIDs).Once()
    74  		for _, id := range peerIDs {
    75  			manager.EXPECT().GetPeerScore(id).Return(1, nil).Once()
    76  
    77  			require.NoError(t, monitor.checkNextPeer())
    78  		}
    79  
    80  		updatedPeers := []peer.ID{
    81  			peer.ID("x"),
    82  			peer.ID("y"),
    83  			peer.ID("z"),
    84  			peer.ID("a"),
    85  		}
    86  		manager.EXPECT().Peers().Return(updatedPeers).Once()
    87  		for _, id := range updatedPeers {
    88  			manager.EXPECT().GetPeerScore(id).Return(1, nil).Once()
    89  
    90  			require.NoError(t, monitor.checkNextPeer())
    91  		}
    92  	})
    93  
    94  	t.Run("Close and ban peer when below min score", func(t *testing.T) {
    95  		monitor, clock, manager := peerMonitorSetup(t)
    96  		id := peerIDs[0]
    97  		manager.EXPECT().Peers().Return(peerIDs).Once()
    98  		manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
    99  		manager.EXPECT().IsStatic(id).Return(false).Once()
   100  		manager.EXPECT().BanPeer(id, clock.Now().Add(testBanDuration)).Return(nil).Once()
   101  
   102  		require.NoError(t, monitor.checkNextPeer())
   103  	})
   104  
   105  	t.Run("Do not close protected peer when below min score", func(t *testing.T) {
   106  		monitor, _, manager := peerMonitorSetup(t)
   107  		id := peerIDs[0]
   108  		manager.EXPECT().Peers().Return(peerIDs).Once()
   109  		manager.EXPECT().GetPeerScore(id).Return(-101, nil).Once()
   110  		manager.EXPECT().IsStatic(id).Return(true)
   111  
   112  		require.NoError(t, monitor.checkNextPeer())
   113  	})
   114  }
   115  
   116  func waitForChan(t *testing.T, ch chan struct{}, msg string) {
   117  	ctx, cancelFn := context.WithTimeout(context.Background(), 30*time.Second)
   118  	defer cancelFn()
   119  	select {
   120  	case <-ctx.Done():
   121  		t.Fatal(msg)
   122  	case <-ch:
   123  		// Ok
   124  	}
   125  }