diff --git a/waku/common/protocol.go b/waku/common/protocol.go index ff1e6b6cd..dd7b25434 100644 --- a/waku/common/protocol.go +++ b/waku/common/protocol.go @@ -66,8 +66,10 @@ type WakuHost interface { LightClientModeConnectionRestricted() bool // ConfirmationsEnabled returns true if message confirmations are enabled. ConfirmationsEnabled() bool - // RateLimits returns the current rate limits for the host - RateLimits() RateLimits + // PacketRateLimits returns the current rate limits for the host + PacketRateLimits() RateLimits + // BytesRateLimits returns the current rate limits for the host + BytesRateLimits() RateLimits // MinPow returns the MinPow for the host MinPow() float64 // BloomFilterMode returns whether the host is using bloom filter diff --git a/waku/common/rate_limiter.go b/waku/common/rate_limiter.go index 29df9d649..c515f6c62 100644 --- a/waku/common/rate_limiter.go +++ b/waku/common/rate_limiter.go @@ -62,15 +62,12 @@ func (MetricsRateLimiterHandler) ExceedIPLimit() error { } // RateLimits contains information about rate limit settings. -// It is exchanged using rateLimitingCode packet or in the handshake. +// It's agnostic on what it's being rate limited on (bytes or number of packets currently) +// It's exchanged with the status-update packet code type RateLimits struct { - PacketIPLimits uint64 // packets per second from a single IP (default 0, no limits) - PacketPeerIDLimits uint64 // packets per second from a single peer ID (default 0, no limits) - PacketTopicLimits uint64 // packets per second from a single topic (default 0, no limits) - - BytesIPLimits uint64 // bytes per second from a single IP (default 0, no limits) - BytesPeerIDLimits uint64 // bytes per second from a single peer ID (default 0, no limits) - BytesTopicLimits uint64 // bytes per second from a single topic (default 0, no limits) + IPLimits uint64 // amount per second from a single IP (default 0, no limits) + PeerIDLimits uint64 // amount per second from a single peer ID (default 0, no limits) + TopicLimits uint64 // amount per second from a single topic (default 0, no limits) } func (r RateLimits) IsZero() bool { @@ -125,10 +122,10 @@ var defaultPeerRateLimiterConfig = PeerRateLimiterConfig{ // PeerRateLimiter represents a rate limiter that limits communication between Peers type PeerRateLimiter struct { packetPeerIDThrottler *tb.Throttler - packetIpThrottler *tb.Throttler + packetIPThrottler *tb.Throttler bytesPeerIDThrottler *tb.Throttler - bytesIpThrottler *tb.Throttler + bytesIPThrottler *tb.Throttler PacketLimitPerSecIP int64 PacketLimitPerSecPeerID int64 @@ -150,9 +147,9 @@ func NewPeerRateLimiter(cfg *PeerRateLimiterConfig, handlers ...RateLimiterHandl return &PeerRateLimiter{ packetPeerIDThrottler: tb.NewThrottler(time.Millisecond * 100), - packetIpThrottler: tb.NewThrottler(time.Millisecond * 100), + packetIPThrottler: tb.NewThrottler(time.Millisecond * 100), bytesPeerIDThrottler: tb.NewThrottler(time.Millisecond * 100), - bytesIpThrottler: tb.NewThrottler(time.Millisecond * 100), + bytesIPThrottler: tb.NewThrottler(time.Millisecond * 100), PacketLimitPerSecIP: cfg.PacketLimitPerSecIP, PacketLimitPerSecPeerID: cfg.PacketLimitPerSecPeerID, BytesLimitPerSecIP: cfg.BytesLimitPerSecIP, @@ -256,10 +253,10 @@ func (r *PeerRateLimiter) throttleIP(ip string, size uint32) bool { var bytesLimiterResponse bool if r.PacketLimitPerSecIP != 0 { - packetLimiterResponse = r.packetIpThrottler.Halt(ip, 1, r.PacketLimitPerSecIP) + packetLimiterResponse = r.packetIPThrottler.Halt(ip, 1, r.PacketLimitPerSecIP) } if r.BytesLimitPerSecIP != 0 { - bytesLimiterResponse = r.bytesIpThrottler.Halt(ip, int64(size), r.BytesLimitPerSecIP) + bytesLimiterResponse = r.bytesIPThrottler.Halt(ip, int64(size), r.BytesLimitPerSecIP) } return packetLimiterResponse || bytesLimiterResponse diff --git a/waku/common/rate_limiter_test.go b/waku/common/rate_limiter_test.go index 43f8c90be..830c21b48 100644 --- a/waku/common/rate_limiter_test.go +++ b/waku/common/rate_limiter_test.go @@ -135,7 +135,7 @@ func TestPeerBytesLimiterHandler(t *testing.T) { msg, err := rw1.ReadMsg() require.NoError(t, err) require.EqualValues(t, 101, msg.Code) - msg.Discard() + require.NoError(t, msg.Discard()) } close(done) }() diff --git a/waku/v0/status_options.go b/waku/v0/status_options.go index 594d9f8a4..58f43f4c7 100644 --- a/waku/v0/status_options.go +++ b/waku/v0/status_options.go @@ -40,7 +40,7 @@ type StatusOptions struct { func StatusOptionsFromHost(host common.WakuHost) StatusOptions { opts := StatusOptions{} - rateLimits := host.RateLimits() + rateLimits := host.PacketRateLimits() opts.RateLimits = &rateLimits lightNode := host.LightClientMode() diff --git a/waku/v1/peer.go b/waku/v1/peer.go index e9277b0f9..11c02d788 100644 --- a/waku/v1/peer.go +++ b/waku/v1/peer.go @@ -48,8 +48,10 @@ type Peer struct { // In that case no envelope is accepted. fullNode bool confirmationsEnabled bool - rateLimitsMu sync.Mutex - rateLimits common.RateLimits + packetRateLimitsMu sync.Mutex + packetRateLimits common.RateLimits + bytesRateLimitsMu sync.Mutex + bytesRateLimits common.RateLimits known mapset.Set // Messages already known by the peer to avoid wasting bandwidth } @@ -488,8 +490,11 @@ func (p *Peer) setOptions(peerOptions StatusOptions) error { if peerOptions.ConfirmationsEnabled != nil { p.confirmationsEnabled = *peerOptions.ConfirmationsEnabled } - if peerOptions.RateLimits != nil { - p.setRateLimits(*peerOptions.RateLimits) + if peerOptions.PacketRateLimits != nil { + p.setPacketRateLimits(*peerOptions.PacketRateLimits) + } + if peerOptions.BytesRateLimits != nil { + p.setBytesRateLimits(*peerOptions.BytesRateLimits) } return nil @@ -591,10 +596,16 @@ func (p *Peer) setTopicInterest(topicInterest []common.TopicType) { p.bloomFilter = nil } -func (p *Peer) setRateLimits(r common.RateLimits) { - p.rateLimitsMu.Lock() - p.rateLimits = r - p.rateLimitsMu.Unlock() +func (p *Peer) setPacketRateLimits(r common.RateLimits) { + p.packetRateLimitsMu.Lock() + p.packetRateLimits = r + p.packetRateLimitsMu.Unlock() +} + +func (p *Peer) setBytesRateLimits(r common.RateLimits) { + p.bytesRateLimitsMu.Lock() + p.bytesRateLimits = r + p.bytesRateLimitsMu.Unlock() } // topicOrBloomMatch matches against topic-interest if topic interest diff --git a/waku/v1/status_options.go b/waku/v1/status_options.go index 88e63bac5..b7ee270db 100644 --- a/waku/v1/status_options.go +++ b/waku/v1/status_options.go @@ -34,15 +34,19 @@ type StatusOptions struct { BloomFilter []byte `rlp:"key=1"` LightNodeEnabled *bool `rlp:"key=2"` ConfirmationsEnabled *bool `rlp:"key=3"` - RateLimits *common.RateLimits `rlp:"key=4"` + PacketRateLimits *common.RateLimits `rlp:"key=4"` TopicInterest []common.TopicType `rlp:"key=5"` + BytesRateLimits *common.RateLimits `rlp:"key=6"` } func StatusOptionsFromHost(host common.WakuHost) StatusOptions { opts := StatusOptions{} - rateLimits := host.RateLimits() - opts.RateLimits = &rateLimits + packetRateLimits := host.PacketRateLimits() + opts.PacketRateLimits = &packetRateLimits + + bytesRateLimits := host.BytesRateLimits() + opts.BytesRateLimits = &bytesRateLimits lightNode := host.LightClientMode() opts.LightNodeEnabled = &lightNode @@ -114,8 +118,12 @@ func (o StatusOptions) WithDefaults() StatusOptions { o.ConfirmationsEnabled = &confirmationsEnabled } - if o.RateLimits == nil { - o.RateLimits = &common.RateLimits{} + if o.PacketRateLimits == nil { + o.PacketRateLimits = &common.RateLimits{} + } + + if o.BytesRateLimits == nil { + o.BytesRateLimits = &common.RateLimits{} } if o.BloomFilter == nil { diff --git a/waku/v1/status_options_test.go b/waku/v1/status_options_test.go index 61a3abcfe..c86d06ef3 100644 --- a/waku/v1/status_options_test.go +++ b/waku/v1/status_options_test.go @@ -20,12 +20,17 @@ func TestEncodeDecodeRLP(t *testing.T) { BloomFilter: common.TopicType{0xaa, 0xbb, 0xcc, 0xdd}.ToBloom(), LightNodeEnabled: &lightNodeEnabled, ConfirmationsEnabled: &confirmationsEnabled, - RateLimits: &common.RateLimits{ + PacketRateLimits: &common.RateLimits{ IPLimits: 10, PeerIDLimits: 5, TopicLimits: 1, }, TopicInterest: []common.TopicType{{0x01}, {0x02}, {0x03}, {0x04}}, + BytesRateLimits: &common.RateLimits{ + IPLimits: 10, + PeerIDLimits: 5, + TopicLimits: 1, + }, } data, err := rlp.EncodeToBytes(opts) require.NoError(t, err) @@ -73,6 +78,7 @@ func TestInitRLPKeyFields(t *testing.T) { 3: 3, 4: 4, 5: 5, + 6: 6, } kfi := map[statusOptionKey]int{ 0: 0, @@ -81,6 +87,7 @@ func TestInitRLPKeyFields(t *testing.T) { 3: 3, 4: 4, 5: 5, + 6: 6, } // Test that the kfi length matches the inited global keyFieldIdx length diff --git a/waku/waku.go b/waku/waku.go index 31d6d4ce3..09a6c6722 100644 --- a/waku/waku.go +++ b/waku/waku.go @@ -394,16 +394,25 @@ func (w *Waku) LightClientModeConnectionRestricted() bool { return w.settings.RestrictLightClientsConn } -// RateLimiting returns RateLimits information. -func (w *Waku) RateLimits() common.RateLimits { +// PacketRateLimiting returns RateLimits information for packets +func (w *Waku) PacketRateLimits() common.RateLimits { if w.rateLimiter == nil { return common.RateLimits{} } return common.RateLimits{ - PacketIPLimits: uint64(w.rateLimiter.PacketLimitPerSecIP), - PacketPeerIDLimits: uint64(w.rateLimiter.PacketLimitPerSecPeerID), - BytesIPLimits: uint64(w.rateLimiter.BytesLimitPerSecIP), - BytesPeerIDLimits: uint64(w.rateLimiter.BytesLimitPerSecPeerID), + IPLimits: uint64(w.rateLimiter.PacketLimitPerSecIP), + PeerIDLimits: uint64(w.rateLimiter.PacketLimitPerSecPeerID), + } +} + +// BytesRateLimiting returns RateLimits information for bytes +func (w *Waku) BytesRateLimits() common.RateLimits { + if w.rateLimiter == nil { + return common.RateLimits{} + } + return common.RateLimits{ + IPLimits: uint64(w.rateLimiter.BytesLimitPerSecIP), + PeerIDLimits: uint64(w.rateLimiter.BytesLimitPerSecPeerID), } }