Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Enforce max assets in multiassets for some instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
franciscoaguirre committed Aug 17, 2023
1 parent 56d45fe commit c6ea9a9
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 4 deletions.
4 changes: 2 additions & 2 deletions xcm/src/v3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub use junction::{BodyId, BodyPart, Junction, NetworkId};
pub use junctions::Junctions;
pub use multiasset::{
AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets,
WildFungibility, WildMultiAsset,
WildFungibility, WildMultiAsset, MAX_ITEMS_IN_MULTIASSETS,
};
pub use multilocation::{
Ancestor, AncestorThen, InteriorMultiLocation, MultiLocation, Parent, ParentThen,
Expand Down Expand Up @@ -188,7 +188,7 @@ pub mod prelude {
WeightLimit::{self, *},
WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
WildMultiAsset::{self, *},
XcmContext, XcmHash, XcmWeightInfo, VERSION as XCM_VERSION,
XcmContext, XcmHash, XcmWeightInfo, MAX_ITEMS_IN_MULTIASSETS, VERSION as XCM_VERSION,
};
}
pub use super::{Instruction, Xcm};
Expand Down
2 changes: 1 addition & 1 deletion xcm/src/v3/multiasset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ pub struct MultiAssets(Vec<MultiAsset>);

/// Maximum number of items we expect in a single `MultiAssets` value. Note this is not (yet)
/// enforced, and just serves to provide a sensible `max_encoded_len` for `MultiAssets`.
const MAX_ITEMS_IN_MULTIASSETS: usize = 20;
pub const MAX_ITEMS_IN_MULTIASSETS: usize = 20;

impl MaxEncodedLen for MultiAssets {
fn max_encoded_len() -> usize {
Expand Down
3 changes: 3 additions & 0 deletions xcm/src/v3/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ pub enum Error {
WeightNotComputable,
/// Recursion stack limit reached
ExceedsStackLimit,
/// Assets exceeded maximum
// TODO (XCMv4): Add to spec
TooManyAssets,
}

impl MaxEncodedLen for Error {
Expand Down
12 changes: 12 additions & 0 deletions xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
WithdrawAsset(assets) => {
// Take `assets` from the origin account (on-chain) and place in holding.
let origin = *self.origin_ref().ok_or(XcmError::BadOrigin)?;
if assets.len() > MAX_ITEMS_IN_MULTIASSETS {
return Err(XcmError::TooManyAssets)
}
for asset in assets.into_inner().into_iter() {
Config::AssetTransactor::withdraw_asset(&asset, &origin, Some(&self.context))?;
self.subsume_asset(asset)?;
Expand All @@ -488,6 +491,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
ReserveAssetDeposited(assets) => {
// check whether we trust origin to be our reserve location for this asset.
let origin = *self.origin_ref().ok_or(XcmError::BadOrigin)?;
if assets.len() > MAX_ITEMS_IN_MULTIASSETS {
return Err(XcmError::TooManyAssets)
}
for asset in assets.into_inner().into_iter() {
// Must ensure that we recognise the asset as being managed by the origin.
ensure!(
Expand Down Expand Up @@ -526,6 +532,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
},
ReceiveTeleportedAsset(assets) => {
let origin = *self.origin_ref().ok_or(XcmError::BadOrigin)?;
if assets.len() > MAX_ITEMS_IN_MULTIASSETS {
return Err(XcmError::TooManyAssets)
}
// check whether we trust origin to teleport this asset to us via config trait.
for asset in assets.inner() {
// We only trust the origin to send us assets that they identify as their
Expand Down Expand Up @@ -719,6 +728,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
},
ClaimAsset { assets, ticket } => {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
if assets.len() > MAX_ITEMS_IN_MULTIASSETS {
return Err(XcmError::TooManyAssets)
}
let ok = Config::AssetClaims::claim_assets(origin, &ticket, &assets, &self.context);
ensure!(ok, XcmError::UnknownClaim);
for asset in assets.into_inner().into_iter() {
Expand Down
55 changes: 54 additions & 1 deletion xcm/xcm-simulator/example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ mod tests {
use codec::Encode;
use frame_support::{assert_ok, weights::Weight};
use xcm::latest::QueryResponseInfo;
use xcm_simulator::TestExt;
use xcm_simulator::{fake_message_hash, TestExt, XcmExecutor};

// Helper function for forming buy execution message
fn buy_execution<C>(fees: impl Into<MultiAsset>) -> Instruction<C> {
Expand Down Expand Up @@ -649,4 +649,57 @@ mod tests {
);
});
}

#[test]
fn too_many_assets_throws_error() {
use crate::Outcome::Incomplete;
use xcm_simulator::XcmError::TooManyAssets;

let assets = MultiAssets::from(vec![
(Here, 1).into(),
(Parent, 1).into(),
(MultiLocation::new(2, Here), 1).into(),
(MultiLocation::new(3, Here), 1).into(),
(MultiLocation::new(4, Here), 1).into(),
(MultiLocation::new(5, Here), 1).into(),
(MultiLocation::new(6, Here), 1).into(),
(MultiLocation::new(7, Here), 1).into(),
(MultiLocation::new(8, Here), 1).into(),
(MultiLocation::new(9, Here), 1).into(),
(MultiLocation::new(10, Here), 1).into(),
(MultiLocation::new(11, Here), 1).into(),
(MultiLocation::new(12, Here), 1).into(),
(MultiLocation::new(13, Here), 1).into(),
(MultiLocation::new(14, Here), 1).into(),
(MultiLocation::new(15, Here), 1).into(),
(MultiLocation::new(16, Here), 1).into(),
(MultiLocation::new(17, Here), 1).into(),
(MultiLocation::new(18, Here), 1).into(),
(MultiLocation::new(19, Here), 1).into(),
(MultiLocation::new(20, Here), 1).into(),
]);
let message = Xcm(vec![WithdrawAsset(assets.clone())]);
let hash = fake_message_hash(&message);
let result =
XcmExecutor::<parachain::XcmConfig>::execute_xcm(Here, message, hash, Weight::MAX);
assert!(matches!(result, Incomplete(_, TooManyAssets)));

let message = Xcm(vec![ReserveAssetDeposited(assets.clone())]);
let hash = fake_message_hash(&message);
let result =
XcmExecutor::<parachain::XcmConfig>::execute_xcm(Here, message, hash, Weight::MAX);
assert!(matches!(result, Incomplete(_, TooManyAssets)));

let message = Xcm(vec![ReceiveTeleportedAsset(assets.clone())]);
let hash = fake_message_hash(&message);
let result =
XcmExecutor::<parachain::XcmConfig>::execute_xcm(Here, message, hash, Weight::MAX);
assert!(matches!(result, Incomplete(_, TooManyAssets)));

let message = Xcm(vec![ClaimAsset { assets: assets.clone(), ticket: Here.into() }]);
let hash = fake_message_hash(&message);
let result =
XcmExecutor::<parachain::XcmConfig>::execute_xcm(Here, message, hash, Weight::MAX);
assert!(matches!(result, Incomplete(_, TooManyAssets)));
}
}

0 comments on commit c6ea9a9

Please sign in to comment.