1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

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

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

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

            
17
pub mod pallet_xcm_benchmarks_fungible;
18
pub mod pallet_xcm_benchmarks_generic;
19

            
20
use {
21
    crate::{Balances, Runtime},
22
    alloc::vec::Vec,
23
    frame_support::{pallet_prelude::PalletInfoAccess, weights::Weight, BoundedVec},
24
    pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight,
25
    pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric,
26
    xcm::{
27
        latest::{prelude::*, AssetTransferFilter, Weight as XCMWeight},
28
        DoubleEncoded,
29
    },
30
};
31

            
32
const MAX_ASSETS: u64 = 1;
33

            
34
pub enum AssetTypes {
35
    Balances,
36
    Ethereum,
37
    Relay,
38
    SiblingParachain,
39
    GrandParent,
40
    Unknown,
41
}
42

            
43
impl From<&Asset> for AssetTypes {
44
462
    fn from(asset: &Asset) -> Self {
45
198
        match asset {
46
            Asset {
47
                id:
48
                    AssetId(Location {
49
                        parents: 0,
50
132
                        interior,
51
                    }),
52
                ..
53
            } => {
54
132
                if let Some(PalletInstance(index)) = interior.first() {
55
132
                    if *index == <Balances as PalletInfoAccess>::index() as u8 {
56
132
                        AssetTypes::Balances
57
                    } else {
58
                        AssetTypes::Unknown
59
                    }
60
                } else {
61
                    AssetTypes::Unknown
62
                }
63
            }
64
            Asset {
65
                id:
66
                    AssetId(Location {
67
                        parents: 2,
68
132
                        interior,
69
                    }),
70
                ..
71
            } => {
72
132
                if let Some(GlobalConsensus(Ethereum { .. })) = interior.first() {
73
132
                    AssetTypes::Ethereum
74
                } else {
75
                    AssetTypes::GrandParent
76
                }
77
            }
78
            Asset {
79
                id:
80
                    AssetId(Location {
81
                        parents: 1,
82
                        interior: Here,
83
                    }),
84
                ..
85
187
            } => AssetTypes::Relay,
86
            Asset {
87
                id:
88
                    AssetId(Location {
89
                        parents: 1,
90
11
                        interior,
91
                    }),
92
                ..
93
            } => {
94
11
                if let Some(Parachain(_)) = interior.first() {
95
11
                    AssetTypes::SiblingParachain
96
                } else {
97
                    AssetTypes::Unknown
98
                }
99
            }
100
            _ => AssetTypes::Unknown,
101
        }
102
462
    }
103
}
104

            
105
trait WeighAssets {
106
    fn weigh_assets(&self, balances_weight: Weight) -> Weight;
107
}
108

            
109
impl WeighAssets for AssetFilter {
110
198
    fn weigh_assets(&self, balances_weight: Weight) -> Weight {
111
132
        match self {
112
66
            Self::Definite(assets) => assets
113
66
                .inner()
114
66
                .iter()
115
66
                .map(From::from)
116
66
                .map(|t| match t {
117
33
                    AssetTypes::Balances => balances_weight,
118
22
                    AssetTypes::Ethereum => balances_weight,
119
11
                    AssetTypes::Relay => balances_weight,
120
                    AssetTypes::SiblingParachain => balances_weight,
121
                    AssetTypes::GrandParent => balances_weight,
122
                    AssetTypes::Unknown => Weight::MAX,
123
66
                })
124
66
                .fold(Weight::zero(), |acc, x| acc.saturating_add(x)),
125
44
            Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight,
126
88
            Self::Wild(AllCounted(count)) => {
127
88
                balances_weight.saturating_mul(MAX_ASSETS.min(u64::from(*count)))
128
            }
129
            Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS),
130
        }
131
198
    }
132
}
133

            
134
impl WeighAssets for Assets {
135
275
    fn weigh_assets(&self, balances_weight: Weight) -> Weight {
136
275
        self.inner()
137
275
            .iter()
138
275
            .map(<AssetTypes as From<&Asset>>::from)
139
396
            .map(|t| match t {
140
99
                AssetTypes::Balances => balances_weight,
141
110
                AssetTypes::Ethereum => balances_weight,
142
176
                AssetTypes::Relay => balances_weight,
143
11
                AssetTypes::SiblingParachain => balances_weight,
144
                AssetTypes::GrandParent => balances_weight,
145
                AssetTypes::Unknown => Weight::MAX,
146
396
            })
147
396
            .fold(Weight::zero(), |acc, x| acc.saturating_add(x))
148
275
    }
149
}
150

            
151
// For now we are returning benchmarked weights only for generic XCM instructions.
152
// Fungible XCM instructions will return a fixed weight value of
153
// 200_000_000 ref_time and its proper PoV weight taken from statemint benchmarks.
154
//
155
// TODO: add the fungible benchmarked values once these are calculated.
156
pub struct XcmWeight<RuntimeCall>(core::marker::PhantomData<RuntimeCall>);
157
impl<RuntimeCall> XcmWeightInfo<RuntimeCall> for XcmWeight<RuntimeCall>
158
where
159
    Runtime: frame_system::Config,
160
{
161
11
    fn withdraw_asset(assets: &Assets) -> XCMWeight {
162
11
        assets.weigh_assets(XcmBalancesWeight::<Runtime>::withdraw_asset())
163
11
    }
164
12
    fn reserve_asset_deposited(assets: &Assets) -> XCMWeight {
165
12
        assets.weigh_assets(XcmBalancesWeight::<Runtime>::reserve_asset_deposited())
166
12
    }
167
    fn receive_teleported_asset(_assets: &Assets) -> XCMWeight {
168
        XCMWeight::MAX
169
    }
170
    fn query_response(
171
        _query_id: &u64,
172
        _response: &Response,
173
        _max_weight: &Weight,
174
        _querier: &Option<Location>,
175
    ) -> XCMWeight {
176
        XcmGeneric::<Runtime>::query_response()
177
    }
178
4
    fn transfer_asset(assets: &Assets, _dest: &Location) -> XCMWeight {
179
4
        assets.weigh_assets(XcmBalancesWeight::<Runtime>::transfer_asset())
180
4
    }
181
    fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> XCMWeight {
182
        assets.weigh_assets(XcmBalancesWeight::<Runtime>::transfer_reserve_asset())
183
    }
184
    fn transact(
185
        _origin_type: &OriginKind,
186
        _require_weight_at_most: &Option<Weight>,
187
        _call: &DoubleEncoded<RuntimeCall>,
188
    ) -> XCMWeight {
189
        XcmGeneric::<Runtime>::transact()
190
    }
191
    fn hrmp_new_channel_open_request(
192
        _sender: &u32,
193
        _max_message_size: &u32,
194
        _max_capacity: &u32,
195
    ) -> XCMWeight {
196
        // XCM Executor does not currently support HRMP channel operations
197
        Weight::MAX
198
    }
199
    fn hrmp_channel_accepted(_recipient: &u32) -> XCMWeight {
200
        // XCM Executor does not currently support HRMP channel operations
201
        Weight::MAX
202
    }
203
    fn hrmp_channel_closing(_initiator: &u32, _sender: &u32, _recipient: &u32) -> XCMWeight {
204
        // XCM Executor does not currently support HRMP channel operations
205
        Weight::MAX
206
    }
207
4
    fn clear_origin() -> XCMWeight {
208
4
        XcmGeneric::<Runtime>::clear_origin()
209
4
    }
210
6
    fn descend_origin(_who: &InteriorLocation) -> XCMWeight {
211
6
        XcmGeneric::<Runtime>::descend_origin()
212
6
    }
213
    fn report_error(_query_response_info: &QueryResponseInfo) -> XCMWeight {
214
        XcmGeneric::<Runtime>::report_error()
215
    }
216
24
    fn deposit_asset(assets: &AssetFilter, _dest: &Location) -> XCMWeight {
217
24
        assets.weigh_assets(XcmBalancesWeight::<Runtime>::deposit_asset())
218
24
    }
219
    fn deposit_reserve_asset(assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> XCMWeight {
220
        assets.weigh_assets(XcmBalancesWeight::<Runtime>::deposit_reserve_asset())
221
    }
222
    fn exchange_asset(_give: &AssetFilter, _receive: &Assets, _maximal: &bool) -> XCMWeight {
223
        Weight::MAX
224
    }
225
    fn initiate_reserve_withdraw(
226
        assets: &AssetFilter,
227
        _reserve: &Location,
228
        _xcm: &Xcm<()>,
229
    ) -> XCMWeight {
230
        assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_reserve_withdraw())
231
    }
232
    fn initiate_teleport(_assets: &AssetFilter, _dest: &Location, _xcm: &Xcm<()>) -> XCMWeight {
233
        XCMWeight::MAX
234
    }
235
    fn report_holding(_response_info: &QueryResponseInfo, _assets: &AssetFilter) -> Weight {
236
        XcmGeneric::<Runtime>::report_holding()
237
    }
238
14
    fn buy_execution(_fees: &Asset, _weight_limit: &WeightLimit) -> XCMWeight {
239
14
        XcmGeneric::<Runtime>::buy_execution()
240
14
    }
241
1
    fn refund_surplus() -> XCMWeight {
242
1
        XcmGeneric::<Runtime>::refund_surplus()
243
1
    }
244
    fn set_error_handler(_xcm: &Xcm<RuntimeCall>) -> XCMWeight {
245
        XcmGeneric::<Runtime>::set_error_handler()
246
    }
247
4
    fn set_appendix(_xcm: &Xcm<RuntimeCall>) -> XCMWeight {
248
4
        XcmGeneric::<Runtime>::set_appendix()
249
4
    }
250
    fn clear_error() -> XCMWeight {
251
        XcmGeneric::<Runtime>::clear_error()
252
    }
253
    fn claim_asset(assets: &Assets, _ticket: &Location) -> XCMWeight {
254
        assets.weigh_assets(XcmGeneric::<Runtime>::claim_asset())
255
    }
256
    fn trap(_code: &u64) -> XCMWeight {
257
        XcmGeneric::<Runtime>::trap()
258
    }
259
    fn subscribe_version(_query_id: &QueryId, _max_response_weight: &Weight) -> XCMWeight {
260
        XcmGeneric::<Runtime>::subscribe_version()
261
    }
262
    fn unsubscribe_version() -> XCMWeight {
263
        XcmGeneric::<Runtime>::unsubscribe_version()
264
    }
265
4
    fn burn_asset(assets: &Assets) -> Weight {
266
4
        assets.weigh_assets(XcmGeneric::<Runtime>::burn_asset())
267
4
    }
268
    fn expect_asset(assets: &Assets) -> Weight {
269
        assets.weigh_assets(XcmGeneric::<Runtime>::expect_asset())
270
    }
271
    fn expect_origin(_origin: &Option<Location>) -> Weight {
272
        XcmGeneric::<Runtime>::expect_origin()
273
    }
274
    fn expect_error(_error: &Option<(u32, XcmError)>) -> Weight {
275
        XcmGeneric::<Runtime>::expect_error()
276
    }
277
    fn expect_transact_status(_transact_status: &MaybeErrorCode) -> Weight {
278
        XcmGeneric::<Runtime>::expect_transact_status()
279
    }
280
    fn query_pallet(_module_name: &Vec<u8>, _response_info: &QueryResponseInfo) -> Weight {
281
        XcmGeneric::<Runtime>::query_pallet()
282
    }
283
    fn expect_pallet(
284
        _index: &u32,
285
        _name: &Vec<u8>,
286
        _module_name: &Vec<u8>,
287
        _crate_major: &u32,
288
        _min_crate_minor: &u32,
289
    ) -> Weight {
290
        XcmGeneric::<Runtime>::expect_pallet()
291
    }
292
    fn report_transact_status(_response_info: &QueryResponseInfo) -> Weight {
293
        XcmGeneric::<Runtime>::report_transact_status()
294
    }
295
    fn clear_transact_status() -> Weight {
296
        XcmGeneric::<Runtime>::clear_transact_status()
297
    }
298
4
    fn universal_origin(_: &Junction) -> Weight {
299
4
        XcmGeneric::<Runtime>::universal_origin()
300
4
    }
301
    fn export_message(_: &NetworkId, _: &Junctions, _: &Xcm<()>) -> Weight {
302
        Weight::MAX
303
    }
304
    fn lock_asset(_: &Asset, _: &Location) -> Weight {
305
        Weight::MAX
306
    }
307
    fn unlock_asset(_: &Asset, _: &Location) -> Weight {
308
        Weight::MAX
309
    }
310
    fn note_unlockable(_: &Asset, _: &Location) -> Weight {
311
        Weight::MAX
312
    }
313
    fn request_unlock(_: &Asset, _: &Location) -> Weight {
314
        Weight::MAX
315
    }
316
    fn set_fees_mode(_: &bool) -> Weight {
317
        XcmGeneric::<Runtime>::set_fees_mode()
318
    }
319
13
    fn set_topic(_topic: &[u8; 32]) -> Weight {
320
13
        XcmGeneric::<Runtime>::set_topic()
321
13
    }
322
    fn clear_topic() -> Weight {
323
        XcmGeneric::<Runtime>::clear_topic()
324
    }
325
    fn alias_origin(_: &Location) -> Weight {
326
        // XCM Executor does not currently support alias origin operations
327
        Weight::MAX
328
    }
329
    fn unpaid_execution(_: &WeightLimit, _: &Option<Location>) -> Weight {
330
        XcmGeneric::<Runtime>::unpaid_execution()
331
    }
332

            
333
    fn pay_fees(_: &Asset) -> Weight {
334
        XcmGeneric::<Runtime>::pay_fees()
335
    }
336

            
337
1
    fn initiate_transfer(
338
1
        _dest: &Location,
339
1
        remote_fees: &Option<AssetTransferFilter>,
340
1
        _preserve_origin: &bool,
341
1
        assets: &BoundedVec<AssetTransferFilter, MaxAssetTransferFilters>,
342
1
        _xcm: &Xcm<()>,
343
1
    ) -> Weight {
344
1
        let mut weight = if let Some(remote_fees) = remote_fees {
345
1
            let fees = remote_fees.inner();
346
1
            fees.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer())
347
        } else {
348
            Weight::zero()
349
        };
350
2
        for asset_filter in assets {
351
1
            let assets = asset_filter.inner();
352
1
            let extra = assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer());
353
1
            weight = weight.saturating_add(extra);
354
1
        }
355
1
        weight
356
1
    }
357

            
358
    fn execute_with_origin(_: &Option<InteriorLocation>, _: &Xcm<RuntimeCall>) -> Weight {
359
        XcmGeneric::<Runtime>::execute_with_origin()
360
    }
361

            
362
    fn set_hints(hints: &BoundedVec<Hint, HintNumVariants>) -> Weight {
363
        let mut weight = Weight::zero();
364
        for hint in hints {
365
            match hint {
366
                AssetClaimer { .. } => {
367
                    weight = weight.saturating_add(XcmGeneric::<Runtime>::asset_claimer());
368
                }
369
            }
370
        }
371
        weight
372
    }
373
}