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

     1  package p2p
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/ethereum-optimism/optimism/op-node/p2p/store"
    10  	"github.com/ethereum-optimism/optimism/op-service/clock"
    11  	"github.com/ethereum-optimism/optimism/op-service/testlog"
    12  	"github.com/ethereum/go-ethereum/log"
    13  	"github.com/libp2p/go-libp2p/core/peer"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  type stubScoreBookUpdate struct {
    18  	id   peer.ID
    19  	diff store.ScoreDiff
    20  }
    21  type stubScoreBook struct {
    22  	err     error
    23  	scores  map[peer.ID]store.PeerScores
    24  	updates chan stubScoreBookUpdate
    25  }
    26  
    27  func (s *stubScoreBook) GetPeerScores(id peer.ID) (store.PeerScores, error) {
    28  	if s.err != nil {
    29  		return store.PeerScores{}, s.err
    30  	}
    31  	scores, ok := s.scores[id]
    32  	if !ok {
    33  		return store.PeerScores{}, nil
    34  	}
    35  	return scores, nil
    36  }
    37  
    38  func (s *stubScoreBook) SetScore(id peer.ID, diff store.ScoreDiff) (store.PeerScores, error) {
    39  	s.updates <- stubScoreBookUpdate{id, diff}
    40  	return s.GetPeerScores(id)
    41  }
    42  
    43  type appScoreTestData struct {
    44  	ctx       context.Context
    45  	logger    log.Logger
    46  	clock     *clock.DeterministicClock
    47  	peers     []peer.ID
    48  	scorebook *stubScoreBook
    49  }
    50  
    51  func (a *appScoreTestData) WaitForNextScoreBookUpdate(t *testing.T) stubScoreBookUpdate {
    52  	ctx, cancelFunc := context.WithTimeout(a.ctx, 30*time.Second)
    53  	defer cancelFunc()
    54  	select {
    55  	case update := <-a.scorebook.updates:
    56  		return update
    57  	case <-ctx.Done():
    58  		t.Fatal("Did not receive expected scorebook update")
    59  		return stubScoreBookUpdate{}
    60  	}
    61  }
    62  
    63  func setupPeerApplicationScorerTest(t *testing.T, params *ApplicationScoreParams) (*appScoreTestData, *peerApplicationScorer) {
    64  	data := &appScoreTestData{
    65  		ctx:    context.Background(),
    66  		logger: testlog.Logger(t, log.LevelInfo),
    67  		clock:  clock.NewDeterministicClock(time.UnixMilli(1000)),
    68  		peers:  []peer.ID{},
    69  		scorebook: &stubScoreBook{
    70  			scores:  make(map[peer.ID]store.PeerScores),
    71  			updates: make(chan stubScoreBookUpdate, 10),
    72  		},
    73  	}
    74  	appScorer := newPeerApplicationScorer(data.ctx, data.logger, data.clock, params, data.scorebook, func() []peer.ID {
    75  		return data.peers
    76  	})
    77  	return data, appScorer
    78  }
    79  
    80  func TestIncrementValidResponses(t *testing.T) {
    81  	data, appScorer := setupPeerApplicationScorerTest(t, &ApplicationScoreParams{
    82  		ValidResponseCap: 10,
    83  	})
    84  
    85  	appScorer.onValidResponse("aaa")
    86  	require.Len(t, data.scorebook.updates, 1)
    87  	update := <-data.scorebook.updates
    88  	require.Equal(t, stubScoreBookUpdate{peer.ID("aaa"), store.IncrementValidResponses{Cap: 10}}, update)
    89  }
    90  
    91  func TestIncrementErrorResponses(t *testing.T) {
    92  	data, appScorer := setupPeerApplicationScorerTest(t, &ApplicationScoreParams{
    93  		ErrorResponseCap: 10,
    94  	})
    95  
    96  	appScorer.onResponseError("aaa")
    97  	require.Len(t, data.scorebook.updates, 1)
    98  	update := <-data.scorebook.updates
    99  	require.Equal(t, stubScoreBookUpdate{peer.ID("aaa"), store.IncrementErrorResponses{Cap: 10}}, update)
   100  }
   101  
   102  func TestIncrementRejectedPayloads(t *testing.T) {
   103  	data, appScorer := setupPeerApplicationScorerTest(t, &ApplicationScoreParams{
   104  		RejectedPayloadCap: 10,
   105  	})
   106  
   107  	appScorer.onRejectedPayload("aaa")
   108  	require.Len(t, data.scorebook.updates, 1)
   109  	update := <-data.scorebook.updates
   110  	require.Equal(t, stubScoreBookUpdate{peer.ID("aaa"), store.IncrementRejectedPayloads{Cap: 10}}, update)
   111  }
   112  
   113  func TestApplicationScore(t *testing.T) {
   114  	data, appScorer := setupPeerApplicationScorerTest(t, &ApplicationScoreParams{
   115  		ValidResponseWeight:   0.8,
   116  		ErrorResponseWeight:   0.6,
   117  		RejectedPayloadWeight: 0.4,
   118  	})
   119  
   120  	peerScore := store.PeerScores{
   121  		ReqResp: store.ReqRespScores{
   122  			ValidResponses:   1,
   123  			ErrorResponses:   2,
   124  			RejectedPayloads: 3,
   125  		},
   126  	}
   127  	data.scorebook.scores["aaa"] = peerScore
   128  	score := appScorer.ApplicationScore("aaa")
   129  	require.Equal(t, 1*0.8+2*0.6+3*0.4, score)
   130  }
   131  
   132  func TestApplicationScoreZeroWhenScoreDoesNotLoad(t *testing.T) {
   133  	data, appScorer := setupPeerApplicationScorerTest(t, &ApplicationScoreParams{})
   134  
   135  	data.scorebook.err = errors.New("boom")
   136  	score := appScorer.ApplicationScore("aaa")
   137  	require.Zero(t, score)
   138  }
   139  
   140  func TestDecayScoresAfterDecayInterval(t *testing.T) {
   141  	params := &ApplicationScoreParams{
   142  		ValidResponseDecay:   0.8,
   143  		ErrorResponseDecay:   0.7,
   144  		RejectedPayloadDecay: 0.3,
   145  		DecayToZero:          0.1,
   146  		DecayInterval:        90 * time.Second,
   147  	}
   148  	data, appScorer := setupPeerApplicationScorerTest(t, params)
   149  	data.peers = []peer.ID{"aaa", "bbb"}
   150  
   151  	expectedDecay := &store.DecayApplicationScores{
   152  		ValidResponseDecay:   0.8,
   153  		ErrorResponseDecay:   0.7,
   154  		RejectedPayloadDecay: 0.3,
   155  		DecayToZero:          0.1,
   156  	}
   157  
   158  	appScorer.start()
   159  	defer appScorer.stop()
   160  
   161  	data.clock.WaitForNewPendingTaskWithTimeout(30 * time.Second)
   162  
   163  	data.clock.AdvanceTime(params.DecayInterval)
   164  
   165  	require.Equal(t, stubScoreBookUpdate{id: "aaa", diff: expectedDecay}, data.WaitForNextScoreBookUpdate(t))
   166  	require.Equal(t, stubScoreBookUpdate{id: "bbb", diff: expectedDecay}, data.WaitForNextScoreBookUpdate(t))
   167  }