mep_vm/
schedule.rs

1// Copyright 2015-2020 Parity Technologies (UK) Ltd.
2// This file is part of Parity Ethereum.
3
4// Parity Ethereum 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// Parity Ethereum 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 Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Cost schedule and other parameterisations for the EVM.
18use std::collections::HashMap;
19use ethereum_types::U256;
20
21/// Definition of schedules that can be applied to a version.
22#[derive(Debug)]
23pub enum VersionedSchedule {
24	PWasm,
25}
26
27/// Definition of the cost schedule and other parameterisations for the EVM.
28#[derive(Debug)]
29pub struct Schedule {
30	/// Does it support exceptional failed code deposit
31	pub exceptional_failed_code_deposit: bool,
32	/// Does it have a delegate cal
33	pub have_delegate_call: bool,
34	/// Does it have a CREATE2 instruction
35	pub have_create2: bool,
36	/// Does it have a REVERT instruction
37	pub have_revert: bool,
38	/// Does it have a EXTCODEHASH instruction
39	pub have_extcodehash: bool,
40	/// VM stack limit
41	pub stack_limit: usize,
42	/// Max number of nested calls/creates
43	pub max_depth: usize,
44	/// Gas prices for instructions in all tiers
45	pub tier_step_gas: [usize; 8],
46	/// Gas price for `EXP` opcode
47	pub exp_gas: usize,
48	/// Additional gas for `EXP` opcode for each byte of exponent
49	pub exp_byte_gas: usize,
50	/// Gas price for `SHA3` opcode
51	pub sha3_gas: usize,
52	/// Additional gas for `SHA3` opcode for each word of hashed memory
53	pub sha3_word_gas: usize,
54	/// Gas price for loading from storage
55	pub sload_gas: usize,
56	/// Special gas price for dirty gas of SSTORE, after net gas metering.
57	pub sstore_dirty_gas: Option<usize>,
58	/// Gas price for setting new value to storage (`storage==0`, `new!=0`)
59	pub sstore_set_gas: usize,
60	/// Gas price for altering value in storage
61	pub sstore_reset_gas: usize,
62	/// Gas refund for `SSTORE` clearing (when `storage!=0`, `new==0`)
63	pub sstore_refund_gas: usize,
64	/// Gas price for `JUMPDEST` opcode
65	pub jumpdest_gas: usize,
66	/// Gas price for `LOG*`
67	pub log_gas: usize,
68	/// Additional gas for data in `LOG*`
69	pub log_data_gas: usize,
70	/// Additional gas for each topic in `LOG*`
71	pub log_topic_gas: usize,
72	/// Gas price for `CREATE` opcode
73	pub create_gas: usize,
74	/// Gas price for `*CALL*` opcodes
75	pub call_gas: usize,
76	/// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0`
77	pub call_stipend: usize,
78	/// Additional gas required for value transfer (`CALL|CALLCODE`)
79	pub call_value_transfer_gas: usize,
80	/// Additional gas for creating new account (`CALL|CALLCODE`)
81	pub call_new_account_gas: usize,
82	/// Refund for SUICIDE
83	pub suicide_refund_gas: usize,
84	/// Gas for used memory
85	pub memory_gas: usize,
86	/// Coefficient used to convert memory size to gas price for memory
87	pub quad_coeff_div: usize,
88	/// Cost for contract length when executing `CREATE`
89	pub create_data_gas: usize,
90	/// Maximum code size when creating a contract.
91	pub create_data_limit: usize,
92	/// Transaction cost
93	pub tx_gas: usize,
94	/// `CREATE` transaction cost
95	pub tx_create_gas: usize,
96	/// Additional cost for empty data transaction
97	pub tx_data_zero_gas: usize,
98	/// Additional cost for non-empty data transaction
99	pub tx_data_non_zero_gas: usize,
100	/// Gas price for copying memory
101	pub copy_gas: usize,
102	/// Price of EXTCODESIZE
103	pub extcodesize_gas: usize,
104	/// Base price of EXTCODECOPY
105	pub extcodecopy_base_gas: usize,
106	/// Price of BALANCE
107	pub balance_gas: usize,
108	/// Price of EXTCODEHASH
109	pub extcodehash_gas: usize,
110	/// Price of SUICIDE
111	pub suicide_gas: usize,
112	/// Amount of additional gas to pay when SUICIDE credits a non-existant account
113	pub suicide_to_new_account_cost: usize,
114	/// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit.
115	/// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS
116	pub sub_gas_cap_divisor: Option<usize>,
117	/// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value.
118	pub no_empty: bool,
119	/// Kill empty accounts if touched.
120	pub kill_empty: bool,
121	/// Blockhash instruction gas cost.
122	pub blockhash_gas: usize,
123	/// Static Call opcode enabled.
124	pub have_static_call: bool,
125	/// RETURNDATA and RETURNDATASIZE opcodes enabled.
126	pub have_return_data: bool,
127	/// SHL, SHR, SAR opcodes enabled.
128	pub have_bitwise_shifting: bool,
129	/// CHAINID opcode enabled.
130	pub have_chain_id: bool,
131	/// SELFBALANCE opcode enabled.
132	pub have_selfbalance: bool,
133	/// Kill basic accounts below this balance if touched.
134	pub kill_dust: CleanDustMode,
135	/// Enable EIP-1283 rules
136	pub eip1283: bool,
137	/// Enable EIP-1706 rules
138	pub eip1706: bool,
139	/// VM execution does not increase null signed address nonce if this field is true.
140	pub keep_unsigned_nonce: bool,
141	/// Latest VM version for contract creation transaction.
142	pub latest_version: U256,
143	/// All supported non-legacy VM versions.
144	pub versions: HashMap<U256, VersionedSchedule>,
145	/// Wasm extra schedule settings, if wasm activated
146	pub wasm: Option<WasmCosts>,
147}
148
149/// Wasm cost table
150#[derive(Debug)]
151pub struct WasmCosts {
152	/// Default opcode cost
153	pub regular: u32,
154	/// Div operations multiplier.
155	pub div: u32,
156	/// Div operations multiplier.
157	pub mul: u32,
158	/// Memory (load/store) operations multiplier.
159	pub mem: u32,
160	/// General static query of U256 value from env-info
161	pub static_u256: u32,
162	/// General static query of Address value from env-info
163	pub static_address: u32,
164	/// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack.
165	pub initial_mem: u32,
166	/// Grow memory cost, per page (64kb)
167	pub grow_mem: u32,
168	/// Memory copy cost, per byte
169	pub memcpy: u32,
170	/// Max stack height (native WebAssembly stack limiter)
171	pub max_stack_height: u32,
172	/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
173	pub opcodes_mul: u32,
174	/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
175	pub opcodes_div: u32,
176	/// Whether create2 extern function is activated.
177	pub have_create2: bool,
178	/// Whether gasleft extern function is activated.
179	pub have_gasleft: bool,
180}
181
182impl Default for WasmCosts {
183	fn default() -> Self {
184		WasmCosts {
185			regular: 1,
186			div: 16,
187			mul: 4,
188			mem: 2,
189			static_u256: 64,
190			static_address: 40,
191			initial_mem: 4096,
192			grow_mem: 8192,
193			memcpy: 1,
194			max_stack_height: 64*1024,
195			opcodes_mul: 3,
196			opcodes_div: 8,
197			have_create2: false,
198			have_gasleft: false,
199		}
200	}
201}
202
203/// Dust accounts cleanup mode.
204#[derive(Debug, PartialEq, Eq)]
205pub enum CleanDustMode {
206	/// Dust cleanup is disabled.
207	Off,
208	/// Basic dust accounts will be removed.
209	BasicOnly,
210	/// Basic and contract dust accounts will be removed.
211	WithCodeAndStorage,
212}
213
214impl Schedule {
215	/// Schedule for the Frontier-era of the Ethereum main net.
216	pub fn new_frontier() -> Schedule {
217		Self::new(false, false, 21000)
218	}
219
220	/// Schedule for the Homestead-era of the Ethereum main net.
221	pub fn new_homestead() -> Schedule {
222		Self::new(true, true, 53000)
223	}
224
225	/// Schedule for the post-EIP-150-era of the Ethereum main net.
226	pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule {
227		Schedule {
228			exceptional_failed_code_deposit: true,
229			have_delegate_call: true,
230			have_create2: false,
231			have_revert: false,
232			have_return_data: false,
233			have_bitwise_shifting: false,
234			have_chain_id: false,
235			have_selfbalance: false,
236			have_extcodehash: false,
237			stack_limit: 1024,
238			max_depth: 1024,
239			tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
240			exp_gas: 10,
241			exp_byte_gas: if fix_exp {50} else {10},
242			sha3_gas: 30,
243			sha3_word_gas: 6,
244			sload_gas: 200,
245			sstore_dirty_gas: None,
246			sstore_set_gas: 20000,
247			sstore_reset_gas: 5000,
248			sstore_refund_gas: 15000,
249			jumpdest_gas: 1,
250			log_gas: 375,
251			log_data_gas: 8,
252			log_topic_gas: 375,
253			create_gas: 32000,
254			call_gas: 700,
255			call_stipend: 2300,
256			call_value_transfer_gas: 9000,
257			call_new_account_gas: 25000,
258			suicide_refund_gas: 24000,
259			memory_gas: 3,
260			quad_coeff_div: 512,
261			create_data_gas: 200,
262			create_data_limit: max_code_size,
263			tx_gas: 21000,
264			tx_create_gas: 53000,
265			tx_data_zero_gas: 4,
266			tx_data_non_zero_gas: 68,
267			copy_gas: 3,
268			extcodesize_gas: 700,
269			extcodecopy_base_gas: 700,
270			extcodehash_gas: 400,
271			balance_gas: 400,
272			suicide_gas: 5000,
273			suicide_to_new_account_cost: 25000,
274			sub_gas_cap_divisor: Some(64),
275			no_empty: no_empty,
276			kill_empty: kill_empty,
277			blockhash_gas: 20,
278			have_static_call: false,
279			kill_dust: CleanDustMode::Off,
280			eip1283: false,
281			eip1706: false,
282			keep_unsigned_nonce: false,
283			latest_version: U256::zero(),
284			versions: HashMap::new(),
285			wasm: None,
286		}
287	}
288
289	/// Schedule for the Byzantium fork of the Ethereum main net.
290	pub fn new_byzantium() -> Schedule {
291		let mut schedule = Self::new_post_eip150(24576, true, true, true);
292		schedule.have_create2 = true;
293		schedule.have_revert = true;
294		schedule.have_static_call = true;
295		schedule.have_return_data = true;
296		schedule
297	}
298
299	/// Schedule for the Constantinople fork of the Ethereum main net.
300	pub fn new_constantinople() -> Schedule {
301		let mut schedule = Self::new_byzantium();
302		schedule.have_bitwise_shifting = true;
303		schedule
304	}
305
306	/// Schedule for the Istanbul fork of the Ethereum main net.
307	pub fn new_istanbul() -> Schedule {
308		let mut schedule = Self::new_constantinople();
309		schedule.have_chain_id = true; // EIP 1344
310		schedule.tx_data_non_zero_gas = 16; // EIP 2028
311		schedule.sload_gas = 800; // EIP 1884
312		schedule.balance_gas = 700; // EIP 1884
313		schedule.extcodehash_gas = 700; // EIP 1884
314		schedule.have_selfbalance = true; // EIP 1884
315		schedule
316	}
317
318	fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
319		Schedule {
320			exceptional_failed_code_deposit: efcd,
321			have_delegate_call: hdc,
322			have_create2: false,
323			have_revert: false,
324			have_return_data: false,
325			have_bitwise_shifting: false,
326			have_chain_id: false,
327			have_selfbalance: false,
328			have_extcodehash: false,
329			stack_limit: 1024,
330			max_depth: 1024,
331			tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
332			exp_gas: 10,
333			exp_byte_gas: 10,
334			sha3_gas: 30,
335			sha3_word_gas: 6,
336			sload_gas: 50,
337			sstore_dirty_gas: None,
338			sstore_set_gas: 20000,
339			sstore_reset_gas: 5000,
340			sstore_refund_gas: 15000,
341			jumpdest_gas: 1,
342			log_gas: 375,
343			log_data_gas: 8,
344			log_topic_gas: 375,
345			create_gas: 32000,
346			call_gas: 40,
347			call_stipend: 2300,
348			call_value_transfer_gas: 9000,
349			call_new_account_gas: 25000,
350			suicide_refund_gas: 24000,
351			memory_gas: 3,
352			quad_coeff_div: 512,
353			create_data_gas: 200,
354			create_data_limit: usize::max_value(),
355			tx_gas: 21000,
356			tx_create_gas: tcg,
357			tx_data_zero_gas: 4,
358			tx_data_non_zero_gas: 68,
359			copy_gas: 3,
360			extcodesize_gas: 20,
361			extcodecopy_base_gas: 20,
362			extcodehash_gas: 400,
363			balance_gas: 20,
364			suicide_gas: 0,
365			suicide_to_new_account_cost: 0,
366			sub_gas_cap_divisor: None,
367			no_empty: false,
368			kill_empty: false,
369			blockhash_gas: 20,
370			have_static_call: false,
371			kill_dust: CleanDustMode::Off,
372			eip1283: false,
373			eip1706: false,
374			keep_unsigned_nonce: false,
375			latest_version: U256::zero(),
376			versions: HashMap::new(),
377			wasm: None,
378		}
379	}
380
381	/// Returns wasm schedule
382	///
383	/// May panic if there is no wasm schedule
384	pub fn wasm(&self) -> &WasmCosts {
385		// *** Prefer PANIC here instead of silently breaking consensus! ***
386		self.wasm.as_ref().expect("Wasm schedule expected to exist while checking wasm contract. Misconfigured client?")
387	}
388}
389
390impl Default for Schedule {
391	fn default() -> Self {
392		Schedule::new_frontier()
393	}
394}
395
396#[test]
397#[cfg(test)]
398fn schedule_evm_assumptions() {
399	let s1 = Schedule::new_frontier();
400	let s2 = Schedule::new_homestead();
401
402	// To optimize division we assume 2**9 for quad_coeff_div
403	assert_eq!(s1.quad_coeff_div, 512);
404	assert_eq!(s2.quad_coeff_div, 512);
405}