git.delta.rocks / unique-network / refs/commits / e8fdadb89923

difftreelog

source

pallets/contracts/src/schedule.rs24.5 KiBsourcehistory
1// This file is part of Substrate.23// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.4// SPDX-License-Identifier: Apache-2.056// Licensed under the Apache License, Version 2.0 (the "License");7// you may not use this file except in compliance with the License.8// You may obtain a copy of the License at9//10// 	http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// distributed under the License is distributed on an "AS IS" BASIS,14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15// See the License for the specific language governing permissions and16// limitations under the License.1718//! This module contains the cost schedule and supporting code that constructs a19//! sane default schedule from a `WeightInfo` implementation.2021use crate::{Config, weights::WeightInfo};2223#[cfg(feature = "std")]24use serde::{Serialize, Deserialize};25use pallet_contracts_proc_macro::{ScheduleDebug, WeightDebug};26use frame_support::weights::Weight;27use sp_std::{marker::PhantomData, vec::Vec};28use codec::{Encode, Decode};29use parity_wasm::elements;30use pwasm_utils::rules;31use sp_runtime::RuntimeDebug;3233/// How many API calls are executed in a single batch. The reason for increasing the amount34/// of API calls in batches (per benchmark component increase) is so that the linear regression35/// has an easier time determining the contribution of that component.36pub const API_BENCHMARK_BATCH_SIZE: u32 = 100;3738/// How many instructions are executed in a single batch. The reasoning is the same39/// as for `API_BENCHMARK_BATCH_SIZE`.40pub const INSTR_BENCHMARK_BATCH_SIZE: u32 = 1_000;4142/// Definition of the cost schedule and other parameterizations for the wasm vm.43///44/// Its fields are private to the crate in order to allow addition of new contract45/// callable functions without bumping to a new major version. A genesis config should46/// rely on public functions of this type.47#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]48#[cfg_attr(feature = "std", serde(bound(serialize = "", deserialize = "")))]49#[derive(Clone, Encode, Decode, PartialEq, Eq, ScheduleDebug)]50pub struct Schedule<T: Config> {51	/// Version of the schedule.52	///53	/// # Note54	///55	/// Must be incremented whenever the [`self.instruction_weights`] are changed. The56	/// reason is that changes to instruction weights require a re-instrumentation57	/// of all contracts which are triggered by a version comparison on call.58	/// Changes to other parts of the schedule should not increment the version in59	/// order to avoid unnecessary re-instrumentations.60	pub(crate) version: u32,6162	/// Whether the `seal_println` function is allowed to be used contracts.63	/// MUST only be enabled for `dev` chains, NOT for production chains64	pub(crate) enable_println: bool,6566	/// Describes the upper limits on various metrics.67	pub(crate) limits: Limits,6869	/// The weights for individual wasm instructions.70	pub(crate) instruction_weights: InstructionWeights<T>,7172	/// The weights for each imported function a contract is allowed to call.73	pub(crate) host_fn_weights: HostFnWeights<T>,74}7576/// Describes the upper limits on various metrics.77///78/// # Note79///80/// The values in this struct should only ever be increased for a deployed chain. The reason81/// is that decreasing those values will break existing contracts which are above the new limits.82#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]83#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)]84pub struct Limits {85	/// The maximum number of topics supported by an event.86	pub event_topics: u32,8788	/// Maximum allowed stack height in number of elements.89	///90	/// See <https://wiki.parity.io/WebAssembly-StackHeight> to find out91	/// how the stack frame cost is calculated. Each element can be of one of the92	/// wasm value types. This means the maximum size per element is 64bit.93	pub stack_height: u32,9495	/// Maximum number of globals a module is allowed to declare.96	///97	/// Globals are not limited through the `stack_height` as locals are. Neither does98	/// the linear memory limit `memory_pages` applies to them.99	pub globals: u32,100101	/// Maximum numbers of parameters a function can have.102	///103	/// Those need to be limited to prevent a potentially exploitable interaction with104	/// the stack height instrumentation: The costs of executing the stack height105	/// instrumentation for an indirectly called function scales linearly with the amount106	/// of parameters of this function. Because the stack height instrumentation itself is107	/// is not weight metered its costs must be static (via this limit) and included in108	/// the costs of the instructions that cause them (call, call_indirect).109	pub parameters: u32,110111	/// Maximum number of memory pages allowed for a contract.112	pub memory_pages: u32,113114	/// Maximum number of elements allowed in a table.115	///116	/// Currently, the only type of element that is allowed in a table is funcref.117	pub table_size: u32,118119	/// Maximum number of elements that can appear as immediate value to the br_table instruction.120	pub br_table_size: u32,121122	/// The maximum length of a subject in bytes used for PRNG generation.123	pub subject_len: u32,124}125126impl Limits {127	/// The maximum memory size in bytes that a contract can occupy.128	pub fn max_memory_size(&self) -> u32 {129		self.memory_pages * 64 * 1024130	}131}132133/// Describes the weight for all categories of supported wasm instructions.134///135/// There there is one field for each wasm instruction that describes the weight to136/// execute one instruction of that name. There are a few execptions:137///138/// 1. If there is a i64 and a i32 variant of an instruction we use the weight139///    of the former for both.140/// 2. The following instructions are free of charge because they merely structure the141///    wasm module and cannot be spammed without making the module invalid (and rejected):142///    End, Unreachable, Return, Else143/// 3. The following instructions cannot be benchmarked because they are removed by any144///    real world execution engine as a preprocessing step and therefore don't yield a145///    meaningful benchmark result. However, in contrast to the instructions mentioned146///    in 2. they can be spammed. We price them with the same weight as the "default"147///    instruction (i64.const): Block, Loop, Nop148/// 4. We price both i64.const and drop as InstructionWeights.i64const / 2. The reason149///    for that is that we cannot benchmark either of them on its own but we need their150///    individual values to derive (by subtraction) the weight of all other instructions151///    that use them as supporting instructions. Supporting means mainly pushing arguments152///    and dropping return values in order to maintain a valid module.153#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]154#[derive(Clone, Encode, Decode, PartialEq, Eq, WeightDebug)]155pub struct InstructionWeights<T: Config> {156	pub i64const: u32,157	pub i64load: u32,158	pub i64store: u32,159	pub select: u32,160	pub r#if: u32,161	pub br: u32,162	pub br_if: u32,163	pub br_table: u32,164	pub br_table_per_entry: u32,165	pub call: u32,166	pub call_indirect: u32,167	pub call_indirect_per_param: u32,168	pub local_get: u32,169	pub local_set: u32,170	pub local_tee: u32,171	pub global_get: u32,172	pub global_set: u32,173	pub memory_current: u32,174	pub memory_grow: u32,175	pub i64clz: u32,176	pub i64ctz: u32,177	pub i64popcnt: u32,178	pub i64eqz: u32,179	pub i64extendsi32: u32,180	pub i64extendui32: u32,181	pub i32wrapi64: u32,182	pub i64eq: u32,183	pub i64ne: u32,184	pub i64lts: u32,185	pub i64ltu: u32,186	pub i64gts: u32,187	pub i64gtu: u32,188	pub i64les: u32,189	pub i64leu: u32,190	pub i64ges: u32,191	pub i64geu: u32,192	pub i64add: u32,193	pub i64sub: u32,194	pub i64mul: u32,195	pub i64divs: u32,196	pub i64divu: u32,197	pub i64rems: u32,198	pub i64remu: u32,199	pub i64and: u32,200	pub i64or: u32,201	pub i64xor: u32,202	pub i64shl: u32,203	pub i64shrs: u32,204	pub i64shru: u32,205	pub i64rotl: u32,206	pub i64rotr: u32,207	/// The type parameter is used in the default implementation.208	#[codec(skip)]209	pub _phantom: PhantomData<T>,210}211212/// Describes the weight for each imported function that a contract is allowed to call.213#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]214#[derive(Clone, Encode, Decode, PartialEq, Eq, WeightDebug)]215pub struct HostFnWeights<T: Config> {216	/// Weight of calling `seal_caller`.217	pub caller: Weight,218219	/// Weight of calling `seal_address`.220	pub address: Weight,221222	/// Weight of calling `seal_gas_left`.223	pub gas_left: Weight,224225	/// Weight of calling `seal_balance`.226	pub balance: Weight,227228	/// Weight of calling `seal_value_transferred`.229	pub value_transferred: Weight,230231	/// Weight of calling `seal_minimum_balance`.232	pub minimum_balance: Weight,233234	/// Weight of calling `seal_tombstone_deposit`.235	pub tombstone_deposit: Weight,236237	/// Weight of calling `seal_rent_allowance`.238	pub rent_allowance: Weight,239240	/// Weight of calling `seal_block_number`.241	pub block_number: Weight,242243	/// Weight of calling `seal_now`.244	pub now: Weight,245246	/// Weight of calling `seal_weight_to_fee`.247	pub weight_to_fee: Weight,248249	/// Weight of calling `gas`.250	pub gas: Weight,251252	/// Weight of calling `seal_input`.253	pub input: Weight,254255	/// Weight per input byte copied to contract memory by `seal_input`.256	pub input_per_byte: Weight,257258	/// Weight of calling `seal_return`.259	pub r#return: Weight,260261	/// Weight per byte returned through `seal_return`.262	pub return_per_byte: Weight,263264	/// Weight of calling `seal_terminate`.265	pub terminate: Weight,266267	/// Weight per byte of the terminated contract.268	pub terminate_per_code_byte: Weight,269270	/// Weight of calling `seal_restore_to`.271	pub restore_to: Weight,272273	/// Weight per byte of the restoring contract.274	pub restore_to_per_caller_code_byte: Weight,275276	/// Weight per byte of the restored contract.277	pub restore_to_per_tombstone_code_byte: Weight,278279	/// Weight per delta key supplied to `seal_restore_to`.280	pub restore_to_per_delta: Weight,281282	/// Weight of calling `seal_random`.283	pub random: Weight,284285	/// Weight of calling `seal_reposit_event`.286	pub deposit_event: Weight,287288	/// Weight per topic supplied to `seal_deposit_event`.289	pub deposit_event_per_topic: Weight,290291	/// Weight per byte of an event deposited through `seal_deposit_event`.292	pub deposit_event_per_byte: Weight,293294	/// Weight of calling `seal_set_rent_allowance`.295	pub set_rent_allowance: Weight,296297	/// Weight of calling `seal_set_storage`.298	pub set_storage: Weight,299300	/// Weight per byte of an item stored with `seal_set_storage`.301	pub set_storage_per_byte: Weight,302303	/// Weight of calling `seal_clear_storage`.304	pub clear_storage: Weight,305306	/// Weight of calling `seal_get_storage`.307	pub get_storage: Weight,308309	/// Weight per byte of an item received via `seal_get_storage`.310	pub get_storage_per_byte: Weight,311312	/// Weight of calling `seal_transfer`.313	pub transfer: Weight,314315	/// Weight of calling `seal_call`.316	pub call: Weight,317318	/// Weight per byte of the called contract.319	pub call_per_code_byte: Weight,320321	/// Weight surcharge that is claimed if `seal_call` does a balance transfer.322	pub call_transfer_surcharge: Weight,323324	/// Weight per input byte supplied to `seal_call`.325	pub call_per_input_byte: Weight,326327	/// Weight per output byte received through `seal_call`.328	pub call_per_output_byte: Weight,329330	/// Weight of calling `seal_instantiate`.331	pub instantiate: Weight,332333	/// Weight per byte of the instantiated contract.334	pub instantiate_per_code_byte: Weight,335336	/// Weight per input byte supplied to `seal_instantiate`.337	pub instantiate_per_input_byte: Weight,338339	/// Weight per output byte received through `seal_instantiate`.340	pub instantiate_per_output_byte: Weight,341342	/// Weight per salt byte supplied to `seal_instantiate`.343	pub instantiate_per_salt_byte: Weight,344345	/// Weight of calling `seal_hash_sha_256`.346	pub hash_sha2_256: Weight,347348	/// Weight per byte hashed by `seal_hash_sha_256`.349	pub hash_sha2_256_per_byte: Weight,350351	/// Weight of calling `seal_hash_keccak_256`.352	pub hash_keccak_256: Weight,353354	/// Weight per byte hashed by `seal_hash_keccak_256`.355	pub hash_keccak_256_per_byte: Weight,356357	/// Weight of calling `seal_hash_blake2_256`.358	pub hash_blake2_256: Weight,359360	/// Weight per byte hashed by `seal_hash_blake2_256`.361	pub hash_blake2_256_per_byte: Weight,362363	/// Weight of calling `seal_hash_blake2_128`.364	pub hash_blake2_128: Weight,365366	/// Weight per byte hashed by `seal_hash_blake2_128`.367	pub hash_blake2_128_per_byte: Weight,368369	/// Weight of calling `seal_rent_params`.370	pub rent_params: Weight,371372	/// The type parameter is used in the default implementation.373	#[codec(skip)]374	pub _phantom: PhantomData<T>,375}376377macro_rules! replace_token {378	($_in:tt $replacement:tt) => {379		$replacement380	};381}382383macro_rules! call_zero {384	($name:ident, $( $arg:expr ),*) => {385		T::WeightInfo::$name($( replace_token!($arg 0) ),*)386	};387}388389macro_rules! cost_args {390	($name:ident, $( $arg: expr ),+) => {391		(T::WeightInfo::$name($( $arg ),+).saturating_sub(call_zero!($name, $( $arg ),+)))392	}393}394395macro_rules! cost_batched_args {396	($name:ident, $( $arg: expr ),+) => {397		cost_args!($name, $( $arg ),+) / Weight::from(API_BENCHMARK_BATCH_SIZE)398	}399}400401macro_rules! cost_instr_no_params_with_batch_size {402	($name:ident, $batch_size:expr) => {403		(cost_args!($name, 1) / Weight::from($batch_size)) as u32404	};405}406407macro_rules! cost_instr_with_batch_size {408	($name:ident, $num_params:expr, $batch_size:expr) => {409		cost_instr_no_params_with_batch_size!($name, $batch_size).saturating_sub(410			(cost_instr_no_params_with_batch_size!(instr_i64const, $batch_size) / 2)411				.saturating_mul($num_params),412		)413	};414}415416macro_rules! cost_instr {417	($name:ident, $num_params:expr) => {418		cost_instr_with_batch_size!($name, $num_params, INSTR_BENCHMARK_BATCH_SIZE)419	};420}421422macro_rules! cost_byte_args {423	($name:ident, $( $arg: expr ),+) => {424		cost_args!($name, $( $arg ),+) / 1024425	}426}427428macro_rules! cost_byte_batched_args {429	($name:ident, $( $arg: expr ),+) => {430		cost_batched_args!($name, $( $arg ),+) / 1024431	}432}433434macro_rules! cost {435	($name:ident) => {436		cost_args!($name, 1)437	};438}439440macro_rules! cost_batched {441	($name:ident) => {442		cost_batched_args!($name, 1)443	};444}445446macro_rules! cost_byte {447	($name:ident) => {448		cost_byte_args!($name, 1)449	};450}451452macro_rules! cost_byte_batched {453	($name:ident) => {454		cost_byte_batched_args!($name, 1)455	};456}457458impl<T: Config> Default for Schedule<T> {459	fn default() -> Self {460		Self {461			version: 0,462			enable_println: false,463			limits: Default::default(),464			instruction_weights: Default::default(),465			host_fn_weights: Default::default(),466		}467	}468}469470impl Default for Limits {471	fn default() -> Self {472		Self {473			event_topics: 4,474			// 512 * sizeof(i64) will give us a 4k stack.475			stack_height: 512,476			globals: 256,477			parameters: 128,478			memory_pages: 16,479			// 4k function pointers (This is in count not bytes).480			table_size: 4096,481			br_table_size: 256,482			subject_len: 32,483		}484	}485}486487impl<T: Config> Default for InstructionWeights<T> {488	fn default() -> Self {489		let max_pages = Limits::default().memory_pages;490		Self {491			i64const: cost_instr!(instr_i64const, 1),492			i64load: cost_instr!(instr_i64load, 2),493			i64store: cost_instr!(instr_i64store, 2),494			select: cost_instr!(instr_select, 4),495			r#if: cost_instr!(instr_if, 3),496			br: cost_instr!(instr_br, 2),497			br_if: cost_instr!(instr_br_if, 5),498			br_table: cost_instr!(instr_br_table, 3),499			br_table_per_entry: cost_instr!(instr_br_table_per_entry, 0),500			call: cost_instr!(instr_call, 2),501			call_indirect: cost_instr!(instr_call_indirect, 3),502			call_indirect_per_param: cost_instr!(instr_call_indirect_per_param, 1),503			local_get: cost_instr!(instr_local_get, 1),504			local_set: cost_instr!(instr_local_set, 1),505			local_tee: cost_instr!(instr_local_tee, 2),506			global_get: cost_instr!(instr_global_get, 1),507			global_set: cost_instr!(instr_global_set, 1),508			memory_current: cost_instr!(instr_memory_current, 1),509			memory_grow: cost_instr_with_batch_size!(instr_memory_grow, 1, max_pages),510			i64clz: cost_instr!(instr_i64clz, 2),511			i64ctz: cost_instr!(instr_i64ctz, 2),512			i64popcnt: cost_instr!(instr_i64popcnt, 2),513			i64eqz: cost_instr!(instr_i64eqz, 2),514			i64extendsi32: cost_instr!(instr_i64extendsi32, 2),515			i64extendui32: cost_instr!(instr_i64extendui32, 2),516			i32wrapi64: cost_instr!(instr_i32wrapi64, 2),517			i64eq: cost_instr!(instr_i64eq, 3),518			i64ne: cost_instr!(instr_i64ne, 3),519			i64lts: cost_instr!(instr_i64lts, 3),520			i64ltu: cost_instr!(instr_i64ltu, 3),521			i64gts: cost_instr!(instr_i64gts, 3),522			i64gtu: cost_instr!(instr_i64gtu, 3),523			i64les: cost_instr!(instr_i64les, 3),524			i64leu: cost_instr!(instr_i64leu, 3),525			i64ges: cost_instr!(instr_i64ges, 3),526			i64geu: cost_instr!(instr_i64geu, 3),527			i64add: cost_instr!(instr_i64add, 3),528			i64sub: cost_instr!(instr_i64sub, 3),529			i64mul: cost_instr!(instr_i64mul, 3),530			i64divs: cost_instr!(instr_i64divs, 3),531			i64divu: cost_instr!(instr_i64divu, 3),532			i64rems: cost_instr!(instr_i64rems, 3),533			i64remu: cost_instr!(instr_i64remu, 3),534			i64and: cost_instr!(instr_i64and, 3),535			i64or: cost_instr!(instr_i64or, 3),536			i64xor: cost_instr!(instr_i64xor, 3),537			i64shl: cost_instr!(instr_i64shl, 3),538			i64shrs: cost_instr!(instr_i64shrs, 3),539			i64shru: cost_instr!(instr_i64shru, 3),540			i64rotl: cost_instr!(instr_i64rotl, 3),541			i64rotr: cost_instr!(instr_i64rotr, 3),542			_phantom: PhantomData,543		}544	}545}546547impl<T: Config> Default for HostFnWeights<T> {548	fn default() -> Self {549		Self {550			caller: cost_batched!(seal_caller),551			address: cost_batched!(seal_address),552			gas_left: cost_batched!(seal_gas_left),553			balance: cost_batched!(seal_balance),554			value_transferred: cost_batched!(seal_value_transferred),555			minimum_balance: cost_batched!(seal_minimum_balance),556			tombstone_deposit: cost_batched!(seal_tombstone_deposit),557			rent_allowance: cost_batched!(seal_rent_allowance),558			block_number: cost_batched!(seal_block_number),559			now: cost_batched!(seal_now),560			weight_to_fee: cost_batched!(seal_weight_to_fee),561			gas: cost_batched!(seal_gas),562			input: cost!(seal_input),563			input_per_byte: cost_byte!(seal_input_per_kb),564			r#return: cost!(seal_return),565			return_per_byte: cost_byte!(seal_return_per_kb),566			terminate: cost!(seal_terminate),567			terminate_per_code_byte: cost_byte!(seal_terminate_per_code_kb),568			restore_to: cost!(seal_restore_to),569			restore_to_per_caller_code_byte: cost_byte_args!(570				seal_restore_to_per_code_kb_delta,571				1,572				0,573				0574			),575			restore_to_per_tombstone_code_byte: cost_byte_args!(576				seal_restore_to_per_code_kb_delta,577				0,578				1,579				0580			),581			restore_to_per_delta: cost_batched_args!(seal_restore_to_per_code_kb_delta, 0, 0, 1),582			random: cost_batched!(seal_random),583			deposit_event: cost_batched!(seal_deposit_event),584			deposit_event_per_topic: cost_batched_args!(seal_deposit_event_per_topic_and_kb, 1, 0),585			deposit_event_per_byte: cost_byte_batched_args!(586				seal_deposit_event_per_topic_and_kb,587				0,588				1589			),590			set_rent_allowance: cost_batched!(seal_set_rent_allowance),591			set_storage: cost_batched!(seal_set_storage),592			set_storage_per_byte: cost_byte_batched!(seal_set_storage_per_kb),593			clear_storage: cost_batched!(seal_clear_storage),594			get_storage: cost_batched!(seal_get_storage),595			get_storage_per_byte: cost_byte_batched!(seal_get_storage_per_kb),596			transfer: cost_batched!(seal_transfer),597			call: cost_batched!(seal_call),598			call_per_code_byte: cost_byte_batched_args!(599				seal_call_per_code_transfer_input_output_kb,600				1,601				0,602				0,603				0604			),605			call_transfer_surcharge: cost_batched_args!(606				seal_call_per_code_transfer_input_output_kb,607				0,608				1,609				0,610				0611			),612			call_per_input_byte: cost_byte_batched_args!(613				seal_call_per_code_transfer_input_output_kb,614				0,615				0,616				1,617				0618			),619			call_per_output_byte: cost_byte_batched_args!(620				seal_call_per_code_transfer_input_output_kb,621				0,622				0,623				0,624				1625			),626			instantiate: cost_batched!(seal_instantiate),627			instantiate_per_code_byte: cost_byte_batched_args!(628				seal_instantiate_per_code_input_output_salt_kb,629				1,630				0,631				0,632				0633			),634			instantiate_per_input_byte: cost_byte_batched_args!(635				seal_instantiate_per_code_input_output_salt_kb,636				0,637				1,638				0,639				0640			),641			instantiate_per_output_byte: cost_byte_batched_args!(642				seal_instantiate_per_code_input_output_salt_kb,643				0,644				0,645				1,646				0647			),648			instantiate_per_salt_byte: cost_byte_batched_args!(649				seal_instantiate_per_code_input_output_salt_kb,650				0,651				0,652				0,653				1654			),655			hash_sha2_256: cost_batched!(seal_hash_sha2_256),656			hash_sha2_256_per_byte: cost_byte_batched!(seal_hash_sha2_256_per_kb),657			hash_keccak_256: cost_batched!(seal_hash_keccak_256),658			hash_keccak_256_per_byte: cost_byte_batched!(seal_hash_keccak_256_per_kb),659			hash_blake2_256: cost_batched!(seal_hash_blake2_256),660			hash_blake2_256_per_byte: cost_byte_batched!(seal_hash_blake2_256_per_kb),661			hash_blake2_128: cost_batched!(seal_hash_blake2_128),662			hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb),663			rent_params: cost_batched!(seal_rent_params),664			_phantom: PhantomData,665		}666	}667}668669struct ScheduleRules<'a, T: Config> {670	schedule: &'a Schedule<T>,671	params: Vec<u32>,672}673674impl<T: Config> Schedule<T> {675	/// Allow contracts to call `seal_println` in order to print messages to the console.676	///677	/// This should only ever be activated in development chains. The printed messages678	/// can be observed on the console by setting the environment variable679	/// `RUST_LOG=runtime=debug` when running the node.680	///681	/// # Note682	///683	/// Is set to `false` by default.684	pub fn enable_println(mut self, enable: bool) -> Self {685		self.enable_println = enable;686		self687	}688689	pub(crate) fn rules(&self, module: &elements::Module) -> impl rules::Rules + '_ {690		ScheduleRules {691			schedule: &self,692			params: module693				.type_section()694				.iter()695				.flat_map(|section| section.types())696				.map(|func| {697					let elements::Type::Function(func) = func;698					func.params().len() as u32699				})700				.collect(),701		}702	}703}704705impl<'a, T: Config> rules::Rules for ScheduleRules<'a, T> {706	fn instruction_cost(&self, instruction: &elements::Instruction) -> Option<u32> {707		use parity_wasm::elements::Instruction::*;708		let w = &self.schedule.instruction_weights;709		let max_params = self.schedule.limits.parameters;710711		let weight = match *instruction {712			End | Unreachable | Return | Else => 0,713			I32Const(_) | I64Const(_) | Block(_) | Loop(_) | Nop | Drop => w.i64const,714			I32Load(_, _)715			| I32Load8S(_, _)716			| I32Load8U(_, _)717			| I32Load16S(_, _)718			| I32Load16U(_, _)719			| I64Load(_, _)720			| I64Load8S(_, _)721			| I64Load8U(_, _)722			| I64Load16S(_, _)723			| I64Load16U(_, _)724			| I64Load32S(_, _)725			| I64Load32U(_, _) => w.i64load,726			I32Store(_, _)727			| I32Store8(_, _)728			| I32Store16(_, _)729			| I64Store(_, _)730			| I64Store8(_, _)731			| I64Store16(_, _)732			| I64Store32(_, _) => w.i64store,733			Select => w.select,734			If(_) => w.r#if,735			Br(_) => w.br,736			BrIf(_) => w.br_if,737			Call(_) => w.call,738			GetLocal(_) => w.local_get,739			SetLocal(_) => w.local_set,740			TeeLocal(_) => w.local_tee,741			GetGlobal(_) => w.global_get,742			SetGlobal(_) => w.global_set,743			CurrentMemory(_) => w.memory_current,744			GrowMemory(_) => w.memory_grow,745			CallIndirect(idx, _) => *self.params.get(idx as usize).unwrap_or(&max_params),746			BrTable(ref data) => w747				.br_table748				.saturating_add(w.br_table_per_entry.saturating_mul(data.table.len() as u32)),749			I32Clz | I64Clz => w.i64clz,750			I32Ctz | I64Ctz => w.i64ctz,751			I32Popcnt | I64Popcnt => w.i64popcnt,752			I32Eqz | I64Eqz => w.i64eqz,753			I64ExtendSI32 => w.i64extendsi32,754			I64ExtendUI32 => w.i64extendui32,755			I32WrapI64 => w.i32wrapi64,756			I32Eq | I64Eq => w.i64eq,757			I32Ne | I64Ne => w.i64ne,758			I32LtS | I64LtS => w.i64lts,759			I32LtU | I64LtU => w.i64ltu,760			I32GtS | I64GtS => w.i64gts,761			I32GtU | I64GtU => w.i64gtu,762			I32LeS | I64LeS => w.i64les,763			I32LeU | I64LeU => w.i64leu,764			I32GeS | I64GeS => w.i64ges,765			I32GeU | I64GeU => w.i64geu,766			I32Add | I64Add => w.i64add,767			I32Sub | I64Sub => w.i64sub,768			I32Mul | I64Mul => w.i64mul,769			I32DivS | I64DivS => w.i64divs,770			I32DivU | I64DivU => w.i64divu,771			I32RemS | I64RemS => w.i64rems,772			I32RemU | I64RemU => w.i64remu,773			I32And | I64And => w.i64and,774			I32Or | I64Or => w.i64or,775			I32Xor | I64Xor => w.i64xor,776			I32Shl | I64Shl => w.i64shl,777			I32ShrS | I64ShrS => w.i64shrs,778			I32ShrU | I64ShrU => w.i64shru,779			I32Rotl | I64Rotl => w.i64rotl,780			I32Rotr | I64Rotr => w.i64rotr,781782			// Returning None makes the gas instrumentation fail which we intend for783			// unsupported or unknown instructions.784			_ => return None,785		};786		Some(weight)787	}788789	fn memory_grow_cost(&self) -> Option<rules::MemoryGrowCost> {790		// We benchmarked the memory.grow instruction with the maximum allowed pages.791		// The cost for growing is therefore already included in the instruction cost.792		None793	}794}795796#[cfg(test)]797mod test {798	use crate::tests::Test;799	use super::*;800801	#[test]802	fn print_test_schedule() {803		let schedule = Schedule::<Test>::default();804		println!("{:#?}", schedule);805	}806}