github.com/status-im/status-go@v1.1.0/waku/common/rate_limiter_test.go (about)

     1  // Copyright 2019 The Waku Library Authors.
     2  //
     3  // The Waku library is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Lesser General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // (at your option) any later version.
     7  //
     8  // The Waku library is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty off
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    11  // GNU Lesser General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Lesser General Public License
    14  // along with the Waku library. If not, see <http://www.gnu.org/licenses/>.
    15  //
    16  // This software uses the go-ethereum library, which is licensed
    17  // under the GNU Lesser General Public Library, version 3 or any later.
    18  
    19  package common
    20  
    21  import (
    22  	"bytes"
    23  	"net"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"github.com/ethereum/go-ethereum/p2p"
    30  	"github.com/ethereum/go-ethereum/p2p/enode"
    31  )
    32  
    33  func TestPeerRateLimiterDecorator(t *testing.T) {
    34  	in, out := p2p.MsgPipe()
    35  	payload := []byte{0x01, 0x02, 0x03}
    36  	msg := p2p.Msg{
    37  		Code:       1,
    38  		Size:       uint32(len(payload)),
    39  		Payload:    bytes.NewReader(payload),
    40  		ReceivedAt: time.Now(),
    41  	}
    42  
    43  	go func() {
    44  		err := in.WriteMsg(msg)
    45  		require.NoError(t, err)
    46  	}()
    47  
    48  	messages := make(chan p2p.Msg, 1)
    49  	runLoop := func(rw p2p.MsgReadWriter) error {
    50  		msg, err := rw.ReadMsg()
    51  		if err != nil {
    52  			return err
    53  		}
    54  		messages <- msg
    55  		return nil
    56  	}
    57  
    58  	r := NewPeerRateLimiter(nil, &mockRateLimiterHandler{})
    59  	err := r.Decorate(nil, out, runLoop)
    60  	require.NoError(t, err)
    61  
    62  	receivedMsg := <-messages
    63  	receivedPayload := make([]byte, receivedMsg.Size)
    64  	_, err = receivedMsg.Payload.Read(receivedPayload)
    65  	require.NoError(t, err)
    66  	require.Equal(t, msg.Code, receivedMsg.Code)
    67  	require.Equal(t, payload, receivedPayload)
    68  }
    69  
    70  func TestPeerLimiterThrottlingWithZeroLimit(t *testing.T) {
    71  	r := NewPeerRateLimiter(&PeerRateLimiterConfig{}, &mockRateLimiterHandler{})
    72  	for i := 0; i < 1000; i++ {
    73  		throttle := r.throttleIP("<nil>", 0)
    74  		require.False(t, throttle)
    75  		throttle = r.throttlePeer([]byte{0x01, 0x02, 0x03}, 0)
    76  		require.False(t, throttle)
    77  	}
    78  }
    79  
    80  func TestPeerPacketLimiterHandler(t *testing.T) {
    81  	h := &mockRateLimiterHandler{}
    82  	r := NewPeerRateLimiter(nil, h)
    83  	p := &TestWakuPeer{
    84  		peer: p2p.NewPeer(enode.ID{0xaa, 0xbb, 0xcc}, "test-peer", nil),
    85  	}
    86  	rw1, rw2 := p2p.MsgPipe()
    87  	count := 100
    88  
    89  	go func() {
    90  		err := echoMessages(r, p, rw2)
    91  		require.NoError(t, err)
    92  	}()
    93  
    94  	done := make(chan struct{})
    95  	go func() {
    96  		for i := 0; i < count; i++ {
    97  			msg, err := rw1.ReadMsg()
    98  			require.NoError(t, err)
    99  			require.EqualValues(t, 101, msg.Code)
   100  		}
   101  		close(done)
   102  	}()
   103  
   104  	for i := 0; i < count; i++ {
   105  		err := rw1.WriteMsg(p2p.Msg{Code: 101})
   106  		require.NoError(t, err)
   107  	}
   108  
   109  	<-done
   110  
   111  	require.EqualValues(t, 100-defaultPeerRateLimiterConfig.PacketLimitPerSecIP, h.exceedIPLimit)
   112  	require.EqualValues(t, 100-defaultPeerRateLimiterConfig.PacketLimitPerSecPeerID, h.exceedPeerLimit)
   113  }
   114  
   115  func TestPeerBytesLimiterHandler(t *testing.T) {
   116  	h := &mockRateLimiterHandler{}
   117  	r := NewPeerRateLimiter(&PeerRateLimiterConfig{
   118  		BytesLimitPerSecIP:     30,
   119  		BytesLimitPerSecPeerID: 30,
   120  	}, h)
   121  	p := &TestWakuPeer{
   122  		peer: p2p.NewPeer(enode.ID{0xaa, 0xbb, 0xcc}, "test-peer", nil),
   123  	}
   124  	rw1, rw2 := p2p.MsgPipe()
   125  	count := 6
   126  
   127  	go func() {
   128  		err := echoMessages(r, p, rw2)
   129  		require.NoError(t, err)
   130  	}()
   131  
   132  	done := make(chan struct{})
   133  	go func() {
   134  		for i := 0; i < count; i++ {
   135  			msg, err := rw1.ReadMsg()
   136  			require.NoError(t, err)
   137  			require.EqualValues(t, 101, msg.Code)
   138  			require.NoError(t, msg.Discard())
   139  		}
   140  		close(done)
   141  	}()
   142  
   143  	for i := 0; i < count; i++ {
   144  		payload := make([]byte, 10)
   145  		msg := p2p.Msg{
   146  			Code:    101,
   147  			Size:    uint32(len(payload)),
   148  			Payload: bytes.NewReader(payload),
   149  		}
   150  
   151  		err := rw1.WriteMsg(msg)
   152  		require.NoError(t, err)
   153  	}
   154  
   155  	<-done
   156  
   157  	require.EqualValues(t, 3, h.exceedIPLimit)
   158  	require.EqualValues(t, 3, h.exceedPeerLimit)
   159  }
   160  
   161  func TestPeerPacketLimiterHandlerWithWhitelisting(t *testing.T) {
   162  	h := &mockRateLimiterHandler{}
   163  	r := NewPeerRateLimiter(&PeerRateLimiterConfig{
   164  		PacketLimitPerSecIP:     1,
   165  		PacketLimitPerSecPeerID: 1,
   166  		WhitelistedIPs:          []string{"<nil>"}, // no IP is represented as <nil> string
   167  		WhitelistedPeerIDs:      []enode.ID{{0xaa, 0xbb, 0xcc}},
   168  	}, h)
   169  	p := &TestWakuPeer{
   170  		peer: p2p.NewPeer(enode.ID{0xaa, 0xbb, 0xcc}, "test-peer", nil),
   171  	}
   172  	rw1, rw2 := p2p.MsgPipe()
   173  	count := 100
   174  
   175  	go func() {
   176  		err := echoMessages(r, p, rw2)
   177  		require.NoError(t, err)
   178  	}()
   179  
   180  	done := make(chan struct{})
   181  	go func() {
   182  		for i := 0; i < count; i++ {
   183  			msg, err := rw1.ReadMsg()
   184  			require.NoError(t, err)
   185  			require.EqualValues(t, 101, msg.Code)
   186  		}
   187  		close(done)
   188  	}()
   189  
   190  	for i := 0; i < count; i++ {
   191  		err := rw1.WriteMsg(p2p.Msg{Code: 101})
   192  		require.NoError(t, err)
   193  	}
   194  
   195  	<-done
   196  
   197  	require.Equal(t, 0, h.exceedIPLimit)
   198  	require.Equal(t, 0, h.exceedPeerLimit)
   199  }
   200  
   201  func echoMessages(r *PeerRateLimiter, p RateLimiterPeer, rw p2p.MsgReadWriter) error {
   202  	return r.Decorate(p, rw, func(rw p2p.MsgReadWriter) error {
   203  		for {
   204  			msg, err := rw.ReadMsg()
   205  			if err != nil {
   206  				return err
   207  			}
   208  			err = rw.WriteMsg(msg)
   209  			if err != nil {
   210  				return err
   211  			}
   212  		}
   213  	})
   214  }
   215  
   216  type mockRateLimiterHandler struct {
   217  	exceedPeerLimit int
   218  	exceedIPLimit   int
   219  }
   220  
   221  func (m *mockRateLimiterHandler) ExceedPeerLimit() error { m.exceedPeerLimit++; return nil }
   222  func (m *mockRateLimiterHandler) ExceedIPLimit() error   { m.exceedIPLimit++; return nil }
   223  
   224  type TestWakuPeer struct {
   225  	peer *p2p.Peer
   226  }
   227  
   228  func (p *TestWakuPeer) IP() net.IP {
   229  	return p.peer.Node().IP()
   230  }
   231  
   232  func (p *TestWakuPeer) ID() []byte {
   233  	id := p.peer.ID()
   234  	return id[:]
   235  }