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
mod pallet_xcm_benchmarks_fungible;
18
mod pallet_xcm_benchmarks_generic;
19

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

            
34
const MAX_ASSETS: u64 = 1;
35

            
36
pub enum AssetTypes {
37
    Balances,
38
    Ethereum,
39
    ChildParachain,
40
    Unknown,
41
}
42

            
43
impl From<&Asset> for AssetTypes {
44
792
    fn from(asset: &Asset) -> Self {
45
547
        match asset {
46
            Asset {
47
                id:
48
                    AssetId(Location {
49
                        parents: 0,
50
                        interior: Here,
51
                    }),
52
                ..
53
487
            } => AssetTypes::Balances,
54
            Asset {
55
                id:
56
                    AssetId(Location {
57
                        parents: 1,
58
245
                        interior,
59
                    }),
60
                ..
61
            } => {
62
245
                if let Some(GlobalConsensus(Ethereum { .. })) = interior.first() {
63
245
                    AssetTypes::Ethereum
64
                } else {
65
                    AssetTypes::Unknown
66
                }
67
            }
68
            Asset {
69
                id:
70
                    AssetId(Location {
71
                        parents: 0,
72
60
                        interior,
73
                    }),
74
                ..
75
            } => {
76
60
                if let Some(Parachain(_)) = interior.first() {
77
60
                    AssetTypes::ChildParachain
78
                } else {
79
                    AssetTypes::Unknown
80
                }
81
            }
82
            _ => AssetTypes::Unknown,
83
        }
84
792
    }
85
}
86

            
87
trait WeighAssets {
88
    fn weigh_assets(&self, balances_weight: Weight) -> Weight;
89
}
90

            
91
impl WeighAssets for AssetFilter {
92
430
    fn weigh_assets(&self, balances_weight: Weight) -> Weight {
93
100
        match self {
94
330
            Self::Definite(assets) => assets
95
330
                .inner()
96
330
                .iter()
97
330
                .map(From::from)
98
330
                .map(|t| match t {
99
224
                    AssetTypes::Balances => balances_weight,
100
106
                    AssetTypes::Ethereum => balances_weight,
101
                    AssetTypes::ChildParachain => balances_weight,
102
                    AssetTypes::Unknown => Weight::MAX,
103
330
                })
104
330
                .fold(Weight::zero(), |acc, x| acc.saturating_add(x)),
105
            Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight,
106
100
            Self::Wild(AllCounted(count)) => {
107
100
                balances_weight.saturating_mul(MAX_ASSETS.min(u64::from(*count)))
108
            }
109
            Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS),
110
        }
111
430
    }
112
}
113

            
114
impl WeighAssets for Assets {
115
437
    fn weigh_assets(&self, balances_weight: Weight) -> Weight {
116
437
        self.inner()
117
437
            .iter()
118
437
            .map(<AssetTypes as From<&Asset>>::from)
119
462
            .map(|t| match t {
120
263
                AssetTypes::Balances => balances_weight,
121
139
                AssetTypes::Ethereum => balances_weight,
122
60
                AssetTypes::ChildParachain => balances_weight,
123
                AssetTypes::Unknown => Weight::MAX,
124
462
            })
125
462
            .fold(Weight::zero(), |acc, x| acc.saturating_add(x))
126
437
    }
127
}
128

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

            
312
    fn pay_fees(_asset: &Asset) -> Weight {
313
        XcmGeneric::<Runtime>::pay_fees()
314
    }
315

            
316
23
    fn initiate_transfer(
317
23
        _dest: &Location,
318
23
        remote_fees: &Option<AssetTransferFilter>,
319
23
        _preserve_origin: &bool,
320
23
        assets: &BoundedVec<AssetTransferFilter, MaxAssetTransferFilters>,
321
23
        _xcm: &Xcm<()>,
322
23
    ) -> Weight {
323
23
        let mut weight = if let Some(remote_fees) = remote_fees {
324
23
            let fees = remote_fees.inner();
325
23
            fees.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer())
326
        } else {
327
            Weight::zero()
328
        };
329
40
        for asset_filter in assets {
330
17
            let assets = asset_filter.inner();
331
17
            let extra = assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer());
332
17
            weight = weight.saturating_add(extra);
333
17
        }
334
23
        weight
335
23
    }
336

            
337
    fn execute_with_origin(
338
        _descendant_origin: &Option<InteriorLocation>,
339
        _xcm: &Xcm<RuntimeCall>,
340
    ) -> Weight {
341
        XcmGeneric::<Runtime>::execute_with_origin()
342
    }
343

            
344
36
    fn set_hints(hints: &BoundedVec<Hint, HintNumVariants>) -> Weight {
345
36
        let mut weight = Weight::zero();
346
72
        for hint in hints {
347
36
            match hint {
348
36
                AssetClaimer { .. } => {
349
36
                    weight = weight.saturating_add(XcmGeneric::<Runtime>::asset_claimer());
350
36
                }
351
            }
352
        }
353
36
        weight
354
36
    }
355
}