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 }