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 {
22
    crate::Runtime,
23
    frame_support::weights::Weight,
24
    pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight,
25
    pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric,
26
    sp_std::prelude::*,
27
    xcm::{
28
        latest::{prelude::*, AssetTransferFilter, Weight as XCMWeight},
29
        DoubleEncoded,
30
    },
31
};
32

            
33
const MAX_ASSETS: u64 = 1;
34

            
35
pub enum AssetTypes {
36
    Balances,
37
    Ethereum,
38
    Unknown,
39
}
40

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

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

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

            
97
impl WeighAssets for Assets {
98
14
    fn weigh_assets(&self, balances_weight: Weight) -> Weight {
99
14
        self.inner()
100
14
            .into_iter()
101
14
            .map(|m| <AssetTypes as From<&Asset>>::from(m))
102
14
            .map(|t| match t {
103
10
                AssetTypes::Balances => balances_weight,
104
4
                AssetTypes::Ethereum => balances_weight,
105
                AssetTypes::Unknown => Weight::MAX,
106
14
            })
107
14
            .fold(Weight::zero(), |acc, x| acc.saturating_add(x))
108
14
    }
109
}
110

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

            
293
    fn pay_fees(_asset: &Asset) -> Weight {
294
        XcmGeneric::<Runtime>::pay_fees()
295
    }
296

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

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

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