Skip to content

Commit fa3b842

Browse files
Add instruction limit when decoding XCMs (#1227)
* Add instruction limit when decoding XCMs * Make the instruction limit a constant * Use vec for buffer * ".git/.scripts/commands/fmt/fmt.sh" * Go back on std * Use BoundedVec's Decode implementation * ".git/.scripts/commands/fmt/fmt.sh" * Use an actual BoundedVec to decode XCMs * Change comment location * ".git/.scripts/commands/fmt/fmt.sh" * Remove unused imports * ".git/.scripts/commands/fmt/fmt.sh" --------- Co-authored-by: command-bot <>
1 parent dcda0e5 commit fa3b842

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

polkadot/xcm/src/v3/mod.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ use super::v2::{
2222
};
2323
use crate::{DoubleEncoded, GetWeight};
2424
use alloc::{vec, vec::Vec};
25-
use bounded_collections::{parameter_types, BoundedVec};
25+
use bounded_collections::{parameter_types, BoundedVec, ConstU32};
2626
use core::{
2727
convert::{TryFrom, TryInto},
2828
fmt::Debug,
2929
result,
3030
};
3131
use derivative::Derivative;
32-
use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen};
32+
use parity_scale_codec::{
33+
self, Decode, Encode, Error as CodecError, Input as CodecInput, MaxEncodedLen,
34+
};
3335
use scale_info::TypeInfo;
3436

3537
mod junction;
@@ -60,13 +62,23 @@ pub const VERSION: super::Version = 3;
6062
/// An identifier for a query.
6163
pub type QueryId = u64;
6264

63-
#[derive(Derivative, Default, Encode, Decode, TypeInfo)]
65+
// TODO (v4): Use `BoundedVec` instead of `Vec`
66+
#[derive(Derivative, Default, Encode, TypeInfo)]
6467
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
6568
#[codec(encode_bound())]
66-
#[codec(decode_bound())]
6769
#[scale_info(bounds(), skip_type_params(Call))]
6870
pub struct Xcm<Call>(pub Vec<Instruction<Call>>);
6971

72+
const MAX_INSTRUCTIONS_TO_DECODE: u32 = 100;
73+
74+
impl<Call> Decode for Xcm<Call> {
75+
fn decode<I: CodecInput>(input: &mut I) -> core::result::Result<Self, CodecError> {
76+
let bounded_instructions =
77+
BoundedVec::<Instruction<Call>, ConstU32<MAX_INSTRUCTIONS_TO_DECODE>>::decode(input)?;
78+
Ok(Self(bounded_instructions.into_inner()))
79+
}
80+
}
81+
7082
impl<Call> Xcm<Call> {
7183
/// Create an empty instance.
7284
pub fn new() -> Self {
@@ -1426,4 +1438,17 @@ mod tests {
14261438
let new_xcm: Xcm<()> = old_xcm.try_into().unwrap();
14271439
assert_eq!(new_xcm, xcm);
14281440
}
1441+
1442+
#[test]
1443+
fn decoding_fails_when_too_many_instructions() {
1444+
let small_xcm = Xcm::<()>(vec![ClearOrigin; 20]);
1445+
let bytes = small_xcm.encode();
1446+
let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]);
1447+
assert!(matches!(decoded_xcm, Ok(_)));
1448+
1449+
let big_xcm = Xcm::<()>(vec![ClearOrigin; 64_000]);
1450+
let bytes = big_xcm.encode();
1451+
let decoded_xcm = Xcm::<()>::decode(&mut &bytes[..]);
1452+
assert!(matches!(decoded_xcm, Err(CodecError { .. })));
1453+
}
14291454
}

0 commit comments

Comments
 (0)