From d988e383dd2732e7e6daabcbbd614b69319e1490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 19 Jan 2022 16:57:03 +0100 Subject: [PATCH] xcmp-queue: Fix handling of encoded blobs (#889) * xcmp-queue: Fix handling of encoded blobs With #701 we tried to fix some infinite loop related to encoded blobs, however that lead actually to not being able to process encoded blobs at all. The reason for this is that `decode_all` doesn't consume the given input. The point of this function is that it returns an error if the data couldn't be decoded or there is still data left. However, this means that the check `remaining_fragments.len() < last_remaining_fragments.len()` would always fail. We remove the while loop, because we decode the entire fragment anyway or it fails. Aka, we don't need to loop here. Next we remove the broken check and we directly reset the `remaining_fragments` (because `decode_all` doesn't consume anything). * Restore correct behavior We need to use a while loop, because there can be multiple `Vec`s. We also need to use `decode`, because `decode_all` would otherwise return an error if the input is not empty afterwards. * Remove unused import --- cumulus/pallets/xcmp-queue/src/lib.rs | 40 ++++++++++++------------- cumulus/pallets/xcmp-queue/src/tests.rs | 7 +++-- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index cab3a18e42..057da50d72 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -33,7 +33,7 @@ mod mock; #[cfg(test)] mod tests; -use codec::{Decode, DecodeAll, DecodeLimit, Encode}; +use codec::{Decode, DecodeLimit, Encode}; use cumulus_primitives_core::{ relay_chain::BlockNumber as RelayBlockNumber, ChannelStatus, GetChannelInfo, MessageSendError, ParaId, XcmpMessageFormat, XcmpMessageHandler, XcmpMessageSource, @@ -538,26 +538,24 @@ impl Pallet { XcmpMessageFormat::ConcatenatedEncodedBlob => { while !remaining_fragments.is_empty() { last_remaining_fragments = remaining_fragments; - match >::decode_all(&mut remaining_fragments) { - Ok(blob) if remaining_fragments.len() < last_remaining_fragments.len() => { - let weight = max_weight - weight_used; - match Self::handle_blob_message(sender, sent_at, blob, weight) { - Ok(used) => weight_used = weight_used.saturating_add(used), - Err(true) => { - // That message didn't get processed this time because of being - // too heavy. We leave it around for next time and bail. - remaining_fragments = last_remaining_fragments; - break - }, - Err(false) => { - // Message invalid; don't attempt to retry - }, - } - }, - _ => { - debug_assert!(false, "Invalid incoming blob message data"); - remaining_fragments = &b""[..]; - }, + + if let Ok(blob) = >::decode(&mut remaining_fragments) { + let weight = max_weight - weight_used; + match Self::handle_blob_message(sender, sent_at, blob, weight) { + Ok(used) => weight_used = weight_used.saturating_add(used), + Err(true) => { + // That message didn't get processed this time because of being + // too heavy. We leave it around for next time and bail. + remaining_fragments = last_remaining_fragments; + break + }, + Err(false) => { + // Message invalid; don't attempt to retry + }, + } + } else { + debug_assert!(false, "Invalid incoming blob message data"); + remaining_fragments = &b""[..]; } } }, diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index bb352e69ff..59726172eb 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -46,10 +46,12 @@ fn bad_message_is_handled() { }); } +/// Tests that a blob message is handled. Currently this isn't implemented and panics when debug assertions +/// are enabled. When this feature is enabled, this test should be rewritten properly. #[test] -#[should_panic = "Invalid incoming blob message data"] +#[should_panic = "Blob messages not handled."] #[cfg(debug_assertions)] -fn other_bad_message_is_handled() { +fn handle_blob_message() { new_test_ext().execute_with(|| { let bad_data = vec![ 1, 1, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 64, 239, @@ -58,7 +60,6 @@ fn other_bad_message_is_handled() { ]; InboundXcmpMessages::::insert(ParaId::from(1000), 1, bad_data); let format = XcmpMessageFormat::ConcatenatedEncodedBlob; - // This should exit with an error. XcmpQueue::process_xcmp_message(1000.into(), (1, format), 10_000_000_000, 10_000_000_000); }); }