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

            
35
const MAX_ASSETS: u64 = 1;
36

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

            
43
impl From<&Asset> for AssetTypes {
44
108
    fn from(asset: &Asset) -> Self {
45
50
        match asset {
46
            Asset {
47
                id:
48
                    AssetId(Location {
49
                        parents: 0,
50
                        interior: Here,
51
                    }),
52
                ..
53
50
            } => AssetTypes::Balances,
54
            Asset {
55
                id:
56
                    AssetId(Location {
57
                        parents: 1,
58
58
                        interior,
59
                    }),
60
                ..
61
            } => {
62
58
                if let Some(GlobalConsensus(Ethereum { .. })) = interior.first() {
63
58
                    AssetTypes::Ethereum
64
                } else {
65
                    AssetTypes::Unknown
66
                }
67
            }
68
            _ => AssetTypes::Unknown,
69
        }
70
108
    }
71
}
72

            
73
trait WeighAssets {
74
    fn weigh_assets(&self, balances_weight: Weight) -> Weight;
75
}
76

            
77
impl WeighAssets for AssetFilter {
78
68
    fn weigh_assets(&self, balances_weight: Weight) -> Weight {
79
48
        match self {
80
20
            Self::Definite(assets) => assets
81
20
                .inner()
82
20
                .iter()
83
20
                .map(From::from)
84
20
                .map(|t| match t {
85
                    AssetTypes::Balances => balances_weight,
86
20
                    AssetTypes::Ethereum => balances_weight,
87
                    AssetTypes::Unknown => Weight::MAX,
88
20
                })
89
20
                .fold(Weight::zero(), |acc, x| acc.saturating_add(x)),
90
            Self::Wild(AllOf { .. } | AllOfCounted { .. }) => balances_weight,
91
48
            Self::Wild(AllCounted(count)) => {
92
48
                balances_weight.saturating_mul(MAX_ASSETS.min(u64::from(*count)))
93
            }
94
            Self::Wild(All) => balances_weight.saturating_mul(MAX_ASSETS),
95
        }
96
68
    }
97
}
98

            
99
impl WeighAssets for Assets {
100
68
    fn weigh_assets(&self, balances_weight: Weight) -> Weight {
101
68
        self.inner()
102
68
            .iter()
103
68
            .map(<AssetTypes as From<&Asset>>::from)
104
88
            .map(|t| match t {
105
50
                AssetTypes::Balances => balances_weight,
106
38
                AssetTypes::Ethereum => balances_weight,
107
                AssetTypes::Unknown => Weight::MAX,
108
88
            })
109
88
            .fold(Weight::zero(), |acc, x| acc.saturating_add(x))
110
68
    }
111
}
112

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

            
296
    fn pay_fees(_asset: &Asset) -> Weight {
297
        XcmGeneric::<Runtime>::pay_fees()
298
    }
299

            
300
    fn initiate_transfer(
301
        _dest: &Location,
302
        remote_fees: &Option<AssetTransferFilter>,
303
        _preserve_origin: &bool,
304
        assets: &BoundedVec<AssetTransferFilter, MaxAssetTransferFilters>,
305
        _xcm: &Xcm<()>,
306
    ) -> Weight {
307
        let mut weight = if let Some(remote_fees) = remote_fees {
308
            let fees = remote_fees.inner();
309
            fees.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer())
310
        } else {
311
            Weight::zero()
312
        };
313
        for asset_filter in assets {
314
            let assets = asset_filter.inner();
315
            let extra = assets.weigh_assets(XcmBalancesWeight::<Runtime>::initiate_transfer());
316
            weight = weight.saturating_add(extra);
317
        }
318
        weight
319
    }
320

            
321
    fn execute_with_origin(
322
        _descendant_origin: &Option<InteriorLocation>,
323
        _xcm: &Xcm<RuntimeCall>,
324
    ) -> Weight {
325
        XcmGeneric::<Runtime>::execute_with_origin()
326
    }
327

            
328
    fn set_hints(hints: &BoundedVec<Hint, HintNumVariants>) -> Weight {
329
        let mut weight = Weight::zero();
330
        for hint in hints {
331
            match hint {
332
                AssetClaimer { .. } => {
333
                    weight = weight.saturating_add(XcmGeneric::<Runtime>::asset_claimer());
334
                }
335
            }
336
        }
337
        weight
338
    }
339
}