diff --git a/ethcore/evm/src/evm.rs b/ethcore/evm/src/evm.rs index f8a08b2b2e3..3c88155f2f5 100644 --- a/ethcore/evm/src/evm.rs +++ b/ethcore/evm/src/evm.rs @@ -44,12 +44,18 @@ pub trait Finalize { impl Finalize for Result { fn finalize(self, ext: E) -> Result { match self { - Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }), - Ok(GasLeft::NeedsReturn { gas_left, data, apply_state }) => ext.ret(&gas_left, &data, apply_state).map(|gas_left| FinalizationResult { - gas_left: gas_left, - apply_state: apply_state, - return_data: data, - }), + Ok(GasLeft::Known(gas_left)) => { + Ok(FinalizationResult { + gas_left, + apply_state: true, + return_data: ReturnData::empty() + }) + }, + Ok(GasLeft::NeedsReturn { gas_left, data, apply_state }) => { + ext.ret(&gas_left, &data, apply_state).map(|gas_left| + FinalizationResult { gas_left, apply_state, return_data: data } + ) + }, Err(err) => Err(err), } } diff --git a/ethcore/evm/src/instructions.rs b/ethcore/evm/src/instructions.rs index 1580f7b591d..b0a66c159e3 100644 --- a/ethcore/evm/src/instructions.rs +++ b/ethcore/evm/src/instructions.rs @@ -151,6 +151,8 @@ enum_with_from_u8! { GASLIMIT = 0x45, #[doc = "get chain ID"] CHAINID = 0x46, + #[doc = "get balance of own account"] + SELFBALANCE = 0x47, #[doc = "remove item from stack"] POP = 0x50, @@ -502,6 +504,7 @@ lazy_static! { arr[DIFFICULTY as usize] = Some(InstructionInfo::new("DIFFICULTY", 0, 1, GasPriceTier::Base)); arr[GASLIMIT as usize] = Some(InstructionInfo::new("GASLIMIT", 0, 1, GasPriceTier::Base)); arr[CHAINID as usize] = Some(InstructionInfo::new("CHAINID", 0, 1, GasPriceTier::Base)); + arr[SELFBALANCE as usize] = Some(InstructionInfo::new("SELFBALANCE", 0, 1, GasPriceTier::Low)); arr[POP as usize] = Some(InstructionInfo::new("POP", 1, 0, GasPriceTier::Base)); arr[MLOAD as usize] = Some(InstructionInfo::new("MLOAD", 1, 1, GasPriceTier::VeryLow)); arr[MSTORE as usize] = Some(InstructionInfo::new("MSTORE", 2, 0, GasPriceTier::VeryLow)); diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 85564385552..47260139521 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -299,7 +299,12 @@ impl Interpreter { let result = if self.gasometer.is_none() { InterpreterResult::Done(Err(vm::Error::OutOfGas)) } else if self.reader.len() == 0 { - InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_ref().expect("Gasometer None case is checked above; qed").current_gas.as_u256()))) + let current_gas = self.gasometer + .as_ref() + .expect("Gasometer None case is checked above; qed") + .current_gas + .as_u256(); + InterpreterResult::Done(Ok(GasLeft::Known(current_gas))) } else { self.step_inner(ext) }; @@ -308,7 +313,7 @@ impl Interpreter { self.done = true; self.informant.done(); } - return result; + result } /// Inner helper function for step. @@ -429,7 +434,8 @@ impl Interpreter { (instruction == instructions::REVERT && !schedule.have_revert) || ((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) || (instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash) || - (instruction == instructions::CHAINID && !schedule.have_chain_id) + (instruction == instructions::CHAINID && !schedule.have_chain_id) || + (instruction == instructions::SELFBALANCE && !schedule.have_selfbalance) { return Err(vm::Error::BadInstruction { instruction: instruction as u8 @@ -847,6 +853,9 @@ impl Interpreter { instructions::CHAINID => { self.stack.push(ext.chain_id().into()) }, + instructions::SELFBALANCE => { + self.stack.push(ext.balance(&self.params.address)?); + } // Stack instructions diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index 05a39e1b5a1..d226b7c1a25 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -124,6 +124,32 @@ fn test_origin(factory: super::Factory) { assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681"); } +evm_test!{test_selfbalance: test_selfbalance_int} +fn test_selfbalance(factory: super::Factory) { + let own_addr = Address::from_str("1337000000000000000000000000000000000000").unwrap(); + // 47 SELFBALANCE + // 60 ff PUSH ff + // 55 SSTORE + let code = hex!("47 60 ff 55").to_vec(); + + let mut params = ActionParams::default(); + params.address = own_addr.clone(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + let mut ext = FakeExt::new_istanbul(); + ext.balances = { + let mut x = HashMap::new(); + x.insert(own_addr, U256::from(1_025)); // 0x401 + x + }; + let gas_left = { + let vm = factory.create(params, ext.schedule(), ext.depth()); + test_finalize(vm.exec(&mut ext).ok().unwrap()).unwrap() + }; + assert_eq!(gas_left, U256::from(79_992)); // TODO[dvdplm]: do the sums here, SELFBALANCE-5 + PUSH1-3 + ONEBYTE-4 + SSTORE-?? = 100_000 - 79_992 + assert_store(&ext, 0xff, "0000000000000000000000000000000000000000000000000000000000000401"); +} + evm_test!{test_sender: test_sender_int} fn test_sender(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); diff --git a/ethcore/types/src/engines/params.rs b/ethcore/types/src/engines/params.rs index fc8eb96674c..7176093f34b 100644 --- a/ethcore/types/src/engines/params.rs +++ b/ethcore/types/src/engines/params.rs @@ -92,6 +92,8 @@ pub struct CommonParams { pub eip1014_transition: BlockNumber, /// Number of first block where EIP-1344 rules begin: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1344.md pub eip1344_transition: BlockNumber, + /// Number of first block where EIP-1884 rules begin:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1884.md + pub eip1884_transition: BlockNumber, /// Number of first block where EIP-2028 rules begin. pub eip2028_transition: BlockNumber, /// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin. @@ -165,6 +167,13 @@ impl CommonParams { schedule.have_extcodehash = block_number >= self.eip1052_transition; schedule.have_chain_id = block_number >= self.eip1344_transition; schedule.eip1283 = block_number >= self.eip1283_transition && !(block_number >= self.eip1283_disable_transition); + + if block_number >= self.eip1884_transition { + schedule.have_selfbalance = true; + schedule.sload_gas = 800; + schedule.balance_gas = 700; + schedule.extcodehash_gas = 700; + } if block_number >= self.eip2028_transition { schedule.tx_data_non_zero_gas = 16; } @@ -289,6 +298,10 @@ impl From for CommonParams { BlockNumber::max_value, Into::into, ), + eip1884_transition: p.eip1884_transition.map_or_else( + BlockNumber::max_value, + Into::into, + ), eip2028_transition: p.eip2028_transition.map_or_else( BlockNumber::max_value, Into::into, diff --git a/ethcore/vm/src/ext.rs b/ethcore/vm/src/ext.rs index 63d9595fb0a..68e5822e451 100644 --- a/ethcore/vm/src/ext.rs +++ b/ethcore/vm/src/ext.rs @@ -91,7 +91,7 @@ pub trait Ext { /// Creates new contract. /// - /// Returns gas_left and contract address if contract creation was succesfull. + /// Returns gas_left and contract address if contract creation was successful. fn create( &mut self, gas: &U256, diff --git a/ethcore/vm/src/return_data.rs b/ethcore/vm/src/return_data.rs index 85fdb361db5..38ac23ffdc8 100644 --- a/ethcore/vm/src/return_data.rs +++ b/ethcore/vm/src/return_data.rs @@ -44,11 +44,7 @@ impl ReturnData { } /// Create `ReturnData` from give buffer and slice. pub fn new(mem: Vec, offset: usize, size: usize) -> Self { - ReturnData { - mem: mem, - offset: offset, - size: size, - } + ReturnData { mem, offset, size } } } diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index e11603ecdaa..877ef145b65 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -19,11 +19,13 @@ use std::collections::HashMap; use ethereum_types::U256; /// Definition of schedules that can be applied to a version. +#[derive(Debug)] pub enum VersionedSchedule { PWasm, } /// 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, @@ -124,6 +126,8 @@ pub struct Schedule { pub have_bitwise_shifting: bool, /// CHAINID opcode enabled. pub have_chain_id: bool, + /// SELFBALANCE opcode enabled. + pub have_selfbalance: bool, /// Kill basic accounts below this balance if touched. pub kill_dust: CleanDustMode, /// Enable EIP-1283 rules @@ -139,6 +143,7 @@ pub struct Schedule { } /// Wasm cost table +#[derive(Debug)] pub struct WasmCosts { /// Default opcode cost pub regular: u32, @@ -192,7 +197,7 @@ impl Default for WasmCosts { } /// Dust accounts cleanup mode. -#[derive(PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum CleanDustMode { /// Dust cleanup is disabled. Off, @@ -223,6 +228,7 @@ impl Schedule { have_return_data: false, have_bitwise_shifting: false, have_chain_id: false, + have_selfbalance: false, have_extcodehash: false, stack_limit: 1024, max_depth: 1024, @@ -294,8 +300,12 @@ impl 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; - schedule.tx_data_non_zero_gas = 16; + 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 } @@ -308,6 +318,7 @@ impl Schedule { have_return_data: false, have_bitwise_shifting: false, have_chain_id: false, + have_selfbalance: false, have_extcodehash: false, stack_limit: 1024, max_depth: 1024, diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 29c842b87bb..7b1cd1c188c 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -96,6 +96,8 @@ pub struct Params { /// See `CommonParams` docs. pub eip1344_transition: Option, /// See `CommonParams` docs. + pub eip1884_transition: Option, + /// See `CommonParams` docs. pub eip2028_transition: Option, /// See `CommonParams` docs. pub dust_protection_transition: Option,