diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs index fecbf4f99073fa4671496e570a5eb3ab6c0bea2e..8b2988d421fdc74c19c1ac73eb5131509b521bea 100644 --- a/bridges/bin/millau/runtime/src/lib.rs +++ b/bridges/bin/millau/runtime/src/lib.rs @@ -453,6 +453,7 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime { type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = crate::rialto_messages::ToRialtoMaximalOutboundPayloadSize; type OutboundPayload = crate::rialto_messages::ToRialtoMessagePayload; type OutboundMessageFee = Balance; @@ -484,6 +485,8 @@ impl pallet_bridge_messages::Config<WithRialtoParachainMessagesInstance> for Run type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = + crate::rialto_parachain_messages::ToRialtoParachainMaximalOutboundPayloadSize; type OutboundPayload = crate::rialto_parachain_messages::ToRialtoParachainMessagePayload; type OutboundMessageFee = Balance; diff --git a/bridges/bin/millau/runtime/src/rialto_messages.rs b/bridges/bin/millau/runtime/src/rialto_messages.rs index dad7591147d81d708a7609d2080897287df89ee1..bbcc6144f8521bc65333c85d15fb8842b9066c6c 100644 --- a/bridges/bin/millau/runtime/src/rialto_messages.rs +++ b/bridges/bin/millau/runtime/src/rialto_messages.rs @@ -79,6 +79,10 @@ pub type FromRialtoMessageDispatch = messages::target::FromBridgedChainMessageDi frame_support::traits::ConstU64<BASE_XCM_WEIGHT_TWICE>, >; +/// Maximal outbound payload size of Millau -> Rialto messages. +pub type ToRialtoMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize<WithRialtoMessageBridge>; + /// Millau <-> Rialto message bridge. #[derive(RuntimeDebug, Clone, Copy)] pub struct WithRialtoMessageBridge; @@ -145,12 +149,9 @@ impl messages::ThisChainWithMessages for Millau { } fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> { - let inbound_data_size = InboundLaneData::<bp_millau::AccountId>::encoded_size_hint( - bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); + let inbound_data_size = InboundLaneData::<bp_millau::AccountId>::encoded_size_hint(1, 1) + .and_then(|x| u32::try_from(x).ok()) + .unwrap_or(u32::MAX); MessageTransaction { dispatch_weight: bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT, @@ -346,10 +347,10 @@ mod tests { let max_incoming_inbound_lane_data_proof_size = bp_messages::InboundLaneData::<()>::encoded_size_hint( - bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as _, bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX as _, ) + .and_then(|x| u32::try_from(x).ok()) .unwrap_or(u32::MAX); pallet_bridge_messages::ensure_able_to_receive_confirmation::<Weights>( bp_millau::Millau::max_extrinsic_size(), diff --git a/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs b/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs index 26b2b5d4c48b7556cf9645fcbf8ef3f68fa91e3a..ceabe2b00018d100803606c6c598b9505377fbd7 100644 --- a/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs +++ b/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs @@ -84,6 +84,10 @@ pub type FromRialtoParachainMessageDispatch = messages::target::FromBridgedChain frame_support::traits::ConstU64<BASE_XCM_WEIGHT_TWICE>, >; +/// Maximal outbound payload size of Millau -> RialtoParachain messages. +pub type ToRialtoParachainMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize<WithRialtoParachainMessageBridge>; + /// Millau <-> RialtoParachain message bridge. #[derive(RuntimeDebug, Clone, Copy)] pub struct WithRialtoParachainMessageBridge; @@ -134,12 +138,9 @@ impl messages::ThisChainWithMessages for Millau { } fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> { - let inbound_data_size = InboundLaneData::<bp_millau::AccountId>::encoded_size_hint( - bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); + let inbound_data_size = InboundLaneData::<bp_millau::AccountId>::encoded_size_hint(1, 1) + .and_then(|x| u32::try_from(x).ok()) + .unwrap_or(u32::MAX); MessageTransaction { dispatch_weight: bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT, diff --git a/bridges/bin/rialto-parachain/runtime/src/lib.rs b/bridges/bin/rialto-parachain/runtime/src/lib.rs index 0927f138f3baf3b329e8b7e318053e0cc88ed80f..37930c3555412d816cb841799a2db93424403782 100644 --- a/bridges/bin/rialto-parachain/runtime/src/lib.rs +++ b/bridges/bin/rialto-parachain/runtime/src/lib.rs @@ -520,6 +520,7 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime { type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize; type OutboundPayload = crate::millau_messages::ToMillauMessagePayload; type OutboundMessageFee = Balance; diff --git a/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs b/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs index 8d88a4d44bcc93ae9457d380753ed8bfa901bc5a..ef8e3c657ac693ce565119675b0977f8070931ea 100644 --- a/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs +++ b/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs @@ -82,6 +82,10 @@ pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesPro pub type ToMillauMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof<bp_millau::Hash>; +/// Maximal outbound payload size of Rialto -> Millau messages. +pub type ToMillauMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize<WithMillauMessageBridge>; + /// Millau <-> RialtoParachain message bridge. #[derive(RuntimeDebug, Clone, Copy)] pub struct WithMillauMessageBridge; @@ -134,12 +138,9 @@ impl messages::ThisChainWithMessages for RialtoParachain { fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> { let inbound_data_size = - InboundLaneData::<bp_rialto_parachain::AccountId>::encoded_size_hint( - bp_rialto_parachain::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); + InboundLaneData::<bp_rialto_parachain::AccountId>::encoded_size_hint(1, 1) + .and_then(|x| u32::try_from(x).ok()) + .unwrap_or(u32::MAX); MessageTransaction { dispatch_weight: diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs index e10ddda0fb3a91b9acc7a39740af74a7e65084f6..3d468a5b4ec1cca4f4348d150d33a5b2a59602b3 100644 --- a/bridges/bin/rialto/runtime/src/lib.rs +++ b/bridges/bin/rialto/runtime/src/lib.rs @@ -437,6 +437,7 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime { type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize; type OutboundPayload = crate::millau_messages::ToMillauMessagePayload; type OutboundMessageFee = Balance; diff --git a/bridges/bin/rialto/runtime/src/millau_messages.rs b/bridges/bin/rialto/runtime/src/millau_messages.rs index fdc376be70e6ea4efad8d250f3dffba7b7549aa2..d547dde538fec8a8868f7a514bb00ee2e40e35ac 100644 --- a/bridges/bin/rialto/runtime/src/millau_messages.rs +++ b/bridges/bin/rialto/runtime/src/millau_messages.rs @@ -78,6 +78,10 @@ pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesPro pub type ToMillauMessagesDeliveryProof = messages::source::FromBridgedChainMessagesDeliveryProof<bp_millau::Hash>; +/// Maximal outbound payload size of Rialto -> Millau messages. +pub type ToMillauMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize<WithMillauMessageBridge>; + /// Millau <-> Rialto message bridge. #[derive(RuntimeDebug, Clone, Copy)] pub struct WithMillauMessageBridge; @@ -144,12 +148,9 @@ impl messages::ThisChainWithMessages for Rialto { } fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> { - let inbound_data_size = InboundLaneData::<bp_rialto::AccountId>::encoded_size_hint( - bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); + let inbound_data_size = InboundLaneData::<bp_rialto::AccountId>::encoded_size_hint(1, 1) + .and_then(|x| u32::try_from(x).ok()) + .unwrap_or(u32::MAX); MessageTransaction { dispatch_weight: bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT, @@ -343,10 +344,10 @@ mod tests { let max_incoming_inbound_lane_data_proof_size = bp_messages::InboundLaneData::<()>::encoded_size_hint( - bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as _, bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX as _, ) + .and_then(|x| u32::try_from(x).ok()) .unwrap_or(u32::MAX); pallet_bridge_messages::ensure_able_to_receive_confirmation::<Weights>( bp_rialto::Rialto::max_extrinsic_size(), diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs index a9a252118b254ebc38d99b63350dd033a70e9edb..e8f8fc1f7f03805ce24b8be1a9f19e937bd8b963 100644 --- a/bridges/bin/runtime-common/src/messages.rs +++ b/bridges/bin/runtime-common/src/messages.rs @@ -200,6 +200,15 @@ pub mod source { /// Message payload for This -> Bridged chain messages. pub type FromThisChainMessagePayload = Vec<u8>; + /// Maximal size of outbound message payload. + pub struct FromThisChainMaximalOutboundPayloadSize<B>(PhantomData<B>); + + impl<B: MessageBridge> Get<u32> for FromThisChainMaximalOutboundPayloadSize<B> { + fn get() -> u32 { + maximal_message_size::<B>() + } + } + /// Messages delivery proof from bridged chain: /// /// - hash of finalized header; @@ -216,7 +225,7 @@ pub mod source { } impl<BridgedHeaderHash> Size for FromBridgedChainMessagesDeliveryProof<BridgedHeaderHash> { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { u32::try_from( self.storage_proof .iter() @@ -529,7 +538,7 @@ pub mod target { } impl<BridgedHeaderHash> Size for FromBridgedChainMessagesProof<BridgedHeaderHash> { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { u32::try_from( self.storage_proof .iter() diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 00875bb878a823beda55a136ab96910ea8eceaaf..6624655ddc18e9ae3b73fbf576e197f5ae1ee6c5 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -16,13 +16,17 @@ //! Everything about incoming messages receival. +use crate::Config; + use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, OutboundLaneData, UnrewardedRelayer, }; use bp_runtime::messages::MessageDispatchResult; -use frame_support::RuntimeDebug; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use frame_support::{traits::Get, RuntimeDebug}; +use scale_info::{Type, TypeInfo}; use sp_std::prelude::PartialEq; /// Inbound lane storage. @@ -44,6 +48,76 @@ pub trait InboundLaneStorage { fn set_data(&mut self, data: InboundLaneData<Self::Relayer>); } +/// Inbound lane data wrapper that implements `MaxEncodedLen`. +/// +/// We have already had `MaxEncodedLen`-like functionality before, but its usage has +/// been localized and we haven't been passing bounds (maximal count of unrewarded relayer entries, +/// maximal count of unconfirmed messages) everywhere. This wrapper allows us to avoid passing +/// these generic bounds all over the code. +/// +/// The encoding of this type matches encoding of the corresponding `MessageData`. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] +pub struct StoredInboundLaneData<T: Config<I>, I: 'static>(pub InboundLaneData<T::InboundRelayer>); + +impl<T: Config<I>, I: 'static> sp_std::ops::Deref for StoredInboundLaneData<T, I> { + type Target = InboundLaneData<T::InboundRelayer>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<T: Config<I>, I: 'static> sp_std::ops::DerefMut for StoredInboundLaneData<T, I> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<T: Config<I>, I: 'static> Default for StoredInboundLaneData<T, I> { + fn default() -> Self { + StoredInboundLaneData(Default::default()) + } +} + +impl<T: Config<I>, I: 'static> From<InboundLaneData<T::InboundRelayer>> + for StoredInboundLaneData<T, I> +{ + fn from(data: InboundLaneData<T::InboundRelayer>) -> Self { + StoredInboundLaneData(data) + } +} + +impl<T: Config<I>, I: 'static> From<StoredInboundLaneData<T, I>> + for InboundLaneData<T::InboundRelayer> +{ + fn from(data: StoredInboundLaneData<T, I>) -> Self { + data.0 + } +} + +impl<T: Config<I>, I: 'static> EncodeLike<StoredInboundLaneData<T, I>> + for InboundLaneData<T::InboundRelayer> +{ +} + +impl<T: Config<I>, I: 'static> TypeInfo for StoredInboundLaneData<T, I> { + type Identity = Self; + + fn type_info() -> Type { + InboundLaneData::<T::InboundRelayer>::type_info() + } +} + +impl<T: Config<I>, I: 'static> MaxEncodedLen for StoredInboundLaneData<T, I> { + fn max_encoded_len() -> usize { + InboundLaneData::<T::InboundRelayer>::encoded_size_hint( + T::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize, + T::MaxUnconfirmedMessagesAtInboundLane::get() as usize, + ) + .unwrap_or(usize::MAX) + } +} + /// Result of single message receival. #[derive(RuntimeDebug, PartialEq, Eq)] pub enum ReceivalResult { @@ -333,7 +407,7 @@ mod tests { run_test(|| { let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID); let max_nonce = - <TestRuntime as crate::Config>::MaxUnrewardedRelayerEntriesAtInboundLane::get(); + <TestRuntime as Config>::MaxUnrewardedRelayerEntriesAtInboundLane::get(); for current_nonce in 1..max_nonce + 1 { assert_eq!( lane.receive_message::<TestMessageDispatch, _>( @@ -372,8 +446,7 @@ mod tests { fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { run_test(|| { let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID); - let max_nonce = - <TestRuntime as crate::Config>::MaxUnconfirmedMessagesAtInboundLane::get(); + let max_nonce = <TestRuntime as Config>::MaxUnconfirmedMessagesAtInboundLane::get(); for current_nonce in 1..=max_nonce { assert_eq!( lane.receive_message::<TestMessageDispatch, _>( diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index a9901018187185d4a81a8910411f796827ebfc00..e02c94d022768bd4ea4740c5769d60da2b84c305 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -37,6 +37,8 @@ // Generated by `decl_event!` #![allow(clippy::unused_unit)] +pub use inbound_lane::StoredInboundLaneData; +pub use outbound_lane::StoredMessageData; pub use weights::WeightInfo; pub use weights_ext::{ ensure_able_to_receive_confirmation, ensure_able_to_receive_message, @@ -62,9 +64,9 @@ use bp_messages::{ UnrewardedRelayersState, }; use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, Size}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - fail, + ensure, fail, traits::Get, weights::{Pays, PostDispatchInfo}, }; @@ -145,6 +147,9 @@ pub mod pallet { /// these messages are from different lanes. type MaxUnconfirmedMessagesAtInboundLane: Get<MessageNonce>; + /// Maximal size of the outbound payload. + #[pallet::constant] + type MaximalOutboundPayloadSize: Get<u32>; /// Payload type of outbound messages. This payload is dispatched on the bridged chain. type OutboundPayload: Parameter + Size; /// Message fee type of outbound messages. This fee is paid on this chain. @@ -154,7 +159,8 @@ pub mod pallet { + Parameter + SaturatingAdd + Zero - + Copy; + + Copy + + MaxEncodedLen; /// Payload type of inbound messages. This payload is dispatched on this chain. type InboundPayload: Decode; @@ -162,7 +168,7 @@ pub mod pallet { type InboundMessageFee: Decode + Zero; /// Identifier of relayer that deliver messages to this chain. Relayer reward is paid on the /// bridged chain. - type InboundRelayer: Parameter; + type InboundRelayer: Parameter + MaxEncodedLen; /// A type which can be turned into an AccountId from a 256-bit hash. /// @@ -216,7 +222,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet<T, I = ()>(PhantomData<(T, I)>); impl<T: Config<I>, I: 'static> OwnedBridgeModule<T> for Pallet<T, I> { @@ -658,6 +663,8 @@ pub mod pallet { pub enum Error<T, I = ()> { /// Pallet is not in Normal operating mode. NotOperatingNormally, + /// The message is too large to be sent over the bridge. + MessageIsTooLarge, /// Message has been treated as invalid by chain verifier. MessageRejectedByChainVerifier, /// Message has been treated as invalid by lane verifier. @@ -707,7 +714,7 @@ pub mod pallet { /// Map of lane id => inbound lane data. #[pallet::storage] pub type InboundLanes<T: Config<I>, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, LaneId, InboundLaneData<T::InboundRelayer>, ValueQuery>; + StorageMap<_, Blake2_128Concat, LaneId, StoredInboundLaneData<T, I>, ValueQuery>; /// Map of lane id => outbound lane data. #[pallet::storage] @@ -717,7 +724,7 @@ pub mod pallet { /// All queued outbound messages. #[pallet::storage] pub type OutboundMessages<T: Config<I>, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, MessageKey, MessageData<T::OutboundMessageFee>>; + StorageMap<_, Blake2_128Concat, MessageKey, StoredMessageData<T, I>>; #[pallet::genesis_config] pub struct GenesisConfig<T: Config<I>, I: 'static = ()> { @@ -756,7 +763,7 @@ pub mod pallet { lane: LaneId, nonce: MessageNonce, ) -> Option<MessageData<T::OutboundMessageFee>> { - OutboundMessages::<T, I>::get(MessageKey { lane_id: lane, nonce }) + OutboundMessages::<T, I>::get(MessageKey { lane_id: lane, nonce }).map(Into::into) } /// Prepare data, related to given inbound message. @@ -822,6 +829,12 @@ fn send_message<T: Config<I>, I: 'static>( > { ensure_normal_operating_mode::<T, I>()?; + // the most lightweigh check is the message size check + ensure!( + payload.size() < T::MaximalOutboundPayloadSize::get(), + Error::<T, I>::MessageIsTooLarge, + ); + // initially, actual (post-dispatch) weight is equal to pre-dispatch weight let mut actual_weight = T::WeightInfo::send_message_weight(&payload, T::DbWeight::get()); @@ -955,7 +968,8 @@ where // this loop is bound by `T::MaxUnconfirmedMessagesAtInboundLane` on the bridged chain let mut relayer_reward = relayers_rewards.entry(entry.relayer).or_default(); for nonce in nonce_begin..nonce_end + 1 { - let message_data = OutboundMessages::<T, I>::get(MessageKey { lane_id, nonce }) + let key = MessageKey { lane_id, nonce }; + let message_data = OutboundMessages::<T, I>::get(key) .expect("message was just confirmed; we never prune unconfirmed messages; qed"); relayer_reward.reward = relayer_reward.reward.saturating_add(&message_data.fee); relayer_reward.messages += 1; @@ -1027,7 +1041,8 @@ impl<T: Config<I>, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage< match self.cached_data.clone().into_inner() { Some(data) => data, None => { - let data = InboundLanes::<T, I>::get(&self.lane_id); + let data: InboundLaneData<T::InboundRelayer> = + InboundLanes::<T, I>::get(&self.lane_id).into(); *self.cached_data.try_borrow_mut().expect( "we're in the single-threaded environment;\ we have no recursive borrows; qed", @@ -1042,7 +1057,7 @@ impl<T: Config<I>, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage< "we're in the single-threaded environment;\ we have no recursive borrows; qed", ) = Some(data.clone()); - InboundLanes::<T, I>::insert(&self.lane_id, data) + InboundLanes::<T, I>::insert(&self.lane_id, StoredInboundLaneData::<T, I>(data)) } } @@ -1070,6 +1085,7 @@ impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag #[cfg(test)] fn message(&self, nonce: &MessageNonce) -> Option<MessageData<T::OutboundMessageFee>> { OutboundMessages::<T, I>::get(MessageKey { lane_id: self.lane_id, nonce: *nonce }) + .map(Into::into) } fn save_message( @@ -1116,8 +1132,9 @@ mod tests { message, message_payload, run_test, unrewarded_relayer, Event as TestEvent, Origin, TestMessageDeliveryAndDispatchPayment, TestMessagesDeliveryProof, TestMessagesParameter, TestMessagesProof, TestOnDeliveryConfirmed1, TestOnDeliveryConfirmed2, - TestOnMessageAccepted, TestRuntime, TokenConversionRate, PAYLOAD_REJECTED_BY_TARGET_CHAIN, - REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, + TestOnMessageAccepted, TestRuntime, TokenConversionRate, MAX_OUTBOUND_PAYLOAD_SIZE, + PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, + TEST_RELAYER_B, }; use bp_messages::{UnrewardedRelayer, UnrewardedRelayersState}; use bp_test_utils::generate_owned_bridge_module_tests; @@ -1137,7 +1154,7 @@ mod tests { fn inbound_unrewarded_relayers_state( lane: bp_messages::LaneId, ) -> bp_messages::UnrewardedRelayersState { - let inbound_lane_data = InboundLanes::<TestRuntime, ()>::get(&lane); + let inbound_lane_data = InboundLanes::<TestRuntime, ()>::get(&lane).0; let last_delivered_nonce = inbound_lane_data.last_delivered_nonce(); let relayers = inbound_lane_data.relayers; bp_messages::UnrewardedRelayersState { @@ -1443,6 +1460,27 @@ mod tests { }); } + #[test] + fn send_message_rejects_too_large_message() { + run_test(|| { + let mut message_payload = message_payload(1, 0); + // the payload isn't simply extra, so it'll definitely overflow + // `MAX_OUTBOUND_PAYLOAD_SIZE` if we add `MAX_OUTBOUND_PAYLOAD_SIZE` bytes to extra + message_payload + .extra + .extend_from_slice(&[0u8; MAX_OUTBOUND_PAYLOAD_SIZE as usize]); + assert_noop!( + Pallet::<TestRuntime>::send_message( + Origin::signed(1), + TEST_LANE_ID, + message_payload, + 0, + ), + Error::<TestRuntime, ()>::MessageIsTooLarge, + ); + }) + } + #[test] fn chain_verifier_rejects_invalid_message_in_send_message() { run_test(|| { @@ -1502,7 +1540,7 @@ mod tests { REGULAR_PAYLOAD.declared_weight, )); - assert_eq!(InboundLanes::<TestRuntime>::get(TEST_LANE_ID).last_delivered_nonce(), 1); + assert_eq!(InboundLanes::<TestRuntime>::get(TEST_LANE_ID).0.last_delivered_nonce(), 1); }); } @@ -1547,7 +1585,7 @@ mod tests { )); assert_eq!( - InboundLanes::<TestRuntime>::get(TEST_LANE_ID), + InboundLanes::<TestRuntime>::get(TEST_LANE_ID).0, InboundLaneData { last_confirmed_nonce: 9, relayers: vec![ @@ -2146,8 +2184,8 @@ mod tests { run_test(|| { let mut small_payload = message_payload(0, 100); let mut large_payload = message_payload(1, 100); - small_payload.extra = vec![1; 100]; - large_payload.extra = vec![2; 16_384]; + small_payload.extra = vec![1; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 10]; + large_payload.extra = vec![2; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 5]; assert_ok!(Pallet::<TestRuntime>::send_message( Origin::signed(1), diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs index 33c6eae6eb23b06c0f80fbdfe21441e3bea13f9e..b836517e419a24399ce0fcaf034055fdb9a477de 100644 --- a/bridges/modules/messages/src/mock.rs +++ b/bridges/modules/messages/src/mock.rs @@ -174,6 +174,7 @@ impl Config for TestRuntime { type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + type MaximalOutboundPayloadSize = frame_support::traits::ConstU32<MAX_OUTBOUND_PAYLOAD_SIZE>; type OutboundPayload = TestPayload; type OutboundMessageFee = TestMessageFee; @@ -205,11 +206,14 @@ impl SenderOrigin<AccountId> for Origin { } impl Size for TestPayload { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { 16 + self.extra.len() as u32 } } +/// Maximal outbound payload size. +pub const MAX_OUTBOUND_PAYLOAD_SIZE: u32 = 4096; + /// Account that has balance to use in tests. pub const ENDOWED_ACCOUNT: AccountId = 0xDEAD; @@ -244,7 +248,7 @@ pub struct TestMessagesProof { } impl Size for TestMessagesProof { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { 0 } } @@ -271,7 +275,7 @@ impl From<Result<Vec<Message<TestMessageFee>>, ()>> for TestMessagesProof { pub struct TestMessagesDeliveryProof(pub Result<(LaneId, InboundLaneData<TestRelayer>), ()>); impl Size for TestMessagesDeliveryProof { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { 0 } } diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index 041dec214b11cef1f000c73e60ca0137b7006f73..5f977b2f2e297f0b48936cc145f0f4e12cacae49 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -16,12 +16,16 @@ //! Everything about outgoing messages sending. +use crate::Config; + use bitvec::prelude::*; use bp_messages::{ DeliveredMessages, DispatchResultsBitVec, LaneId, MessageData, MessageNonce, OutboundLaneData, UnrewardedRelayer, }; -use frame_support::RuntimeDebug; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use frame_support::{traits::Get, RuntimeDebug}; +use scale_info::{Type, TypeInfo}; use sp_std::collections::vec_deque::VecDeque; /// Outbound lane storage. @@ -44,6 +48,66 @@ pub trait OutboundLaneStorage { fn remove_message(&mut self, nonce: &MessageNonce); } +/// Outbound message data wrapper that implements `MaxEncodedLen`. +/// +/// We have already had `MaxEncodedLen`-like functionality before, but its usage has +/// been localized and we haven't been passing it everywhere. This wrapper allows us +/// to avoid passing these generic bounds all over the code. +/// +/// The encoding of this type matches encoding of the corresponding `MessageData`. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] +pub struct StoredMessageData<T: Config<I>, I: 'static>(pub MessageData<T::OutboundMessageFee>); + +impl<T: Config<I>, I: 'static> sp_std::ops::Deref for StoredMessageData<T, I> { + type Target = MessageData<T::OutboundMessageFee>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<T: Config<I>, I: 'static> sp_std::ops::DerefMut for StoredMessageData<T, I> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<T: Config<I>, I: 'static> From<MessageData<T::OutboundMessageFee>> + for StoredMessageData<T, I> +{ + fn from(data: MessageData<T::OutboundMessageFee>) -> Self { + StoredMessageData(data) + } +} + +impl<T: Config<I>, I: 'static> From<StoredMessageData<T, I>> + for MessageData<T::OutboundMessageFee> +{ + fn from(data: StoredMessageData<T, I>) -> Self { + data.0 + } +} + +impl<T: Config<I>, I: 'static> TypeInfo for StoredMessageData<T, I> { + type Identity = Self; + + fn type_info() -> Type { + MessageData::<T::OutboundMessageFee>::type_info() + } +} + +impl<T: Config<I>, I: 'static> EncodeLike<StoredMessageData<T, I>> + for MessageData<T::OutboundMessageFee> +{ +} + +impl<T: Config<I>, I: 'static> MaxEncodedLen for StoredMessageData<T, I> { + fn max_encoded_len() -> usize { + T::OutboundMessageFee::max_encoded_len() + .saturating_add(T::MaximalOutboundPayloadSize::get() as usize) + } +} + /// Result of messages receival confirmation. #[derive(RuntimeDebug, PartialEq, Eq)] pub enum ReceivalConfirmationResult { diff --git a/bridges/modules/messages/src/weights_ext.rs b/bridges/modules/messages/src/weights_ext.rs index 483a22eda1d6b8cf3079973f74375c666efbfb19..80ac810e8c921c35c58007720453a72fde424735 100644 --- a/bridges/modules/messages/src/weights_ext.rs +++ b/bridges/modules/messages/src/weights_ext.rs @@ -199,7 +199,7 @@ pub trait WeightInfoExt: WeightInfo { /// Weight of message send extrinsic. fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight { let transaction_overhead = Self::send_message_overhead(); - let message_size_overhead = Self::send_message_size_overhead(message.size_hint()); + let message_size_overhead = Self::send_message_size_overhead(message.size()); let call_back_overhead = Self::single_message_callback_overhead(db_weight); transaction_overhead @@ -225,7 +225,7 @@ pub trait WeightInfoExt: WeightInfo { let expected_proof_size = EXPECTED_DEFAULT_MESSAGE_LENGTH .saturating_mul(messages_count.saturating_sub(1)) .saturating_add(Self::expected_extra_storage_proof_size()); - let actual_proof_size = proof.size_hint(); + let actual_proof_size = proof.size(); let proof_size_overhead = Self::storage_proof_size_overhead( actual_proof_size.saturating_sub(expected_proof_size), ); @@ -253,7 +253,7 @@ pub trait WeightInfoExt: WeightInfo { // proof size overhead weight let expected_proof_size = Self::expected_extra_storage_proof_size(); - let actual_proof_size = proof.size_hint(); + let actual_proof_size = proof.size(); let proof_size_overhead = Self::storage_proof_size_overhead( actual_proof_size.saturating_sub(expected_proof_size), ); diff --git a/bridges/modules/parachains/src/weights_ext.rs b/bridges/modules/parachains/src/weights_ext.rs index 3f3815eed96c620aaa724a754fc5f6dbb8d4db6c..f345762dad9c8166500ea0d0872e61847fcdc84b 100644 --- a/bridges/modules/parachains/src/weights_ext.rs +++ b/bridges/modules/parachains/src/weights_ext.rs @@ -56,7 +56,7 @@ pub trait WeightInfoExt: WeightInfo { let expected_proof_size = parachains_count .saturating_mul(DEFAULT_PARACHAIN_HEAD_SIZE) .saturating_add(Self::expected_extra_storage_proof_size()); - let actual_proof_size = proof.size_hint(); + let actual_proof_size = proof.size(); let proof_size_overhead = Self::storage_proof_size_overhead( actual_proof_size.saturating_sub(expected_proof_size), ); diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs index 240c2daaa98c16c1a475620e0554b065b38a2d15..48c80e7017a0801b50a30abe245956695e41c9d4 100644 --- a/bridges/primitives/chain-millau/src/lib.rs +++ b/bridges/primitives/chain-millau/src/lib.rs @@ -53,9 +53,6 @@ pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; /// Can be computed by subtracting encoded call size from raw transaction size. pub const TX_EXTRA_BYTES: u32 = 103; -/// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id. -pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32; - /// Maximum weight of single Millau block. /// /// This represents 0.5 seconds of compute assuming a target block time of six seconds. @@ -363,19 +360,3 @@ sp_api::decl_runtime_apis! { ) -> Vec<InboundMessageDetails>; } } - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::codec::Encode; - - #[test] - fn maximal_account_size_does_not_overflow_constant() { - assert!( - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE as usize >= AccountId::from([0u8; 32]).encode().len(), - "Actual maximal size of encoded AccountId ({}) overflows expected ({})", - AccountId::from([0u8; 32]).encode().len(), - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - ); - } -} diff --git a/bridges/primitives/chain-rialto-parachain/src/lib.rs b/bridges/primitives/chain-rialto-parachain/src/lib.rs index 38b4192bf348c5fe37176d881bf6eda549d81504..9e54744f2d29b38cffa69c0631552bc10839cae6 100644 --- a/bridges/primitives/chain-rialto-parachain/src/lib.rs +++ b/bridges/primitives/chain-rialto-parachain/src/lib.rs @@ -50,9 +50,6 @@ pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; /// Can be computed by subtracting encoded call size from raw transaction size. pub const TX_EXTRA_BYTES: u32 = 104; -/// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id. -pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32; - /// Maximal weight of single RialtoParachain block. /// /// This represents two seconds of compute assuming a target block time of six seconds. @@ -290,19 +287,3 @@ sp_api::decl_runtime_apis! { ) -> Vec<InboundMessageDetails>; } } - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::codec::Encode; - - #[test] - fn maximal_account_size_does_not_overflow_constant() { - assert!( - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE as usize >= AccountId::from([0u8; 32]).encode().len(), - "Actual maximal size of encoded AccountId ({}) overflows expected ({})", - AccountId::from([0u8; 32]).encode().len(), - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - ); - } -} diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs index e5c5ebab76ff50f459ff11f88a1a4c809dbc83df..9acc9f9f9a6dbc216822e781ee180651372c0cc9 100644 --- a/bridges/primitives/chain-rialto/src/lib.rs +++ b/bridges/primitives/chain-rialto/src/lib.rs @@ -44,9 +44,6 @@ pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; /// Can be computed by subtracting encoded call size from raw transaction size. pub const TX_EXTRA_BYTES: u32 = 104; -/// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id. -pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32; - /// Maximal weight of single Rialto block. /// /// This represents two seconds of compute assuming a target block time of six seconds. @@ -311,19 +308,3 @@ sp_api::decl_runtime_apis! { ) -> Vec<InboundMessageDetails>; } } - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::codec::Encode; - - #[test] - fn maximal_account_size_does_not_overflow_constant() { - assert!( - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE as usize >= AccountId::from([0u8; 32]).encode().len(), - "Actual maximal size of encoded AccountId ({}) overflows expected ({})", - AccountId::from([0u8; 32]).encode().len(), - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - ); - } -} diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 455caad729b70357b904115eb0b79f114cbfd111..ad1dbd38be9017cbe90d8983173f9b10548ab7a9 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -21,8 +21,8 @@ #![allow(clippy::too_many_arguments)] use bitvec::prelude::*; -use bp_runtime::messages::DispatchFeePayment; -use codec::{Decode, Encode}; +use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, OperatingMode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; use sp_std::{collections::vec_deque::VecDeque, prelude::*}; @@ -32,11 +32,10 @@ pub mod storage_keys; pub mod target_chain; // Weight is reexported to avoid additional frame-support dependencies in related crates. -use bp_runtime::{BasicOperatingMode, OperatingMode}; pub use frame_support::weights::Weight; /// Messages pallet operating mode. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum MessagesOperatingMode { /// Basic operating mode (Normal/Halted) @@ -89,7 +88,7 @@ pub type BridgeMessageId = (LaneId, MessageNonce); pub type MessagePayload = Vec<u8>; /// Message key (unique message identifier) as it is stored in the storage. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct MessageKey { /// ID of the message lane. pub lane_id: LaneId, @@ -158,13 +157,13 @@ impl<RelayerId> InboundLaneData<RelayerId> { /// Returns approximate size of the struct, given a number of entries in the `relayers` set and /// size of each entry. /// - /// Returns `None` if size overflows `u32` limits. - pub fn encoded_size_hint( - relayer_id_encoded_size: u32, - relayers_entries: u32, - messages_count: u32, - ) -> Option<u32> { - let message_nonce_size = 8; + /// Returns `None` if size overflows `usize` limits. + pub fn encoded_size_hint(relayers_entries: usize, messages_count: usize) -> Option<usize> + where + RelayerId: MaxEncodedLen, + { + let message_nonce_size = MessageNonce::max_encoded_len(); + let relayer_id_encoded_size = RelayerId::max_encoded_len(); let relayers_entry_size = relayer_id_encoded_size.checked_add(2 * message_nonce_size)?; let relayers_size = relayers_entries.checked_mul(relayers_entry_size)?; let dispatch_results_per_byte = 8; @@ -305,7 +304,7 @@ pub struct UnrewardedRelayersState { } /// Outbound lane data. -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct OutboundLaneData { /// Nonce of the oldest message that we haven't yet pruned. May point to not-yet-generated /// message if all sent messages are already pruned. @@ -379,11 +378,8 @@ mod tests { (13u8, 128u8), ]; for (relayer_entries, messages_count) in test_cases { - let expected_size = InboundLaneData::<u8>::encoded_size_hint( - 1, - relayer_entries as _, - messages_count as _, - ); + let expected_size = + InboundLaneData::<u8>::encoded_size_hint(relayer_entries as _, messages_count as _); let actual_size = InboundLaneData { relayers: (1u8..=relayer_entries) .map(|i| { diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index 8db1af2fd3367887c411a22a90f0353d7ac7af0b..4b0ef430ad5336b0fdf202be880540c3d51cda61 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -65,11 +65,6 @@ pub mod parachains; /// at next runtime upgrade. pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; -/// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id. -/// -/// All polkadot-like chains are using same crypto. -pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32; - /// All Polkadot-like chains allow normal extrinsics to fill block up to 75 percent. /// /// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate. @@ -429,18 +424,6 @@ pub fn account_info_storage_key(id: &AccountId) -> Vec<u8> { #[cfg(test)] mod tests { use super::*; - use sp_runtime::codec::Encode; - - #[test] - fn maximal_encoded_account_id_size_is_correct() { - let actual_size = AccountId::from([0u8; 32]).encode().len(); - assert!( - actual_size <= MAXIMAL_ENCODED_ACCOUNT_ID_SIZE as usize, - "Actual size of encoded account id for Polkadot-like chains ({}) is larger than expected {}", - actual_size, - MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - ); - } #[test] fn should_generate_storage_key() { diff --git a/bridges/primitives/polkadot-core/src/parachains.rs b/bridges/primitives/polkadot-core/src/parachains.rs index af05e7e98582bae16ec217bdf0e108bdeaffa185..59b895065e179c5b16e770fc48b05a201aea7e2a 100644 --- a/bridges/primitives/polkadot-core/src/parachains.rs +++ b/bridges/primitives/polkadot-core/src/parachains.rs @@ -93,7 +93,7 @@ pub type ParaHasher = crate::Hasher; pub struct ParaHeadsProof(pub Vec<Vec<u8>>); impl Size for ParaHeadsProof { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { u32::try_from(self.0.iter().fold(0usize, |sum, node| sum.saturating_add(node.len()))) .unwrap_or(u32::MAX) } diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 4b69bbdb688287be0156bd3c1248790cf4bacc09..2849e346da42658324d0e79833b0f85ece2e06ba 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, FullCodec}; +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use frame_support::{ log, pallet_prelude::DispatchResult, PalletError, RuntimeDebug, StorageHasher, StorageValue, }; @@ -139,21 +139,18 @@ pub fn derive_relayer_fund_account_id(bridge_id: ChainId) -> H256 { /// Anything that has size. pub trait Size { - /// Return approximate size of this object (in bytes). - /// - /// This function should be lightweight. The result should not necessary be absolutely - /// accurate. - fn size_hint(&self) -> u32; + /// Return size of this object (in bytes). + fn size(&self) -> u32; } impl Size for () { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { 0 } } impl Size for Vec<u8> { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { self.len() as _ } } @@ -162,7 +159,7 @@ impl Size for Vec<u8> { pub struct PreComputedSize(pub usize); impl Size for PreComputedSize { - fn size_hint(&self) -> u32 { + fn size(&self) -> u32 { u32::try_from(self.0).unwrap_or(u32::MAX) } } @@ -308,7 +305,7 @@ pub trait OperatingMode: Send + Copy + Debug + FullCodec { } /// Basic operating modes for a bridges module (Normal/Halted). -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub enum BasicOperatingMode { /// Normal mode, when all operations are allowed. diff --git a/bridges/relays/client-kusama/src/lib.rs b/bridges/relays/client-kusama/src/lib.rs index 8011cbc564666ef3989507f8392b47770aca87e0..31eb3f40e33941050e4890ceada69c4dd7ff7740 100644 --- a/bridges/relays/client-kusama/src/lib.rs +++ b/bridges/relays/client-kusama/src/lib.rs @@ -63,7 +63,6 @@ impl Chain for Kusama { bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_kusama::SignedBlock; type Call = crate::runtime::Call; diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs index 36ad9df69d69b16b713f8cabd5e9639556daae74..4250bd34de75f6f7830679bea9c5bdba317f65b0 100644 --- a/bridges/relays/client-millau/src/lib.rs +++ b/bridges/relays/client-millau/src/lib.rs @@ -82,7 +82,6 @@ impl Chain for Millau { bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = millau_runtime::SignedBlock; type Call = millau_runtime::Call; diff --git a/bridges/relays/client-polkadot/src/lib.rs b/bridges/relays/client-polkadot/src/lib.rs index 745bbc44fb6fbf67c0f1699ec9d930370c3d62d7..35d876f54638042c0e439c8d7468b6fe1bbd3c96 100644 --- a/bridges/relays/client-polkadot/src/lib.rs +++ b/bridges/relays/client-polkadot/src/lib.rs @@ -63,7 +63,6 @@ impl Chain for Polkadot { bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_polkadot::SignedBlock; type Call = crate::runtime::Call; diff --git a/bridges/relays/client-rialto-parachain/src/lib.rs b/bridges/relays/client-rialto-parachain/src/lib.rs index 74393211d93770854b5e5d74734adffe861cbe5c..a6f34201ca5f5ff115cab0764e292bd22410a4b2 100644 --- a/bridges/relays/client-rialto-parachain/src/lib.rs +++ b/bridges/relays/client-rialto-parachain/src/lib.rs @@ -63,8 +63,6 @@ impl Chain for RialtoParachain { bp_rialto_parachain::BEST_FINALIZED_RIALTO_PARACHAIN_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = - bp_rialto_parachain::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = rialto_parachain_runtime::SignedBlock; type Call = rialto_parachain_runtime::Call; diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs index 7ddaaabe3611c1397fef4615609598c1ceb02760..67b96563817e3b1485078c6f0c74eb600d998d97 100644 --- a/bridges/relays/client-rialto/src/lib.rs +++ b/bridges/relays/client-rialto/src/lib.rs @@ -63,7 +63,6 @@ impl Chain for Rialto { bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = rialto_runtime::SignedBlock; type Call = rialto_runtime::Call; diff --git a/bridges/relays/client-rococo/src/lib.rs b/bridges/relays/client-rococo/src/lib.rs index 161b719516ae9dcf523ffd91643c37873c5d9fd9..42a22a8f268bd040bd690d892200afe119b7060a 100644 --- a/bridges/relays/client-rococo/src/lib.rs +++ b/bridges/relays/client-rococo/src/lib.rs @@ -66,7 +66,6 @@ impl Chain for Rococo { bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_rococo::SignedBlock; type Call = crate::runtime::Call; diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs index d7f441b73ac2c6ab2b60e514980978364c024e2d..adfecff4eed185abc8e063d97f681905231a3436 100644 --- a/bridges/relays/client-substrate/src/chain.rs +++ b/bridges/relays/client-substrate/src/chain.rs @@ -52,8 +52,6 @@ pub trait Chain: ChainBase + Clone { const AVERAGE_BLOCK_INTERVAL: Duration; /// Maximal expected storage proof overhead (in bytes). const STORAGE_PROOF_OVERHEAD: u32; - /// Maximal size (in bytes) of SCALE-encoded account id on this chain. - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32; /// Block type. type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>; diff --git a/bridges/relays/client-substrate/src/test_chain.rs b/bridges/relays/client-substrate/src/test_chain.rs index f97df643a208d33d1e6954c3865ffab07796d050..f9a9e2455ed99ddd12d8f038853e79dd41897ed4 100644 --- a/bridges/relays/client-substrate/src/test_chain.rs +++ b/bridges/relays/client-substrate/src/test_chain.rs @@ -55,7 +55,6 @@ impl Chain for TestChain { const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestMethod"; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); const STORAGE_PROOF_OVERHEAD: u32 = 0; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0; type SignedBlock = sp_runtime::generic::SignedBlock< sp_runtime::generic::Block<Self::Header, sp_runtime::OpaqueExtrinsic>, diff --git a/bridges/relays/client-westend/src/lib.rs b/bridges/relays/client-westend/src/lib.rs index cd2e3caab61826749a7177ff04fc285c518d5e09..4b27bfeb82d8ac02e25fe6b092eab173e3811a1c 100644 --- a/bridges/relays/client-westend/src/lib.rs +++ b/bridges/relays/client-westend/src/lib.rs @@ -58,7 +58,6 @@ impl Chain for Westend { bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_westend::SignedBlock; type Call = bp_westend::Call; @@ -117,7 +116,6 @@ impl Chain for Westmint { bp_westend::BEST_FINALIZED_WESTMINT_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_westend::SignedBlock; type Call = bp_westend::Call; diff --git a/bridges/relays/client-wococo/src/lib.rs b/bridges/relays/client-wococo/src/lib.rs index eb20e40f483e65d359467da13c73cc2815f2ec39..3c96a80b60db57bd7199bc78ef2fe7d713736045 100644 --- a/bridges/relays/client-wococo/src/lib.rs +++ b/bridges/relays/client-wococo/src/lib.rs @@ -66,7 +66,6 @@ impl Chain for Wococo { bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE; - const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; type SignedBlock = bp_wococo::SignedBlock; type Call = crate::runtime::Call; diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs index 5a6b6554e4bae633e481bf1238afd01638036c6f..8ed8367d35d7cf691a663b2e62360043eb007f85 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs @@ -467,12 +467,10 @@ where /// affect the call weight - we only care about its size. fn prepare_dummy_messages_delivery_proof<SC: Chain, TC: Chain>( ) -> SubstrateMessagesDeliveryProof<TC> { - let single_message_confirmation_size = bp_messages::InboundLaneData::<()>::encoded_size_hint( - SC::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - 1, - 1, - ) - .unwrap_or(u32::MAX); + let single_message_confirmation_size = + bp_messages::InboundLaneData::<()>::encoded_size_hint(1, 1) + .and_then(|x| u32::try_from(x).ok()) + .unwrap_or(u32::MAX); let proof_size = TC::STORAGE_PROOF_OVERHEAD.saturating_add(single_message_confirmation_size); ( UnrewardedRelayersState { @@ -651,6 +649,7 @@ fn make_message_details_map<C: Chain>( mod tests { use super::*; use bp_runtime::messages::DispatchFeePayment; + use codec::MaxEncodedLen; use relay_rococo_client::Rococo; use relay_wococo_client::Wococo; @@ -765,7 +764,7 @@ mod tests { #[test] fn prepare_dummy_messages_delivery_proof_works() { let expected_minimal_size = - Wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE + Rococo::STORAGE_PROOF_OVERHEAD; + bp_wococo::AccountId::max_encoded_len() as u32 + Rococo::STORAGE_PROOF_OVERHEAD; let dummy_proof = prepare_dummy_messages_delivery_proof::<Wococo, Rococo>(); assert!( dummy_proof.1.encode().len() as u32 > expected_minimal_size,