tests.rs 12.1 KB
Newer Older
Gavin Wood's avatar
Gavin Wood committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright 2020 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/>.

Shawn Tabrizi's avatar
Shawn Tabrizi committed
17
use super::{mock::*, *};
18
use frame_support::{assert_err, weights::constants::WEIGHT_PER_SECOND};
Gavin Wood's avatar
Gavin Wood committed
19
use xcm::latest::prelude::*;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
20
use xcm_executor::{traits::*, Config, XcmExecutor};
Gavin Wood's avatar
Gavin Wood committed
21
22
23

#[test]
fn basic_setup_works() {
24
	add_reserve(Parent.into(), Wild((Parent, WildFungible).into()));
Gavin Wood's avatar
Gavin Wood committed
25
	assert!(<TestConfig as Config>::IsReserve::filter_asset_location(
26
27
		&(Parent, 100).into(),
		&Parent.into(),
Gavin Wood's avatar
Gavin Wood committed
28
29
	));

30
31
32
33
34
35
36
37
38
39
40
41
42
	assert_eq!(to_account(X1(Parachain(1)).into()), Ok(1001));
	assert_eq!(to_account(X1(Parachain(50)).into()), Ok(1050));
	assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(1)))), Ok(2001));
	assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(50)))), Ok(2050));
	assert_eq!(
		to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 1, network: Any }))),
		Ok(1),
	);
	assert_eq!(
		to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 42, network: Any }))),
		Ok(42),
	);
	assert_eq!(to_account(Here.into()), Ok(3000));
Gavin Wood's avatar
Gavin Wood committed
43
44
45
46
}

#[test]
fn weigher_should_work() {
Gavin Wood's avatar
Gavin Wood committed
47
	let mut message = opaque::Xcm::ReserveAssetDeposited {
48
		assets: (Parent, 100).into(),
Gavin Wood's avatar
Gavin Wood committed
49
		effects: vec![
Shawn Tabrizi's avatar
Shawn Tabrizi committed
50
			Order::BuyExecution {
51
				fees: (Parent, 1).into(),
Shawn Tabrizi's avatar
Shawn Tabrizi committed
52
53
54
				weight: 0,
				debt: 30,
				halt_on_error: true,
Gavin Wood's avatar
Gavin Wood committed
55
				instructions: vec![],
Shawn Tabrizi's avatar
Shawn Tabrizi committed
56
			},
57
			Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() },
Gavin Wood's avatar
Gavin Wood committed
58
		],
Shawn Tabrizi's avatar
Shawn Tabrizi committed
59
60
	}
	.into();
Gavin Wood's avatar
Gavin Wood committed
61
62
63
64
65
	assert_eq!(<TestConfig as Config>::Weigher::shallow(&mut message), Ok(30));
}

#[test]
fn take_weight_credit_barrier_should_work() {
Gavin Wood's avatar
Gavin Wood committed
66
	let mut message =
67
		opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() };
Gavin Wood's avatar
Gavin Wood committed
68
69

	let mut weight_credit = 10;
70
71
72
73
74
75
76
	let r = TakeWeightCredit::should_execute(
		&Parent.into(),
		true,
		&mut message,
		10,
		&mut weight_credit,
	);
Gavin Wood's avatar
Gavin Wood committed
77
78
79
	assert_eq!(r, Ok(()));
	assert_eq!(weight_credit, 0);

80
81
82
83
84
85
86
	let r = TakeWeightCredit::should_execute(
		&Parent.into(),
		true,
		&mut message,
		10,
		&mut weight_credit,
	);
Gavin Wood's avatar
Gavin Wood committed
87
88
89
90
91
92
	assert_eq!(r, Err(()));
	assert_eq!(weight_credit, 0);
}

#[test]
fn allow_unpaid_should_work() {
Gavin Wood's avatar
Gavin Wood committed
93
	let mut message =
94
		opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() };
Gavin Wood's avatar
Gavin Wood committed
95

96
	AllowUnpaidFrom::set(vec![Parent.into()]);
Gavin Wood's avatar
Gavin Wood committed
97
98

	let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
99
		&Parachain(1).into(),
Gavin Wood's avatar
Gavin Wood committed
100
101
102
103
104
105
106
107
		true,
		&mut message,
		10,
		&mut 0,
	);
	assert_eq!(r, Err(()));

	let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
108
		&Parent.into(),
Gavin Wood's avatar
Gavin Wood committed
109
110
111
112
113
114
115
116
117
118
		true,
		&mut message,
		10,
		&mut 0,
	);
	assert_eq!(r, Ok(()));
}

#[test]
fn allow_paid_should_work() {
119
	AllowPaidFrom::set(vec![Parent.into()]);
Gavin Wood's avatar
Gavin Wood committed
120

Gavin Wood's avatar
Gavin Wood committed
121
	let mut message =
122
		opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() };
Gavin Wood's avatar
Gavin Wood committed
123
124

	let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
125
		&Parachain(1).into(),
Gavin Wood's avatar
Gavin Wood committed
126
127
128
129
130
131
132
		true,
		&mut message,
		10,
		&mut 0,
	);
	assert_eq!(r, Err(()));

133
	let fees = (Parent, 1).into();
Gavin Wood's avatar
Gavin Wood committed
134
	let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited {
135
		assets: (Parent, 100).into(),
Gavin Wood's avatar
Gavin Wood committed
136
		effects: vec![
Shawn Tabrizi's avatar
Shawn Tabrizi committed
137
			Order::BuyExecution {
Gavin Wood's avatar
Gavin Wood committed
138
				fees,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
139
140
141
				weight: 0,
				debt: 20,
				halt_on_error: true,
Gavin Wood's avatar
Gavin Wood committed
142
				instructions: vec![],
Shawn Tabrizi's avatar
Shawn Tabrizi committed
143
			},
144
			Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() },
Gavin Wood's avatar
Gavin Wood committed
145
146
147
148
		],
	};

	let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
149
		&Parent.into(),
Gavin Wood's avatar
Gavin Wood committed
150
151
152
153
154
155
156
		true,
		&mut underpaying_message,
		30,
		&mut 0,
	);
	assert_eq!(r, Err(()));

157
	let fees = (Parent, 1).into();
Gavin Wood's avatar
Gavin Wood committed
158
	let mut paying_message = opaque::Xcm::ReserveAssetDeposited {
159
		assets: (Parent, 100).into(),
Gavin Wood's avatar
Gavin Wood committed
160
		effects: vec![
Shawn Tabrizi's avatar
Shawn Tabrizi committed
161
			Order::BuyExecution {
Gavin Wood's avatar
Gavin Wood committed
162
				fees,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
163
164
165
				weight: 0,
				debt: 30,
				halt_on_error: true,
Gavin Wood's avatar
Gavin Wood committed
166
				instructions: vec![],
Shawn Tabrizi's avatar
Shawn Tabrizi committed
167
			},
168
			Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() },
Gavin Wood's avatar
Gavin Wood committed
169
170
171
172
		],
	};

	let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
173
		&Parachain(1).into(),
Gavin Wood's avatar
Gavin Wood committed
174
175
176
177
178
179
180
181
		true,
		&mut paying_message,
		30,
		&mut 0,
	);
	assert_eq!(r, Err(()));

	let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
182
		&Parent.into(),
Gavin Wood's avatar
Gavin Wood committed
183
184
185
186
187
188
189
190
191
192
		true,
		&mut paying_message,
		30,
		&mut 0,
	);
	assert_eq!(r, Ok(()));
}

#[test]
fn paying_reserve_deposit_should_work() {
193
194
	AllowPaidFrom::set(vec![Parent.into()]);
	add_reserve(Parent.into(), (Parent, WildFungible).into());
Gavin Wood's avatar
Gavin Wood committed
195
	WeightPrice::set((Parent.into(), 1_000_000_000_000));
Gavin Wood's avatar
Gavin Wood committed
196

197
198
	let origin = Parent.into();
	let fees = (Parent, 30).into();
Gavin Wood's avatar
Gavin Wood committed
199
	let message = Xcm::<TestCall>::ReserveAssetDeposited {
200
		assets: (Parent, 100).into(),
Gavin Wood's avatar
Gavin Wood committed
201
		effects: vec![
Shawn Tabrizi's avatar
Shawn Tabrizi committed
202
			Order::<TestCall>::BuyExecution {
Gavin Wood's avatar
Gavin Wood committed
203
				fees,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
204
205
206
				weight: 0,
				debt: 30,
				halt_on_error: true,
Gavin Wood's avatar
Gavin Wood committed
207
208
209
210
211
				instructions: vec![],
			},
			Order::<TestCall>::DepositAsset {
				assets: All.into(),
				max_assets: 1,
212
				beneficiary: Here.into(),
Shawn Tabrizi's avatar
Shawn Tabrizi committed
213
			},
Gavin Wood's avatar
Gavin Wood committed
214
215
216
217
218
		],
	};
	let weight_limit = 50;
	let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit);
	assert_eq!(r, Outcome::Complete(30));
219
	assert_eq!(assets(3000), vec![(Parent, 70).into()]);
Gavin Wood's avatar
Gavin Wood committed
220
221
222
223
224
}

#[test]
fn transfer_should_work() {
	// we'll let them have message execution for free.
225
	AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
Gavin Wood's avatar
Gavin Wood committed
226
	// Child parachain #1 owns 1000 tokens held by us in reserve.
227
	add_asset(1001, (Here, 1000));
Gavin Wood's avatar
Gavin Wood committed
228
229
	// They want to transfer 100 of them to their sibling parachain #2
	let r = XcmExecutor::<TestConfig>::execute_xcm(
230
		Parachain(1).into(),
Gavin Wood's avatar
Gavin Wood committed
231
		Xcm::TransferAsset {
Gavin Wood's avatar
Gavin Wood committed
232
			assets: (Here, 100).into(),
233
			beneficiary: X1(AccountIndex64 { index: 3, network: Any }).into(),
Gavin Wood's avatar
Gavin Wood committed
234
235
236
237
		},
		50,
	);
	assert_eq!(r, Outcome::Complete(10));
Gavin Wood's avatar
Gavin Wood committed
238
239
	assert_eq!(assets(3), vec![(Here, 100).into()]);
	assert_eq!(assets(1001), vec![(Here, 900).into()]);
Gavin Wood's avatar
Gavin Wood committed
240
241
242
243
244
	assert_eq!(sent_xcm(), vec![]);
}

#[test]
fn reserve_transfer_should_work() {
245
	AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
Gavin Wood's avatar
Gavin Wood committed
246
	// Child parachain #1 owns 1000 tokens held by us in reserve.
247
	add_asset(1001, (Here, 1000));
Gavin Wood's avatar
Gavin Wood committed
248
	// The remote account owned by gav.
249
	let three: MultiLocation = X1(AccountIndex64 { index: 3, network: Any }).into();
Gavin Wood's avatar
Gavin Wood committed
250
251
252
253

	// They want to transfer 100 of our native asset from sovereign account of parachain #1 into #2
	// and let them know to hand it to account #3.
	let r = XcmExecutor::<TestConfig>::execute_xcm(
254
		Parachain(1).into(),
Gavin Wood's avatar
Gavin Wood committed
255
		Xcm::TransferReserveAsset {
Gavin Wood's avatar
Gavin Wood committed
256
			assets: (Here, 100).into(),
257
			dest: Parachain(2).into(),
Gavin Wood's avatar
Gavin Wood committed
258
259
260
261
262
			effects: vec![Order::DepositAsset {
				assets: All.into(),
				max_assets: 1,
				beneficiary: three.clone(),
			}],
Gavin Wood's avatar
Gavin Wood committed
263
264
265
266
267
		},
		50,
	);
	assert_eq!(r, Outcome::Complete(10));

Gavin Wood's avatar
Gavin Wood committed
268
	assert_eq!(assets(1002), vec![(Here, 100).into()]);
Shawn Tabrizi's avatar
Shawn Tabrizi committed
269
270
271
	assert_eq!(
		sent_xcm(),
		vec![(
272
			Parachain(2).into(),
Gavin Wood's avatar
Gavin Wood committed
273
			Xcm::ReserveAssetDeposited {
274
				assets: (Parent, 100).into(),
Gavin Wood's avatar
Gavin Wood committed
275
276
277
278
279
				effects: vec![Order::DepositAsset {
					assets: All.into(),
					max_assets: 1,
					beneficiary: three
				}],
Shawn Tabrizi's avatar
Shawn Tabrizi committed
280
281
282
			}
		)]
	);
Gavin Wood's avatar
Gavin Wood committed
283
284
285
286
}

#[test]
fn transacting_should_work() {
287
	AllowUnpaidFrom::set(vec![Parent.into()]);
Gavin Wood's avatar
Gavin Wood committed
288

289
	let origin = Parent.into();
Gavin Wood's avatar
Gavin Wood committed
290
291
292
293
294
295
296
297
298
299
300
301
	let message = Xcm::<TestCall>::Transact {
		origin_type: OriginKind::Native,
		require_weight_at_most: 50,
		call: TestCall::Any(50, None).encode().into(),
	};
	let weight_limit = 60;
	let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit);
	assert_eq!(r, Outcome::Complete(60));
}

#[test]
fn transacting_should_respect_max_weight_requirement() {
302
	AllowUnpaidFrom::set(vec![Parent.into()]);
Gavin Wood's avatar
Gavin Wood committed
303

304
	let origin = Parent.into();
Gavin Wood's avatar
Gavin Wood committed
305
306
307
308
309
310
311
312
313
314
315
316
	let message = Xcm::<TestCall>::Transact {
		origin_type: OriginKind::Native,
		require_weight_at_most: 40,
		call: TestCall::Any(50, None).encode().into(),
	};
	let weight_limit = 60;
	let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit);
	assert_eq!(r, Outcome::Incomplete(60, XcmError::TooMuchWeightRequired));
}

#[test]
fn transacting_should_refund_weight() {
317
	AllowUnpaidFrom::set(vec![Parent.into()]);
Gavin Wood's avatar
Gavin Wood committed
318

319
	let origin = Parent.into();
Gavin Wood's avatar
Gavin Wood committed
320
321
322
323
324
325
326
327
328
329
330
331
	let message = Xcm::<TestCall>::Transact {
		origin_type: OriginKind::Native,
		require_weight_at_most: 50,
		call: TestCall::Any(50, Some(30)).encode().into(),
	};
	let weight_limit = 60;
	let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit);
	assert_eq!(r, Outcome::Complete(40));
}

#[test]
fn paid_transacting_should_refund_payment_for_unused_weight() {
332
	let one: MultiLocation = X1(AccountIndex64 { index: 1, network: Any }).into();
Shawn Tabrizi's avatar
Shawn Tabrizi committed
333
	AllowPaidFrom::set(vec![one.clone()]);
334
	add_asset(1, (Parent, 100));
Gavin Wood's avatar
Gavin Wood committed
335
	WeightPrice::set((Parent.into(), 1_000_000_000_000));
Gavin Wood's avatar
Gavin Wood committed
336
337

	let origin = one.clone();
338
	let fees = (Parent, 100).into();
Gavin Wood's avatar
Gavin Wood committed
339
	let message = Xcm::<TestCall>::WithdrawAsset {
340
		assets: (Parent, 100).into(), // enough for 100 units of weight.
Gavin Wood's avatar
Gavin Wood committed
341
		effects: vec![
Shawn Tabrizi's avatar
Shawn Tabrizi committed
342
			Order::<TestCall>::BuyExecution {
Gavin Wood's avatar
Gavin Wood committed
343
				fees,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
344
345
346
				weight: 70,
				debt: 30,
				halt_on_error: true,
Gavin Wood's avatar
Gavin Wood committed
347
				instructions: vec![Xcm::<TestCall>::Transact {
Gavin Wood's avatar
Gavin Wood committed
348
349
350
351
					origin_type: OriginKind::Native,
					require_weight_at_most: 60,
					// call estimated at 70 but only takes 10.
					call: TestCall::Any(60, Some(10)).encode().into(),
Shawn Tabrizi's avatar
Shawn Tabrizi committed
352
353
				}],
			},
Gavin Wood's avatar
Gavin Wood committed
354
355
356
357
358
			Order::<TestCall>::DepositAsset {
				assets: All.into(),
				max_assets: 1,
				beneficiary: one.clone(),
			},
Gavin Wood's avatar
Gavin Wood committed
359
360
361
362
363
		],
	};
	let weight_limit = 100;
	let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit);
	assert_eq!(r, Outcome::Complete(50));
364
	assert_eq!(assets(1), vec![(Parent, 50).into()]);
Gavin Wood's avatar
Gavin Wood committed
365
366
367
368
369
}

#[test]
fn prepaid_result_of_query_should_get_free_execution() {
	let query_id = 33;
370
	let origin: MultiLocation = Parent.into();
Gavin Wood's avatar
Gavin Wood committed
371
372
373
	// We put this in manually here, but normally this would be done at the point of crafting the message.
	expect_response(query_id, origin.clone());

374
	let the_response = Response::Assets((Parent, 100).into());
Shawn Tabrizi's avatar
Shawn Tabrizi committed
375
	let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone() };
Gavin Wood's avatar
Gavin Wood committed
376
377
378
379
380
381
382
383
384
385
386
	let weight_limit = 10;

	// First time the response gets through since we're expecting it...
	let r = XcmExecutor::<TestConfig>::execute_xcm(origin.clone(), message.clone(), weight_limit);
	assert_eq!(r, Outcome::Complete(10));
	assert_eq!(response(query_id).unwrap(), the_response);

	// Second time it doesn't, since we're not.
	let r = XcmExecutor::<TestConfig>::execute_xcm(origin.clone(), message.clone(), weight_limit);
	assert_eq!(r, Outcome::Incomplete(10, XcmError::Barrier));
}
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435

fn fungible_multi_asset(location: MultiLocation, amount: u128) -> MultiAsset {
	(AssetId::from(location), Fungibility::Fungible(amount)).into()
}

#[test]
fn weight_trader_tuple_should_work() {
	pub const PARA_1: MultiLocation = X1(Parachain(1));
	pub const PARA_2: MultiLocation = X1(Parachain(2));

	parameter_types! {
		pub static HereWeightPrice: (AssetId, u128) = (Here.into(), WEIGHT_PER_SECOND.into());
		pub static PARA1WeightPrice: (AssetId, u128) = (PARA_1.into(), WEIGHT_PER_SECOND.into());
	}

	type Traders = (
		// trader one
		FixedRateOfFungible<HereWeightPrice, ()>,
		// trader two
		FixedRateOfFungible<PARA1WeightPrice, ()>,
	);

	let mut traders = Traders::new();
	// trader one buys weight
	assert_eq!(
		traders.buy_weight(5, fungible_multi_asset(Here, 10).into()),
		Ok(fungible_multi_asset(Here, 5).into()),
	);
	// trader one refunds
	assert_eq!(traders.refund_weight(2), Some(fungible_multi_asset(Here, 2)));

	let mut traders = Traders::new();
	// trader one failed; trader two buys weight
	assert_eq!(
		traders.buy_weight(5, fungible_multi_asset(PARA_1, 10).into()),
		Ok(fungible_multi_asset(PARA_1, 5).into()),
	);
	// trader two refunds
	assert_eq!(traders.refund_weight(2), Some(fungible_multi_asset(PARA_1, 2)));

	let mut traders = Traders::new();
	// all traders fails
	assert_err!(
		traders.buy_weight(5, fungible_multi_asset(PARA_2, 10).into()),
		XcmError::TooExpensive,
	);
	// and no refund
	assert_eq!(traders.refund_weight(2), None);
}