diff --git a/beacon_node/eth2_libp2p/src/rpc/rate_limiter.rs b/beacon_node/eth2_libp2p/src/rpc/rate_limiter.rs index bb41246b1e4..bc34ce832e7 100644 --- a/beacon_node/eth2_libp2p/src/rpc/rate_limiter.rs +++ b/beacon_node/eth2_libp2p/src/rpc/rate_limiter.rs @@ -189,7 +189,30 @@ impl RPCRateLimiter { request: &RPCRequest, ) -> Result<(), RateLimitedErr> { let time_since_start = self.init_time.elapsed(); - let tokens = request.expected_responses().max(1); + let mut tokens = request.expected_responses().max(1); + + // Increase the rate limit for blocks by range requests with large step counts. + // We count to tokens as a quadratic increase with step size. + // Using (step_size/5)^2 + 1 as penalty factor allows step sizes of 1-4 to have no penalty + // but step sizes higher than this add a quadratic penalty. + // Penalty's go: + // Step size | Penalty Factor + // 1 | 1 + // 2 | 1 + // 3 | 1 + // 4 | 1 + // 5 | 2 + // 6 | 2 + // 7 | 2 + // 8 | 3 + // 9 | 4 + // 10 | 5 + + if let RPCRequest::BlocksByRange(bbr_req) = request { + let penalty_factor = (bbr_req.step as f64 / 5.0).powi(2) as u64 + 1; + tokens *= penalty_factor; + } + let check = |limiter: &mut Limiter| limiter.allows(time_since_start, peer_id, tokens); let limiter = match request.protocol() { diff --git a/beacon_node/network/src/router/processor.rs b/beacon_node/network/src/router/processor.rs index f99cea0bb6f..9d83c55766d 100644 --- a/beacon_node/network/src/router/processor.rs +++ b/beacon_node/network/src/router/processor.rs @@ -374,22 +374,29 @@ impl Processor { } }; - // pick out the required blocks, ignoring skip-slots and stepping by the step parameter; + // Pick out the required blocks, ignoring skip-slots and stepping by the step parameter. + // + // NOTE: We don't mind if req.count * req.step overflows as it just ends the iterator early and + // the peer will get less blocks. + // The step parameter is quadratically weighted in the filter, so large values should be + // prevented before reaching this point. let mut last_block_root = None; let maybe_block_roots = process_results(forwards_block_root_iter, |iter| { - iter.take_while(|(_, slot)| slot.as_u64() < req.start_slot + req.count * req.step) - // map skip slots to None - .map(|(root, _)| { - let result = if Some(root) == last_block_root { - None - } else { - Some(root) - }; - last_block_root = Some(root); - result - }) - .step_by(req.step as usize) - .collect::>>() + iter.take_while(|(_, slot)| { + slot.as_u64() < req.start_slot.saturating_add(req.count * req.step) + }) + // map skip slots to None + .map(|(root, _)| { + let result = if Some(root) == last_block_root { + None + } else { + Some(root) + }; + last_block_root = Some(root); + result + }) + .step_by(req.step as usize) + .collect::>>() }); let block_roots = match maybe_block_roots {