pallet_contracts/schedule.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// 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 at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// 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 and
16// limitations under the License.
17
18//! This module contains the cost schedule and supporting code that constructs a
19//! sane default schedule from a `WeightInfo` implementation.
20
21use crate::{weights::WeightInfo, Config};
22
23use codec::{Decode, Encode};
24use core::marker::PhantomData;
25use frame_support::DefaultNoBound;
26use scale_info::TypeInfo;
27#[cfg(feature = "std")]
28use serde::{Deserialize, Serialize};
29
30/// Definition of the cost schedule and other parameterizations for the wasm vm.
31///
32/// Its [`Default`] implementation is the designated way to initialize this type. It uses
33/// the benchmarked information supplied by [`Config::WeightInfo`]. All of its fields are
34/// public and can therefore be modified. For example in order to change some of the limits
35/// and set a custom instruction weight version the following code could be used:
36/// ```rust
37/// use pallet_contracts::{Schedule, Limits, InstructionWeights, Config};
38///
39/// fn create_schedule<T: Config>() -> Schedule<T> {
40/// Schedule {
41/// limits: Limits {
42/// memory_pages: 16,
43/// .. Default::default()
44/// },
45/// instruction_weights: InstructionWeights {
46/// .. Default::default()
47/// },
48/// .. Default::default()
49/// }
50/// }
51/// ```
52#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
53#[cfg_attr(feature = "std", serde(bound(serialize = "", deserialize = "")))]
54#[cfg_attr(feature = "runtime-benchmarks", derive(frame_support::DebugNoBound))]
55#[derive(Clone, Encode, Decode, PartialEq, Eq, DefaultNoBound, TypeInfo)]
56#[scale_info(skip_type_params(T))]
57pub struct Schedule<T: Config> {
58 /// Describes the upper limits on various metrics.
59 pub limits: Limits,
60
61 /// The weights for individual wasm instructions.
62 pub instruction_weights: InstructionWeights<T>,
63}
64
65impl<T: Config> Schedule<T> {
66 /// Returns the reference time per engine fuel.
67 pub fn ref_time_by_fuel(&self) -> u64 {
68 self.instruction_weights.base as u64
69 }
70}
71
72/// Describes the upper limits on various metrics.
73#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
74#[cfg_attr(feature = "runtime-benchmarks", derive(Debug))]
75#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
76pub struct Limits {
77 /// The maximum number of topics supported by an event.
78 pub event_topics: u32,
79
80 /// Maximum number of memory pages allowed for a contract.
81 pub memory_pages: u32,
82
83 /// The maximum length of a subject in bytes used for PRNG generation.
84 pub subject_len: u32,
85
86 /// The maximum size of a storage value and event payload in bytes.
87 pub payload_len: u32,
88
89 /// The maximum node runtime memory. This is for integrity checks only and does not affect the
90 /// real setting.
91 pub runtime_memory: u32,
92
93 /// The maximum validator node runtime memory. This is for integrity checks only and does not
94 /// affect the real setting.
95 pub validator_runtime_memory: u32,
96
97 /// The additional ref_time added to the `deposit_event` host function call per event data
98 /// byte.
99 pub event_ref_time: u64,
100}
101
102impl Limits {
103 /// The maximum memory size in bytes that a contract can occupy.
104 pub fn max_memory_size(&self) -> u32 {
105 self.memory_pages * 64 * 1024
106 }
107}
108
109/// Gas metering of Wasm executed instructions is being done on the engine side.
110/// This struct holds a reference value used to gas units scaling between host and engine.
111#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
112#[cfg_attr(feature = "runtime-benchmarks", derive(frame_support::DebugNoBound))]
113#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
114#[scale_info(skip_type_params(T))]
115pub struct InstructionWeights<T: Config> {
116 /// Base instruction `ref_time` Weight.
117 /// Should match to wasmi's `1` fuel (see <https://github.com/wasmi-labs/wasmi/issues/701>).
118 pub base: u32,
119 /// The type parameter is used in the default implementation.
120 #[codec(skip)]
121 pub _phantom: PhantomData<T>,
122}
123
124impl Default for Limits {
125 fn default() -> Self {
126 Self {
127 event_topics: 4,
128 memory_pages: 16,
129 subject_len: 32,
130 payload_len: 16 * 1024,
131 runtime_memory: 1024 * 1024 * 128,
132 validator_runtime_memory: 1024 * 1024 * 512,
133 event_ref_time: 60_000,
134 }
135 }
136}
137
138impl<T: Config> Default for InstructionWeights<T> {
139 /// We execute 6 different instructions therefore we have to divide the actual
140 /// computed gas costs by 6 to have a rough estimate as to how expensive each
141 /// single executed instruction is going to be.
142 fn default() -> Self {
143 let instr_cost = T::WeightInfo::instr_i64_load_store(1)
144 .saturating_sub(T::WeightInfo::instr_i64_load_store(0))
145 .ref_time() as u32;
146 let base = instr_cost / 6;
147 Self { base, _phantom: PhantomData }
148 }
149}