From c0920b30eea888e69c3702cbf9e9d73d4851a0c9 Mon Sep 17 00:00:00 2001 From: "adria0.eth" <5526331+adria0@users.noreply.github.com> Date: Mon, 6 Apr 2020 22:31:12 +0200 Subject: [PATCH] Reduced gas cost for static calls made to precompiles EIP2046/1352 (#11583) * Implemented eip2046 * Update ethcore/builtin/src/lib.rs Co-Authored-By: Wei Tang * Update ethcore/builtin/src/lib.rs Co-Authored-By: Wei Tang * Update ethcore/builtin/src/lib.rs Co-Authored-By: Andronik Ordian * Update ethcore/builtin/src/lib.rs Co-Authored-By: Wei Tang * move precompile address limit def to gasometer * use const instead lazy_static Co-authored-by: Wei Tang Co-authored-by: Andronik Ordian --- ethcore/evm/src/interpreter/gasometer.rs | 23 +++- ethcore/machine/src/test_helpers.rs | 3 + ethcore/res/ethereum/berlin_test.json | 122 ++++++++++++++++++++ ethcore/res/ethereum/tests | 2 +- ethcore/spec/src/chain.rs | 2 + ethcore/src/test_helpers/evm_test_client.rs | 1 + ethcore/types/src/engines/params.rs | 9 ++ ethcore/vm/src/schedule.rs | 13 ++- ethcore/vm/src/tests.rs | 7 ++ json/src/spec/params.rs | 2 + json/src/spec/spec.rs | 4 +- 11 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 ethcore/res/ethereum/berlin_test.json diff --git a/ethcore/evm/src/interpreter/gasometer.rs b/ethcore/evm/src/interpreter/gasometer.rs index 5f8692d40..2c2e148df 100644 --- a/ethcore/evm/src/interpreter/gasometer.rs +++ b/ethcore/evm/src/interpreter/gasometer.rs @@ -15,7 +15,7 @@ // along with Open Ethereum. If not, see . use std::cmp; -use ethereum_types::{BigEndianHash, U256}; +use ethereum_types::{BigEndianHash, U256, H160, Address}; use super::u256_to_address; use {evm, vm}; @@ -31,6 +31,8 @@ macro_rules! overflowing { }} } +const PRECOMPILES_ADDRESS_LIMIT: Address = H160([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff,0xff]); + enum Request { Gas(Cost), GasMem(Cost, Cost), @@ -224,7 +226,7 @@ impl Gasometer { Request::GasMemProvide(gas, mem, Some(requested)) }, - instructions::DELEGATECALL | instructions::STATICCALL => { + instructions::DELEGATECALL => { let gas = Gas::from(schedule.call_gas); let mem = cmp::max( mem_needed(stack.peek(4), stack.peek(5))?, @@ -234,6 +236,23 @@ impl Gasometer { Request::GasMemProvide(gas, mem, Some(requested)) }, + instructions::STATICCALL => { + let code_address = u256_to_address(stack.peek(1)); + let gas = if code_address <= PRECOMPILES_ADDRESS_LIMIT { + Gas::from(schedule.staticcall_precompile_gas) + } else { + Gas::from(schedule.call_gas) + }; + + let mem = cmp::max( + mem_needed(stack.peek(4), stack.peek(5))?, // out_off, out_size + mem_needed(stack.peek(2), stack.peek(3))? // in_off, in_size + ); + + let requested = *stack.peek(0); + + Request::GasMemProvide(gas, mem, Some(requested)) + }, instructions::CREATE => { let start = stack.peek(1); let len = stack.peek(2); diff --git a/ethcore/machine/src/test_helpers.rs b/ethcore/machine/src/test_helpers.rs index ffea1f9f9..fd8793b50 100644 --- a/ethcore/machine/src/test_helpers.rs +++ b/ethcore/machine/src/test_helpers.rs @@ -55,6 +55,9 @@ pub fn new_constantinople_fix_test_machine() -> Machine { load_machine(include_b /// Create a new Foundation Istanbul era spec. pub fn new_istanbul_test_machine() -> Machine { load_machine(include_bytes!("../../res/ethereum/istanbul_test.json")) } +/// Create a new Foundation Berlin era spec. +pub fn new_berlin_test_machine() -> Machine { load_machine(include_bytes!("../../res/ethereum/berlin_test.json")) } + /// Create a new Musicoin-MCIP3-era spec. pub fn new_mcip3_test_machine() -> Machine { load_machine(include_bytes!("../../res/ethereum/mcip3_test.json")) } diff --git a/ethcore/res/ethereum/berlin_test.json b/ethcore/res/ethereum/berlin_test.json new file mode 100644 index 000000000..817350db0 --- /dev/null +++ b/ethcore/res/ethereum/berlin_test.json @@ -0,0 +1,122 @@ +{ + "name": "Berlin (test)", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x1BC16D674EC80000", + "homesteadTransition": "0x0", + "eip100bTransition": "0x0", + "difficultyBombDelays": { + "0": 5000000 + } + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x1", + "maxCodeSize": 24576, + "maxCodeSizeTransition": "0x0", + "eip150Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip140Transition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip155Transition": "0x0", + "eip658Transition": "0x0", + "eip145Transition": "0x0", + "eip1014Transition": "0x0", + "eip1052Transition": "0x0", + "eip1283Transition": "0x0", + "eip1283DisableTransition": "0x0", + "eip1283ReenableTransition": "0x0", + "eip1344Transition": "0x0", + "eip1706Transition": "0x0", + "eip1884Transition": "0x0", + "eip2028Transition": "0x0", + "eip2046Transition": "0x0" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x1388" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x00", "pricing": { "modexp": { "divisor": 20 } } } }, + "0000000000000000000000000000000000000006": { + "builtin": { + "name": "alt_bn128_add", + "pricing": { + "0": { + "price": { "alt_bn128_const_operations": { "price": 500 }} + }, + "0": { + "info": "EIP 1108 transition", + "price": { "alt_bn128_const_operations": { "price": 150 }} + } + } + } + }, + "0000000000000000000000000000000000000007": { + "builtin": { + "name": "alt_bn128_mul", + "pricing": { + "0": { + "price": { "alt_bn128_const_operations": { "price": 40000 }} + }, + "0": { + "info": "EIP 1108 transition", + "price": { "alt_bn128_const_operations": { "price": 6000 }} + } + } + } + }, + "0000000000000000000000000000000000000008": { + "builtin": { + "name": "alt_bn128_pairing", + "pricing": { + "0": { + "price": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 }} + }, + "0": { + "info": "EIP 1108 transition", + "price": { "alt_bn128_pairing": { "base": 45000, "pair": 34000 }} + } + } + } + }, + "0000000000000000000000000000000000000009": { + "builtin": { + "name": "blake2_f", + "activate_at": "0x00", + "pricing": { + "blake2_f": { + "gas_per_round": 1 + } + } + } + } + } +} diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index d4f86ecf4..06acfb48a 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit d4f86ecf4aa7c44a40bc0c972fd3e25d63ef5d92 +Subproject commit 06acfb48aee71ecb57a9ca991cf0f57b630e3469 diff --git a/ethcore/spec/src/chain.rs b/ethcore/spec/src/chain.rs index 1a34d3911..3c53e4374 100644 --- a/ethcore/spec/src/chain.rs +++ b/ethcore/spec/src/chain.rs @@ -91,6 +91,7 @@ bundle_test_spec! { "ethereum/byzantium_test" => new_byzantium_test, "ethereum/constantinople_test" => new_constantinople_test, "ethereum/istanbul_test" => new_istanbul_test, + "ethereum/berlin_test" => new_berlin_test, "ethereum/eip150_test" => new_eip150_test, "ethereum/eip161_test" => new_eip161_test, "ethereum/eip210_test" => new_eip210_test, @@ -117,6 +118,7 @@ bundle_test_machine! { "ethereum/byzantium_test" => new_byzantium_test_machine, "ethereum/constantinople_test" => new_constantinople_test_machine, "ethereum/istanbul_test" => new_istanbul_test_machine, + "ethereum/berlin_test" => new_berlin_test_machine, "ethereum/eip210_test" => new_eip210_test_machine, "ethereum/frontier_test" => new_frontier_test_machine, "ethereum/homestead_test" => new_homestead_test_machine, diff --git a/ethcore/src/test_helpers/evm_test_client.rs b/ethcore/src/test_helpers/evm_test_client.rs index 4985172b6..d4a252484 100644 --- a/ethcore/src/test_helpers/evm_test_client.rs +++ b/ethcore/src/test_helpers/evm_test_client.rs @@ -110,6 +110,7 @@ impl<'a> EvmTestClient<'a> { ForkSpec::Constantinople => Some(spec::new_constantinople_test()), ForkSpec::ConstantinopleFix => Some(spec::new_constantinople_fix_test()), ForkSpec::Istanbul => Some(spec::new_istanbul_test()), + ForkSpec::Berlin => Some(spec::new_berlin_test()), ForkSpec::EIP158ToByzantiumAt5 => Some(spec::new_transition_test()), ForkSpec::FrontierToHomesteadAt5 | ForkSpec::HomesteadToDaoAt5 | ForkSpec::HomesteadToEIP150At5 => None, } diff --git a/ethcore/types/src/engines/params.rs b/ethcore/types/src/engines/params.rs index beb8e2113..571996d06 100644 --- a/ethcore/types/src/engines/params.rs +++ b/ethcore/types/src/engines/params.rs @@ -100,6 +100,8 @@ pub struct CommonParams { pub eip1884_transition: BlockNumber, /// Number of first block where EIP-2028 rules begin. pub eip2028_transition: BlockNumber, + /// Number of first block where EIP-2046/1352 rules begin. + pub eip2046_transition: BlockNumber, /// Number of first block where EIP-2200 advance transition begin. pub eip2200_advance_transition: BlockNumber, /// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin. @@ -191,6 +193,9 @@ impl CommonParams { schedule.sload_gas = 800; schedule.sstore_dirty_gas = Some(800); } + if block_number >= self.eip2046_transition { + schedule.staticcall_precompile_gas = 40; + } if block_number >= self.eip210_transition { schedule.blockhash_gas = 800; } @@ -328,6 +333,10 @@ impl From for CommonParams { BlockNumber::max_value, Into::into, ), + eip2046_transition: p.eip2046_transition.map_or_else( + BlockNumber::max_value, + Into::into, + ), eip2200_advance_transition: p.eip2200_advance_transition.map_or_else( BlockNumber::max_value, Into::into, diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index db8dacab5..8be062e57 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -71,8 +71,10 @@ pub struct Schedule { pub log_topic_gas: usize, /// Gas price for `CREATE` opcode pub create_gas: usize, - /// Gas price for `*CALL*` opcodes + /// Gas price for `*CALL*` opcodes, EXCEPT for staticcall to precompiles pub call_gas: usize, + /// Gas price for staticcall to precompiles + pub staticcall_precompile_gas: usize, /// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0` pub call_stipend: usize, /// Additional gas required for value transfer (`CALL|CALLCODE`) @@ -250,6 +252,7 @@ impl Schedule { log_topic_gas: 375, create_gas: 32000, call_gas: 700, + staticcall_precompile_gas: 700, call_stipend: 2300, call_value_transfer_gas: 9000, call_new_account_gas: 25000, @@ -312,6 +315,13 @@ impl Schedule { schedule } + /// Schedule for the Berlin fork of the Ethereum main net. + pub fn new_berlin() -> Schedule { + let mut schedule = Self::new_istanbul(); + schedule.staticcall_precompile_gas = 40; // EIPs 2046 1352 + schedule + } + fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { Schedule { exceptional_failed_code_deposit: efcd, @@ -341,6 +351,7 @@ impl Schedule { log_topic_gas: 375, create_gas: 32000, call_gas: 40, + staticcall_precompile_gas: 40, call_stipend: 2300, call_value_transfer_gas: 9000, call_new_account_gas: 25000, diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index 575567f8d..a87b531f1 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -107,6 +107,13 @@ impl FakeExt { ext } + /// New fake externalities with Berlin schedule rules + pub fn new_berlin() -> Self { + let mut ext = FakeExt::default(); + ext.schedule = Schedule::new_berlin(); + ext + } + /// Alter fake externalities to allow wasm pub fn with_wasm(mut self) -> Self { self.schedule.wasm = Some(Default::default()); diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index a7b5f8230..df117bb1d 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -107,6 +107,8 @@ pub struct Params { /// See `CommonParams` docs. pub eip2028_transition: Option, /// See `CommonParams` docs. + pub eip2046_transition: Option, + /// See `CommonParams` docs. pub eip2200_advance_transition: Option, /// See `CommonParams` docs. pub dust_protection_transition: Option, diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs index 50d2c6b2e..74e224247 100644 --- a/json/src/spec/spec.rs +++ b/json/src/spec/spec.rs @@ -38,8 +38,10 @@ pub enum ForkSpec { Constantinople, /// Constantinople transition test-net ConstantinopleFix, - /// Istanbul (To be announced) + /// Istanbul (#9,069,000 2019-12-08) Istanbul, + /// Berlin (To be announced) + Berlin, /// Byzantium transition test-net EIP158ToByzantiumAt5, /// Homestead transition test-net