Skip to content

Commit 2a274c7

Browse files
nibharii-cruz
authored andcommitted
Remove Mutex from RateLimit as it has &mut self everywhere.
Co-authored-by: ii-cruz <ii.pintocruz@gmail.com>
1 parent 9b9d82d commit 2a274c7

4 files changed

Lines changed: 72 additions & 91 deletions

File tree

network-interface/src/request/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub trait RequestCommon:
143143
pub trait RequestSerialize: RequestCommon {
144144
/// Serializes a request.
145145
/// A serialized request is composed of:
146-
/// - A variant for the Type ID of the request
146+
/// - A variable sized integer for the Type ID of the request
147147
/// - Serialized content of the inner type.
148148
fn serialize_request(&self) -> Vec<u8> {
149149
let mut data = Vec::with_capacity(self.serialized_request_size());
@@ -167,7 +167,7 @@ pub trait RequestSerialize: RequestCommon {
167167

168168
/// Deserializes a request
169169
/// A serialized request is composed of:
170-
/// - A variant for the Type ID of the request
170+
/// - A variable sized integer for the Type ID of the request
171171
/// - Serialized content of the inner type.
172172
fn deserialize_request(buffer: &[u8]) -> Result<Self, DeserializeError> {
173173
// Check for correct type.

network-libp2p/src/network_types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ pub(crate) struct TaskState {
249249
/// Senders for receiving responses per `InboundRequestId` for request-response
250250
pub(crate) response_channels:
251251
HashMap<InboundRequestId, ResponseChannel<Option<OutgoingResponse>>>,
252-
/// Senders for replying to requests per `RequestType` for request-response
252+
/// Senders and respective rate limiting constants for replying to requests per `RequestType` for request-response
253253
pub(crate) receive_requests: HashMap<
254254
RequestType,
255255
(

network-libp2p/src/rate_limiting.rs

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,17 @@ use std::{
55
};
66

77
use instant::Instant;
8-
use libp2p::{request_response::InboundRequestId, PeerId};
8+
use libp2p::PeerId;
99
use nimiq_network_interface::request::{RequestCommon, RequestType};
10-
use parking_lot::Mutex;
1110

1211
/// The rate limiting request metadata that will be passed on between the network and the swarm.
1312
/// This is not sent through the wire.
1413
#[derive(Debug, PartialEq)]
1514
pub(crate) struct RequestRateLimitData {
1615
/// Maximum requests allowed by this request type.
17-
max_requests: u32,
16+
pub(crate) max_requests: u32,
1817
/// The range/window of time of this request type.
19-
time_window: Duration,
18+
pub(crate) time_window: Duration,
2019
}
2120

2221
impl RequestRateLimitData {
@@ -163,26 +162,27 @@ impl RateLimit {
163162
}
164163
}
165164

166-
// Network helpers for rate limiting
165+
// Rate limiting overarching structure. It holds the rate limits by peer and request type.
166+
// This handles the case of a peer reconnecting within the time window to attempt to bypass the rate limits established.
167167
#[derive(Default)]
168168
pub(crate) struct RateLimits {
169-
peer_request_limits: Mutex<HashMap<PeerId, HashMap<RequestType, RateLimit>>>,
170-
rate_limits_pending_deletion: Mutex<PendingDeletion>,
169+
/// The rate limits per active peer.
170+
peer_request_limits: HashMap<PeerId, HashMap<RequestType, RateLimit>>,
171+
/// All the pending deletion rate limits.
172+
rate_limits_pending_deletion: PendingDeletion,
171173
}
172174

173175
impl RateLimits {
176+
/// Increases the counter of the rate limit and returns a bool in case the defined rate limit is surpassed.
174177
pub(crate) fn exceeds_rate_limit(
175178
&mut self,
176179
peer_id: PeerId,
177180
request_type: RequestType,
178-
request_id: InboundRequestId,
179181
request_rate_limit_data: &RequestRateLimitData,
180182
) -> bool {
181-
// Gets lock of peer requests limits read and write on it.
182-
let mut peer_request_limits = self.peer_request_limits.lock();
183-
184183
// If the peer has never sent a request of this type, creates a new entry.
185-
let requests_limit = peer_request_limits
184+
let requests_limit = self
185+
.peer_request_limits
186186
.entry(peer_id)
187187
.or_default()
188188
.entry(request_type)
@@ -195,67 +195,44 @@ impl RateLimits {
195195
});
196196

197197
// Ensures that the request is allowed based on the set limits and updates the counter.
198-
// Returns early if not allowed.
199-
if !requests_limit.increment_and_is_allowed(1) {
200-
info!(
201-
%request_id,
202-
%peer_id,
203-
%request_type,
204-
"Rate limit was exceeded!",
205-
);
206-
log::debug!(
207-
"[{:?}][{:?}] {:?} Exceeded max requests rate {:?} requests per {:?} seconds",
208-
request_id,
209-
peer_id,
210-
request_type,
211-
request_rate_limit_data.max_requests,
212-
request_rate_limit_data.time_window,
213-
);
214-
return true;
215-
}
216-
217-
false
198+
!requests_limit.increment_and_is_allowed(1)
218199
}
219200

201+
/// Mark all rate limits of a given peer as pending for deletion.
202+
/// Every time this is called the expired rate limits will get delete pruned.
220203
pub(crate) fn remove_rate_limits(&mut self, peer_id: PeerId) {
221204
// Every time a peer disconnects, we delete all expired pending limits.
222205
self.clean_up();
223206

224-
// Firstly we must acquire the lock of the pending deletes to avoid deadlocks.
225-
let mut rate_limits_pending_deletion_l = self.rate_limits_pending_deletion.lock();
226-
let mut peer_request_limits_l = self.peer_request_limits.lock();
227-
228207
// Go through all existing request types of the given peer and deletes the limit counters if possible or marks it for deletion.
229-
if let Some(request_limits) = peer_request_limits_l.get_mut(&peer_id) {
208+
if let Some(request_limits) = self.peer_request_limits.get_mut(&peer_id) {
230209
request_limits.retain(|req_type, rate_limit| {
231210
// Gets the requests limit and deletes it if no counter info would be lost, otherwise places it as pending deletion.
232211
if !rate_limit.can_delete(Instant::now()) {
233-
rate_limits_pending_deletion_l.insert(peer_id, *req_type, rate_limit);
212+
self.rate_limits_pending_deletion
213+
.insert(peer_id, *req_type, rate_limit);
234214
true
235215
} else {
236216
false
237217
}
238218
});
239219
// If the peer no longer has any pending rate limits, then it gets removed.
240220
if request_limits.is_empty() {
241-
peer_request_limits_l.remove(&peer_id);
221+
self.peer_request_limits.remove(&peer_id);
242222
}
243223
}
244224
}
245225

246226
/// Deletes the rate limits that were previously marked as pending if its expiration time has passed.
247227
fn clean_up(&mut self) {
248-
let mut rate_limits_pending_deletion_l = self.rate_limits_pending_deletion.lock();
249-
250228
// Iterates from the oldest to the most recent expiration date and deletes the entries that have expired.
251229
// The pending to deletion is ordered from the oldest to the most recent expiration date, thus we break early
252230
// from the loop once we find a non expired rate limit.
253-
while let Some(peer_expiration) = rate_limits_pending_deletion_l.first() {
231+
while let Some(peer_expiration) = self.rate_limits_pending_deletion.first() {
254232
let current_timestamp = Instant::now();
255233
if peer_expiration.expiration_time <= current_timestamp {
256-
let mut peer_request_limits_l = self.peer_request_limits.lock();
257-
258-
if let Some(peer_req_limits) = peer_request_limits_l
234+
if let Some(peer_req_limits) = self
235+
.peer_request_limits
259236
.get_mut(&peer_expiration.peer_id)
260237
.and_then(|peer_req_limits| {
261238
if let Some(rate_limit) = peer_req_limits.get(&peer_expiration.req_type) {
@@ -272,7 +249,7 @@ impl RateLimits {
272249
{
273250
// If the peer no longer has any pending rate limits, then it gets removed from both rate limits and pending deletion.
274251
if peer_req_limits.is_empty() {
275-
peer_request_limits_l.remove(&peer_expiration.peer_id);
252+
self.peer_request_limits.remove(&peer_expiration.peer_id);
276253
}
277254
} else {
278255
// If the information is in pending deletion, that should mean it was not deleted from peer_request_limits yet, so that
@@ -282,7 +259,7 @@ impl RateLimits {
282259
);
283260
}
284261
// Removes the entry from the pending for deletion.
285-
rate_limits_pending_deletion_l.remove_first();
262+
self.rate_limits_pending_deletion.remove_first();
286263
} else {
287264
break;
288265
}

network-libp2p/src/swarm.rs

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use libp2p::{
1616
identity::Keypair,
1717
kad::{self, store::RecordStore, GetRecordOk, InboundRequest, QueryResult, Quorum, Record},
1818
noise,
19-
request_response::{self, InboundRequestId, ResponseChannel},
19+
request_response::{self},
2020
swarm::{
2121
dial_opts::{DialOpts, PeerCondition},
2222
SwarmEvent,
@@ -30,7 +30,7 @@ use nimiq_bls::{CompressedPublicKey, KeyPair};
3030
use nimiq_network_interface::{
3131
network::{CloseReason, NetworkEvent},
3232
peer_info::PeerInfo,
33-
request::{peek_type, InboundRequestError, OutboundRequestError, RequestError, RequestType},
33+
request::{peek_type, InboundRequestError, OutboundRequestError, RequestError},
3434
};
3535
use nimiq_serde::{Deserialize, Serialize};
3636
use nimiq_time::Interval;
@@ -712,30 +712,57 @@ fn handle_event(
712712
if rate_limiting.exceeds_rate_limit(
713713
peer_id,
714714
type_id,
715-
request_id,
716715
request_rate_limit_data,
717716
) {
718-
respond_on_behalf(
719-
swarm,
720-
request_id,
721-
peer_id,
722-
type_id,
723-
channel,
724-
Err(InboundRequestError::ExceedsRateLimit),
717+
log::debug!(
718+
%request_id,
719+
%peer_id,
720+
%type_id,
721+
max_requests=%request_rate_limit_data.max_requests,
722+
time_window=?request_rate_limit_data.time_window,
723+
"Exceeded max requests rate.",
725724
);
725+
let response: Result<(), InboundRequestError> =
726+
Err(InboundRequestError::ExceedsRateLimit);
727+
if swarm
728+
.behaviour_mut()
729+
.request_response
730+
.send_response(
731+
channel,
732+
Some(response.serialize_to_vec()),
733+
)
734+
.is_err()
735+
{
736+
error!(
737+
%request_id,
738+
%peer_id,
739+
%type_id,
740+
"Could not send rate limit error response"
741+
);
742+
}
726743
} else {
727744
if type_id.requires_response() {
728745
state.response_channels.insert(request_id, channel);
729746
} else {
730747
// Respond on behalf of the actual receiver because the actual receiver isn't interested in responding.
731-
respond_on_behalf(
732-
swarm,
733-
request_id,
734-
peer_id,
735-
type_id,
736-
channel,
737-
Ok(()),
738-
);
748+
let response: Result<(), InboundRequestError> =
749+
Ok(());
750+
if swarm
751+
.behaviour_mut()
752+
.request_response
753+
.send_response(
754+
channel,
755+
Some(response.serialize_to_vec()),
756+
)
757+
.is_err()
758+
{
759+
error!(
760+
%request_id,
761+
%peer_id,
762+
%type_id,
763+
"Could not send auto response",
764+
);
765+
}
739766
}
740767
if let Err(e) = sender.try_send((
741768
request.into(),
@@ -1215,29 +1242,6 @@ pub(crate) fn verify_record(record: &Record) -> Option<DhtRecord> {
12151242
None
12161243
}
12171244

1218-
fn respond_on_behalf(
1219-
swarm: &mut NimiqSwarm,
1220-
request_id: InboundRequestId,
1221-
peer_id: PeerId,
1222-
type_id: RequestType,
1223-
channel: ResponseChannel<Option<Vec<u8>>>,
1224-
response: Result<(), InboundRequestError>,
1225-
) {
1226-
if swarm
1227-
.behaviour_mut()
1228-
.request_response
1229-
.send_response(channel, Some(response.serialize_to_vec()))
1230-
.is_err()
1231-
{
1232-
error!(
1233-
%request_id,
1234-
%peer_id,
1235-
%type_id,
1236-
"Could not send response {:?}", response
1237-
);
1238-
}
1239-
}
1240-
12411245
fn to_response_error(error: OutboundFailure) -> RequestError {
12421246
match error {
12431247
OutboundFailure::ConnectionClosed => {

0 commit comments

Comments
 (0)