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

            
34
const MAX_ASSETS: u64 = 1;
35

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

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

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

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

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

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

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

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

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

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