From b8f4086095142d3941ca93d392942922b3a6c455 Mon Sep 17 00:00:00 2001
From: Serban Iorga <serban@parity.io>
Date: Thu, 13 Apr 2023 10:38:34 +0300
Subject: [PATCH] Define `RangeInclusiveExt` (#2037)

* Define RangeInclusiveExt

* Use RangeInclusiveExt

* Add docs
---
 .../runtime-common/src/messages_call_ext.rs   | 16 --------------
 .../src/refund_relayer_extension.rs           |  6 +++---
 bridges/modules/messages/src/lib.rs           |  7 ++-----
 bridges/primitives/messages/src/lib.rs        |  8 ++-----
 bridges/primitives/runtime/src/lib.rs         | 21 +++++++++++++++++--
 5 files changed, 26 insertions(+), 32 deletions(-)

diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs
index b208a9d02b4..1ca1bab6a35 100644
--- a/bridges/bin/runtime-common/src/messages_call_ext.rs
+++ b/bridges/bin/runtime-common/src/messages_call_ext.rs
@@ -115,22 +115,6 @@ pub enum CallInfo {
 	ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo),
 }
 
-impl CallInfo {
-	/// Returns number of messages, bundled with this transaction.
-	pub fn bundled_messages(&self) -> MessageNonce {
-		let bundled_range = match *self {
-			Self::ReceiveMessagesProof(ref info) => &info.base.bundled_range,
-			Self::ReceiveMessagesDeliveryProof(ref info) => &info.0.bundled_range,
-		};
-
-		bundled_range
-			.end()
-			.checked_sub(*bundled_range.start())
-			.map(|d| d.saturating_add(1))
-			.unwrap_or(0)
-	}
-}
-
 /// Helper struct that provides methods for working with a call supported by `CallInfo`.
 pub struct CallHelper<T: Config<I>, I: 'static> {
 	pub _phantom_data: sp_std::marker::PhantomData<(T, I)>,
diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs
index 1aae6a16a3c..925fea2a743 100644
--- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs
+++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs
@@ -24,7 +24,7 @@ use crate::messages_call_ext::{
 };
 use bp_messages::LaneId;
 use bp_relayers::{RewardsAccountOwner, RewardsAccountParams};
-use bp_runtime::StaticStrProvider;
+use bp_runtime::{RangeInclusiveExt, StaticStrProvider};
 use codec::{Decode, Encode};
 use frame_support::{
 	dispatch::{CallableCallFor, DispatchInfo, Dispatchable, PostDispatchInfo},
@@ -319,9 +319,9 @@ where
 		if let Some(parsed_call) = parsed_call {
 			// we give delivery transactions some boost, that depends on number of messages inside
 			let messages_call_info = parsed_call.messages_call_info();
-			if let MessagesCallInfo::ReceiveMessagesProof(_) = messages_call_info {
+			if let MessagesCallInfo::ReceiveMessagesProof(info) = messages_call_info {
 				// compute total number of messages in transaction
-				let bundled_messages = messages_call_info.bundled_messages();
+				let bundled_messages = info.base.bundled_range.checked_len().unwrap_or(0);
 
 				// a quick check to avoid invalid high-priority transactions
 				if bundled_messages <= Runtime::MaxUnconfirmedMessagesAtInboundLane::get() {
diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs
index 3404ba0b219..5b1b98ea7a1 100644
--- a/bridges/modules/messages/src/lib.rs
+++ b/bridges/modules/messages/src/lib.rs
@@ -90,6 +90,7 @@ pub const LOG_TARGET: &str = "runtime::bridge-messages";
 pub mod pallet {
 	use super::*;
 	use bp_messages::{ReceivalResult, ReceivedMessages};
+	use bp_runtime::RangeInclusiveExt;
 	use frame_support::pallet_prelude::*;
 	use frame_system::pallet_prelude::*;
 
@@ -514,11 +515,7 @@ pub mod pallet {
 				);
 				relayers_state.total_messages = sp_std::cmp::min(
 					relayers_state.total_messages,
-					received_range
-						.end()
-						.checked_sub(*received_range.start())
-						.and_then(|x| x.checked_add(1))
-						.unwrap_or(MessageNonce::MAX),
+					received_range.checked_len().unwrap_or(MessageNonce::MAX),
 				);
 			};
 
diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs
index c877c9cdf2c..9481a4b9bb8 100644
--- a/bridges/primitives/messages/src/lib.rs
+++ b/bridges/primitives/messages/src/lib.rs
@@ -21,7 +21,7 @@
 #![allow(clippy::too_many_arguments)]
 
 use bitvec::prelude::*;
-use bp_runtime::{BasicOperatingMode, OperatingMode};
+use bp_runtime::{BasicOperatingMode, OperatingMode, RangeInclusiveExt};
 use codec::{Decode, Encode, MaxEncodedLen};
 use frame_support::RuntimeDebug;
 use scale_info::TypeInfo;
@@ -347,11 +347,7 @@ impl DeliveredMessages {
 
 	/// Return total count of delivered messages.
 	pub fn total_messages(&self) -> MessageNonce {
-		if self.end >= self.begin {
-			self.end - self.begin + 1
-		} else {
-			0
-		}
+		(self.begin..=self.end).checked_len().unwrap_or(0)
 	}
 
 	/// Note new dispatched message.
diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs
index d4f551ce57a..df77745bc02 100644
--- a/bridges/primitives/runtime/src/lib.rs
+++ b/bridges/primitives/runtime/src/lib.rs
@@ -27,7 +27,7 @@ use frame_system::RawOrigin;
 use scale_info::TypeInfo;
 use sp_core::storage::StorageKey;
 use sp_runtime::traits::{BadOrigin, Header as HeaderT, UniqueSaturatedInto};
-use sp_std::{convert::TryFrom, fmt::Debug, vec, vec::Vec};
+use sp_std::{convert::TryFrom, fmt::Debug, ops::RangeInclusive, vec, vec::Vec};
 
 pub use chain::{
 	AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf,
@@ -35,7 +35,7 @@ pub use chain::{
 	UnderlyingChainProvider,
 };
 pub use frame_support::storage::storage_prefix as storage_value_final_key;
-use num_traits::{CheckedSub, One};
+use num_traits::{CheckedAdd, CheckedSub, One};
 pub use storage_proof::{
 	record_all_keys as record_all_trie_keys, Error as StorageProofError,
 	ProofSize as StorageProofSize, RawStorageProof, StorageProofChecker,
@@ -523,6 +523,23 @@ impl<T> Debug for StrippableError<T> {
 	}
 }
 
+/// A trait defining helper methods for `RangeInclusive` (start..=end)
+pub trait RangeInclusiveExt<Idx> {
+	/// Computes the length of the `RangeInclusive`, checking for underflow and overflow.
+	fn checked_len(&self) -> Option<Idx>;
+}
+
+impl<Idx> RangeInclusiveExt<Idx> for RangeInclusive<Idx>
+where
+	Idx: CheckedSub + CheckedAdd + One,
+{
+	fn checked_len(&self) -> Option<Idx> {
+		self.end()
+			.checked_sub(self.start())
+			.and_then(|len| len.checked_add(&Idx::one()))
+	}
+}
+
 #[cfg(test)]
 mod tests {
 	use super::*;
-- 
GitLab