tests.rs 37.5 KiB
Newer Older
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

use crate::{
	mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries,
	QueryStatus, VersionDiscoveryQueue, VersionNotifiers, VersionNotifyTargets,
};
use frame_support::{
	assert_noop, assert_ok,
	traits::{Currency, Hooks},
	weights::Weight,
use polkadot_parachain::primitives::Id as ParaId;
use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash};
Gavin Wood's avatar
Gavin Wood committed
use xcm::{latest::QueryResponseInfo, prelude::*};
use xcm_builder::AllowKnownQueryResponses;
use xcm_executor::{traits::ShouldExecute, XcmExecutor};

const ALICE: AccountId = AccountId::new([0u8; 32]);
const BOB: AccountId = AccountId::new([1u8; 32]);
const PARA_ID: u32 = 2000;
const INITIAL_BALANCE: u128 = 100;
const SEND_AMOUNT: u128 = 10;

#[test]
fn report_outcome_notify_works() {
	let balances = vec![
		(ALICE, INITIAL_BALANCE),
		(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
	];
Gavin Wood's avatar
Gavin Wood committed
	let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into();
	let mut message = Xcm(vec![TransferAsset {
		assets: (Here, SEND_AMOUNT).into(),
		beneficiary: sender.clone(),
	}]);
	let call = pallet_test_notifier::Call::notification_received {
		query_id: 0,
		response: Default::default(),
	};
	let notify = RuntimeCall::TestNotifier(call);
	new_test_ext_with_balances(balances).execute_with(|| {
Gavin Wood's avatar
Gavin Wood committed
		XcmPallet::report_outcome_notify(
			&mut message,
			Parachain(PARA_ID).into_location(),
			notify,
			100,
		)
		.unwrap();
Gavin Wood's avatar
Gavin Wood committed
				SetAppendix(Xcm(vec![ReportError(QueryResponseInfo {
					destination: Parent.into(),
Gavin Wood's avatar
Gavin Wood committed
					max_weight: Weight::from_parts(1_000_000, 1_000_000),
				})])),
				TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender.clone() },
			])
		);
Gavin Wood's avatar
Gavin Wood committed
		let querier: MultiLocation = Here.into();
		let status = QueryStatus::Pending {
			responder: MultiLocation::from(Parachain(PARA_ID)).into(),
			maybe_notify: Some((4, 2)),
			timeout: 100,
Gavin Wood's avatar
Gavin Wood committed
			maybe_match_querier: Some(querier.clone().into()),
		};
		assert_eq!(crate::Queries::<Test>::iter().collect::<Vec<_>>(), vec![(0, status)]);

Gavin Wood's avatar
Gavin Wood committed
		let message = Xcm(vec![QueryResponse {
			query_id: 0,
			response: Response::ExecutionResult(None),
			max_weight: Weight::from_parts(1_000_000, 1_000_000),
			querier: Some(querier),
		}]);
		let hash = fake_message_hash(&message);
		let r = XcmExecutor::<XcmConfig>::execute_xcm(
Gavin Wood's avatar
Gavin Wood committed
			Parachain(PARA_ID),
			message,
			hash,
			Weight::from_parts(1_000_000_000, 1_000_000_000),
Gavin Wood's avatar
Gavin Wood committed
		assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
				RuntimeEvent::TestNotifier(pallet_test_notifier::Event::ResponseReceived(
					Response::ExecutionResult(None),
				RuntimeEvent::XcmPallet(crate::Event::Notified(0, 4, 2)),
			]
		);
		assert_eq!(crate::Queries::<Test>::iter().collect::<Vec<_>>(), vec![]);
	});
}

#[test]
fn report_outcome_works() {
	let balances = vec![
		(ALICE, INITIAL_BALANCE),
		(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
	];
Gavin Wood's avatar
Gavin Wood committed
	let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into();
	let mut message = Xcm(vec![TransferAsset {
		assets: (Here, SEND_AMOUNT).into(),
		beneficiary: sender.clone(),
	}]);
	new_test_ext_with_balances(balances).execute_with(|| {
Gavin Wood's avatar
Gavin Wood committed
		XcmPallet::report_outcome(&mut message, Parachain(PARA_ID).into_location(), 100).unwrap();
Gavin Wood's avatar
Gavin Wood committed
				SetAppendix(Xcm(vec![ReportError(QueryResponseInfo {
					destination: Parent.into(),
Gavin Wood's avatar
Gavin Wood committed
					max_weight: Weight::zero(),
				})])),
				TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender.clone() },
			])
		);
Gavin Wood's avatar
Gavin Wood committed
		let querier: MultiLocation = Here.into();
		let status = QueryStatus::Pending {
			responder: MultiLocation::from(Parachain(PARA_ID)).into(),
			maybe_notify: None,
			timeout: 100,
Gavin Wood's avatar
Gavin Wood committed
			maybe_match_querier: Some(querier.clone().into()),
		};
		assert_eq!(crate::Queries::<Test>::iter().collect::<Vec<_>>(), vec![(0, status)]);

Gavin Wood's avatar
Gavin Wood committed
		let message = Xcm(vec![QueryResponse {
			query_id: 0,
			response: Response::ExecutionResult(None),
			max_weight: Weight::zero(),
			querier: Some(querier),
		}]);
		let hash = fake_message_hash(&message);
		let r = XcmExecutor::<XcmConfig>::execute_xcm(
Gavin Wood's avatar
Gavin Wood committed
			Parachain(PARA_ID),
			message,
			hash,
			Weight::from_parts(1_000_000_000, 1_000_000_000),
Gavin Wood's avatar
Gavin Wood committed
		assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
		assert_eq!(
			last_event(),
			RuntimeEvent::XcmPallet(crate::Event::ResponseReady(
				0,
				Response::ExecutionResult(None),
			))
		);

		let response = Some((Response::ExecutionResult(None), 1));
		assert_eq!(XcmPallet::take_response(0), response);
	});
}

#[test]
fn custom_querier_works() {
	let balances = vec![
		(ALICE, INITIAL_BALANCE),
		(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
	];
	new_test_ext_with_balances(balances).execute_with(|| {
		let querier: MultiLocation =
			(Parent, AccountId32 { network: None, id: ALICE.into() }).into();

		let r = TestNotifier::prepare_new_query(RuntimeOrigin::signed(ALICE), querier.clone());
		assert_eq!(r, Ok(()));
		let status = QueryStatus::Pending {
			responder: MultiLocation::from(AccountId32 { network: None, id: ALICE.into() }).into(),
			maybe_notify: None,
			timeout: 100,
			maybe_match_querier: Some(querier.clone().into()),
		};
		assert_eq!(crate::Queries::<Test>::iter().collect::<Vec<_>>(), vec![(0, status)]);

		// Supplying no querier when one is expected will fail
		let message = Xcm(vec![QueryResponse {
			query_id: 0,
			response: Response::ExecutionResult(None),
			max_weight: Weight::zero(),
			querier: None,
		}]);
		let hash = fake_message_hash(&message);
		let r = XcmExecutor::<XcmConfig>::execute_xcm_in_credit(
			AccountId32 { network: None, id: ALICE.into() },
Loading full blame...