// Copyright 2015-2020 Parity Technologies (UK) Ltd. // This file is part of OpenEthereum. // OpenEthereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // OpenEthereum is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with OpenEthereum. If not, see . //! Cost schedule and other parameterisations for the EVM. // Gas per non accessed address when sload pub const EIP2929_COLD_SLOAD_COST: usize = 2100; // Gas per non accessed address accessing account from other opcodes defined in EIP2929 pub const EIP2929_COLD_ACCOUNT_ACCESS_COST: usize = 2600; // Gas per already accessed address pub const EIP2929_WARM_STORAGE_READ_COST: usize = 100; // Gas per sstore reset pub const EIP2929_SSTORE_RESET_GAS: usize = 5000 - EIP2929_COLD_SLOAD_COST; /// Gas per received storage key pub const EIP2930_ACCESS_LIST_STORAGE_KEY_COST: usize = 1900; /// Gas per received address pub const EIP2930_ACCESS_LIST_ADDRESS_COST: usize = 2400; /// Gas used per transaction divided by this number is the maximum refundable amount pub const MAX_REFUND_QUOTIENT: usize = 2; pub const EIP3529_MAX_REFUND_QUOTIENT: usize = 5; /// Reduced SSTORE refund as by EIP-3529 pub const EIP3529_SSTORE_CLEARS_SCHEDULE: usize = EIP2929_SSTORE_RESET_GAS + EIP2930_ACCESS_LIST_STORAGE_KEY_COST; /// Definition of the cost schedule and other parameterisations for the EVM. #[derive(Debug)] pub struct Schedule { /// Does it support exceptional failed code deposit pub exceptional_failed_code_deposit: bool, /// Does it have a delegate cal pub have_delegate_call: bool, /// Does it have a CREATE2 instruction pub have_create2: bool, /// Does it have a REVERT instruction pub have_revert: bool, /// Does it have a EXTCODEHASH instruction pub have_extcodehash: bool, /// VM stack limit pub stack_limit: usize, /// Max number of nested calls/creates pub max_depth: usize, /// Gas prices for instructions in all tiers pub tier_step_gas: [usize; 8], /// Gas price for `EXP` opcode pub exp_gas: usize, /// Additional gas for `EXP` opcode for each byte of exponent pub exp_byte_gas: usize, /// Gas price for `SHA3` opcode pub sha3_gas: usize, /// Additional gas for `SHA3` opcode for each word of hashed memory pub sha3_word_gas: usize, /// Gas price for loading from storage pub sload_gas: usize, /// Gas price for setting new value to storage (`storage==0`, `new!=0`) pub sstore_set_gas: usize, /// Gas price for altering value in storage pub sstore_reset_gas: usize, /// Gas refund for `SSTORE` clearing (when `storage!=0`, `new==0`) pub sstore_refund_gas: usize, /// Gas price for `JUMPDEST` opcode pub jumpdest_gas: usize, /// Gas price for `LOG*` pub log_gas: usize, /// Additional gas for data in `LOG*` pub log_data_gas: usize, /// Additional gas for each topic in `LOG*` pub log_topic_gas: usize, /// Gas price for `CREATE` opcode pub create_gas: usize, /// Gas price for `*CALL*` opcodes pub call_gas: usize, /// EIP-2929 COLD_SLOAD_COST pub cold_sload_cost: usize, /// EIP-2929 COLD_ACCOUNT_ACCESS_COST pub cold_account_access_cost: usize, /// EIP-2929 WARM_STORAGE_READ_COST pub warm_storage_read_cost: usize, /// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0` pub call_stipend: usize, /// Additional gas required for value transfer (`CALL|CALLCODE`) pub call_value_transfer_gas: usize, /// Additional gas for creating new account (`CALL|CALLCODE`) pub call_new_account_gas: usize, /// Refund for SUICIDE pub suicide_refund_gas: usize, /// Gas for used memory pub memory_gas: usize, /// Coefficient used to convert memory size to gas price for memory pub quad_coeff_div: usize, /// Cost for contract length when executing `CREATE` pub create_data_gas: usize, /// Maximum code size when creating a contract. pub create_data_limit: usize, /// Transaction cost pub tx_gas: usize, /// `CREATE` transaction cost pub tx_create_gas: usize, /// Additional cost for empty data transaction pub tx_data_zero_gas: usize, /// Additional cost for non-empty data transaction pub tx_data_non_zero_gas: usize, /// Gas price for copying memory pub copy_gas: usize, /// Price of EXTCODESIZE pub extcodesize_gas: usize, /// Base price of EXTCODECOPY pub extcodecopy_base_gas: usize, /// Price of BALANCE pub balance_gas: usize, /// Price of EXTCODEHASH pub extcodehash_gas: usize, /// Price of SUICIDE pub suicide_gas: usize, /// Amount of additional gas to pay when SUICIDE credits a non-existant account pub suicide_to_new_account_cost: usize, /// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit. /// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS pub sub_gas_cap_divisor: Option, /// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value. pub no_empty: bool, /// Kill empty accounts if touched. pub kill_empty: bool, /// Blockhash instruction gas cost. pub blockhash_gas: usize, /// Static Call opcode enabled. pub have_static_call: bool, /// RETURNDATA and RETURNDATASIZE opcodes enabled. pub have_return_data: bool, /// SHL, SHR, SAR opcodes enabled. pub have_bitwise_shifting: bool, /// CHAINID opcode enabled. pub have_chain_id: bool, /// SELFBALANCE opcode enabled. pub have_selfbalance: bool, /// BEGINSUB, JUMPSUB and RETURNSUB opcodes enabled. pub have_subs: bool, /// Kill basic accounts below this balance if touched. pub kill_dust: CleanDustMode, /// Enable EIP-1283 rules pub eip1283: bool, /// Enable EIP-1706 rules pub eip1706: bool, /// VM execution does not increase null signed address nonce if this field is true. pub keep_unsigned_nonce: bool, /// Wasm extra schedule settings, if wasm activated pub wasm: Option, /// Enable EIP-2929 rules pub eip2929: bool, /// Enable EIP-2930 rules for optional access list transactions. it depends on EIP-2929 pub eip2930: bool, /// Gas used in transaction divided by this number is the maximum refundable amount. pub max_refund_quotient: usize, // Enable EIP-3541 rule pub eip3541: bool, } /// Wasm cost table #[derive(Debug)] pub struct WasmCosts { /// Default opcode cost pub regular: u32, /// Div operations multiplier. pub div: u32, /// Div operations multiplier. pub mul: u32, /// Memory (load/store) operations multiplier. pub mem: u32, /// General static query of U256 value from env-info pub static_u256: u32, /// General static query of Address value from env-info pub static_address: u32, /// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack. pub initial_mem: u32, /// Grow memory cost, per page (64kb) pub grow_mem: u32, /// Memory copy cost, per byte pub memcpy: u32, /// Max stack height (native WebAssembly stack limiter) pub max_stack_height: u32, /// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div` pub opcodes_mul: u32, /// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div` pub opcodes_div: u32, /// Whether create2 extern function is activated. pub have_create2: bool, /// Whether gasleft extern function is activated. pub have_gasleft: bool, } impl Default for WasmCosts { fn default() -> Self { WasmCosts { regular: 1, div: 16, mul: 4, mem: 2, static_u256: 64, static_address: 40, initial_mem: 4096, grow_mem: 8192, memcpy: 1, max_stack_height: 64 * 1024, opcodes_mul: 3, opcodes_div: 8, have_create2: false, have_gasleft: false, } } } /// Dust accounts cleanup mode. #[derive(Debug, PartialEq, Eq)] pub enum CleanDustMode { /// Dust cleanup is disabled. Off, /// Basic dust accounts will be removed. BasicOnly, /// Basic and contract dust accounts will be removed. WithCodeAndStorage, } impl Schedule { /// Schedule for the Frontier-era of the Ethereum main net. pub fn new_frontier() -> Schedule { Self::new(false, false, 21000) } /// Schedule for the Homestead-era of the Ethereum main net. pub fn new_homestead() -> Schedule { Self::new(true, true, 53000) } /// Schedule for the post-EIP-150-era of the Ethereum main net. pub fn new_post_eip150( max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, ) -> Schedule { Schedule { exceptional_failed_code_deposit: true, have_delegate_call: true, have_create2: false, have_revert: false, have_return_data: false, have_bitwise_shifting: false, have_chain_id: false, have_selfbalance: false, have_subs: false, have_extcodehash: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], exp_gas: 10, exp_byte_gas: if fix_exp { 50 } else { 10 }, sha3_gas: 30, sha3_word_gas: 6, sload_gas: 200, sstore_set_gas: 20000, sstore_reset_gas: 5000, sstore_refund_gas: 15000, jumpdest_gas: 1, log_gas: 375, log_data_gas: 8, log_topic_gas: 375, create_gas: 32000, call_gas: 700, cold_account_access_cost: 0, cold_sload_cost: 0, warm_storage_read_cost: 0, call_stipend: 2300, call_value_transfer_gas: 9000, call_new_account_gas: 25000, suicide_refund_gas: 24000, memory_gas: 3, quad_coeff_div: 512, create_data_gas: 200, create_data_limit: max_code_size, tx_gas: 21000, tx_create_gas: 53000, tx_data_zero_gas: 4, tx_data_non_zero_gas: 68, copy_gas: 3, extcodesize_gas: 700, extcodecopy_base_gas: 700, extcodehash_gas: 400, balance_gas: 400, suicide_gas: 5000, suicide_to_new_account_cost: 25000, sub_gas_cap_divisor: Some(64), no_empty: no_empty, kill_empty: kill_empty, blockhash_gas: 20, have_static_call: false, kill_dust: CleanDustMode::Off, eip1283: false, eip1706: false, keep_unsigned_nonce: false, wasm: None, eip2929: false, eip2930: false, max_refund_quotient: MAX_REFUND_QUOTIENT, eip3541: false, } } /// Schedule for the Byzantium fork of the Ethereum main net. pub fn new_byzantium() -> Schedule { let mut schedule = Self::new_post_eip150(24576, true, true, true); schedule.have_create2 = true; schedule.have_revert = true; schedule.have_static_call = true; schedule.have_return_data = true; schedule } /// Schedule for the Constantinople fork of the Ethereum main net. pub fn new_constantinople() -> Schedule { let mut schedule = Self::new_byzantium(); schedule.have_bitwise_shifting = true; // EIP 145 schedule.have_extcodehash = true; // EIP 1052 schedule } /// Schedule for the Istanbul fork of the Ethereum main net. pub fn new_istanbul() -> Schedule { let mut schedule = Self::new_constantinople(); schedule.have_chain_id = true; // EIP 1344 schedule.tx_data_non_zero_gas = 16; // EIP 2028 schedule.sload_gas = 800; // EIP 1884 schedule.balance_gas = 700; // EIP 1884 schedule.extcodehash_gas = 700; // EIP 1884 schedule.have_selfbalance = true; // EIP 1884 schedule } /// Schedule for the Yolov3 testnet of the Ethereum main net. pub fn new_berlin() -> Schedule { let mut schedule = Self::new_istanbul(); schedule.have_subs = true; // EIP 2315 schedule.eip1283 = true; schedule.eip2929 = true; schedule.eip2930 = true; schedule.cold_sload_cost = EIP2929_COLD_SLOAD_COST; schedule.cold_account_access_cost = EIP2929_COLD_ACCOUNT_ACCESS_COST; schedule.warm_storage_read_cost = EIP2929_WARM_STORAGE_READ_COST; schedule.sload_gas = EIP2929_WARM_STORAGE_READ_COST; schedule.call_gas = EIP2929_COLD_ACCOUNT_ACCESS_COST; schedule.balance_gas = EIP2929_COLD_ACCOUNT_ACCESS_COST; schedule.extcodecopy_base_gas = EIP2929_COLD_ACCOUNT_ACCESS_COST; schedule.extcodehash_gas = EIP2929_COLD_ACCOUNT_ACCESS_COST; schedule.extcodesize_gas = EIP2929_COLD_ACCOUNT_ACCESS_COST; schedule.sstore_reset_gas = EIP2929_SSTORE_RESET_GAS; schedule } pub fn new_london() -> Schedule { let mut schedule = Self::new_berlin(); // EIP-3529 changes schedule.suicide_refund_gas = 0; schedule.sstore_refund_gas = EIP3529_SSTORE_CLEARS_SCHEDULE; schedule.max_refund_quotient = EIP3529_MAX_REFUND_QUOTIENT; schedule.eip3541 = true; schedule } fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { Schedule { exceptional_failed_code_deposit: efcd, have_delegate_call: hdc, have_create2: false, have_revert: false, have_return_data: false, have_bitwise_shifting: false, have_chain_id: false, have_selfbalance: false, have_subs: false, have_extcodehash: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], exp_gas: 10, exp_byte_gas: 10, sha3_gas: 30, sha3_word_gas: 6, sload_gas: 50, sstore_set_gas: 20000, sstore_reset_gas: 5000, sstore_refund_gas: 15000, jumpdest_gas: 1, log_gas: 375, log_data_gas: 8, log_topic_gas: 375, create_gas: 32000, call_gas: 40, cold_account_access_cost: 0, cold_sload_cost: 0, warm_storage_read_cost: 0, call_stipend: 2300, call_value_transfer_gas: 9000, call_new_account_gas: 25000, suicide_refund_gas: 24000, memory_gas: 3, quad_coeff_div: 512, create_data_gas: 200, create_data_limit: usize::max_value(), tx_gas: 21000, tx_create_gas: tcg, tx_data_zero_gas: 4, tx_data_non_zero_gas: 68, copy_gas: 3, extcodesize_gas: 20, extcodecopy_base_gas: 20, extcodehash_gas: 400, balance_gas: 20, suicide_gas: 0, suicide_to_new_account_cost: 0, sub_gas_cap_divisor: None, no_empty: false, kill_empty: false, blockhash_gas: 20, have_static_call: false, kill_dust: CleanDustMode::Off, eip1283: false, eip1706: false, keep_unsigned_nonce: false, wasm: None, eip2929: false, eip2930: false, max_refund_quotient: MAX_REFUND_QUOTIENT, eip3541: false, } } /// Returns wasm schedule /// /// May panic if there is no wasm schedule pub fn wasm(&self) -> &WasmCosts { // *** Prefer PANIC here instead of silently breaking consensus! *** self.wasm.as_ref().expect( "Wasm schedule expected to exist while checking wasm contract. Misconfigured client?", ) } } impl Default for Schedule { fn default() -> Self { Schedule::new_frontier() } } #[test] #[cfg(test)] fn schedule_evm_assumptions() { let s1 = Schedule::new_frontier(); let s2 = Schedule::new_homestead(); // To optimize division we assume 2**9 for quad_coeff_div assert_eq!(s1.quad_coeff_div, 512); assert_eq!(s2.quad_coeff_div, 512); }