Skip to content

Commit 51dcc9f

Browse files
Enforce a decoding limit in MultiAssets (#1395)
* Enforce a decoding limit in MultiAssets * ".git/.scripts/commands/fmt/fmt.sh" * Update polkadot/xcm/src/v3/multiasset.rs Co-authored-by: Keith Yeung <[email protected]> * Just use a BoundedVec * Conflicts --------- Co-authored-by: command-bot <> Co-authored-by: Keith Yeung <[email protected]>
1 parent 3369168 commit 51dcc9f

File tree

1 file changed

+33
-5
lines changed

1 file changed

+33
-5
lines changed

polkadot/xcm/src/v3/multiasset.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use core::{
4040
};
4141
use parity_scale_codec::{self as codec, Decode, Encode, MaxEncodedLen};
4242
use scale_info::TypeInfo;
43+
use bounded_collections::{BoundedVec, ConstU32};
4344

4445
/// A general identifier for an instance of a non-fungible asset class.
4546
#[derive(
@@ -506,9 +507,8 @@ impl TryFrom<OldMultiAsset> for MultiAsset {
506507
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
507508
pub struct MultiAssets(Vec<MultiAsset>);
508509

509-
/// Maximum number of items we expect in a single `MultiAssets` value. Note this is not (yet)
510-
/// enforced, and just serves to provide a sensible `max_encoded_len` for `MultiAssets`.
511-
const MAX_ITEMS_IN_MULTIASSETS: usize = 20;
510+
/// Maximum number of items in a single `MultiAssets` value that can be decoded.
511+
pub const MAX_ITEMS_IN_MULTIASSETS: usize = 20;
512512

513513
impl MaxEncodedLen for MultiAssets {
514514
fn max_encoded_len() -> usize {
@@ -517,8 +517,9 @@ impl MaxEncodedLen for MultiAssets {
517517
}
518518

519519
impl Decode for MultiAssets {
520-
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> {
521-
Self::from_sorted_and_deduplicated(Vec::<MultiAsset>::decode(input)?)
520+
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
521+
let bounded_instructions = BoundedVec::<MultiAsset, ConstU32<{ MAX_ITEMS_IN_MULTIASSETS as u32 }>>::decode(input)?;
522+
Self::from_sorted_and_deduplicated(bounded_instructions.into_inner())
522523
.map_err(|()| "Out of order".into())
523524
}
524525
}
@@ -974,4 +975,31 @@ mod tests {
974975
let r = MultiAssets::from_sorted_and_deduplicated(mixed_bad);
975976
assert!(r.is_err());
976977
}
978+
979+
#[test]
980+
fn decoding_respects_limit() {
981+
use super::*;
982+
983+
// Having lots of one asset will work since they are deduplicated
984+
let lots_of_one_asset: MultiAssets =
985+
vec![(GeneralIndex(1), 1u128).into(); MAX_ITEMS_IN_MULTIASSETS + 1].into();
986+
let encoded = lots_of_one_asset.encode();
987+
assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
988+
989+
// Fewer assets than the limit works
990+
let mut few_assets: MultiAssets = Vec::new().into();
991+
for i in 0..MAX_ITEMS_IN_MULTIASSETS {
992+
few_assets.push((GeneralIndex(i as u128), 1u128).into());
993+
}
994+
let encoded = few_assets.encode();
995+
assert!(MultiAssets::decode(&mut &encoded[..]).is_ok());
996+
997+
// Having lots of different assets will not work
998+
let mut too_many_different_assets: MultiAssets = Vec::new().into();
999+
for i in 0..MAX_ITEMS_IN_MULTIASSETS + 1 {
1000+
too_many_different_assets.push((GeneralIndex(i as u128), 1u128).into());
1001+
}
1002+
let encoded = too_many_different_assets.encode();
1003+
assert!(MultiAssets::decode(&mut &encoded[..]).is_err());
1004+
}
9771005
}

0 commit comments

Comments
 (0)