Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
eip214, #4833
Browse files Browse the repository at this point in the history
  • Loading branch information
debris authored and arkpar committed May 31, 2017
1 parent 62f170c commit edba366
Show file tree
Hide file tree
Showing 23 changed files with 185 additions and 103 deletions.
2 changes: 1 addition & 1 deletion ethcore/res/ethereum/frontier_like_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"homesteadTransition": "0x118c30",
"daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
Expand Down
2 changes: 1 addition & 1 deletion ethcore/res/ethereum/transition_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"homesteadTransition": "0x5",
"daoHardforkTransition": "0x8",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub struct TestBlockChainClient {
/// Blocks.
pub blocks: RwLock<HashMap<H256, Bytes>>,
/// Mapping of numbers to hashes.
pub numbers: RwLock<HashMap<usize, H256>>,
pub numbers: RwLock<HashMap<usize, H256>>,
/// Genesis block hash.
pub genesis_hash: H256,
/// Last block hash.
Expand Down Expand Up @@ -353,7 +353,7 @@ pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {

impl MiningBlockChainClient for TestBlockChainClient {
fn latest_schedule(&self) -> Schedule {
Schedule::new_post_eip150(24576, true, true, true, true)
Schedule::new_post_eip150(24576, true, true, true)
}

fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
Expand Down
8 changes: 1 addition & 7 deletions ethcore/src/engines/authority_round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ use account_provider::AccountProvider;
use block::*;
use spec::CommonParams;
use engines::{Call, Engine, Seal, EngineError};
use header::{Header, BlockNumber};
use header::Header;
use error::{Error, TransactionError, BlockError};
use evm::Schedule;
use ethjson;
use io::{IoContext, IoHandler, TimerToken, IoService};
use builtin::Builtin;
Expand Down Expand Up @@ -293,11 +292,6 @@ impl Engine for AuthorityRound {
]
}

fn schedule(&self, block_number: BlockNumber) -> Schedule {
let eip86 = block_number >= self.params.eip86_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86)
}

fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load().into();
Expand Down
7 changes: 0 additions & 7 deletions ethcore/src/engines/instant_seal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ use util::{Address, HashMap};
use builtin::Builtin;
use engines::{Engine, Seal};
use spec::CommonParams;
use evm::Schedule;
use block::ExecutedBlock;
use header::BlockNumber;

/// An engine which does not provide any consensus mechanism, just seals blocks internally.
pub struct InstantSeal {
Expand Down Expand Up @@ -58,11 +56,6 @@ impl Engine for InstantSeal {
&self.builtins
}

fn schedule(&self, block_number: BlockNumber) -> Schedule {
let eip86 = block_number >= self.params.eip86_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86)
}

fn seals_internally(&self) -> Option<bool> { Some(true) }

fn generate_seal(&self, _block: &ExecutedBlock) -> Seal {
Expand Down
4 changes: 3 additions & 1 deletion ethcore/src/engines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ pub trait Engine : Sync + Send {
fn params(&self) -> &CommonParams;

/// Get the EVM schedule for the given `block_number`.
fn schedule(&self, block_number: BlockNumber) -> Schedule;
fn schedule(&self, block_number: BlockNumber) -> Schedule {
Schedule::from_params(block_number, self.params())
}

/// Builtin-contracts we would like to see in the chain.
/// (In principle these are just hints for the engine since that has the last word on them.)
Expand Down
6 changes: 0 additions & 6 deletions ethcore/src/engines/tendermint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ use account_provider::AccountProvider;
use block::*;
use spec::CommonParams;
use engines::{Engine, Seal, EngineError};
use evm::Schedule;
use state::CleanupMode;
use io::IoService;
use super::signer::EngineSigner;
Expand Down Expand Up @@ -404,11 +403,6 @@ impl Engine for Tendermint {
]
}

fn schedule(&self, block_number: BlockNumber) -> Schedule {
let eip86 = block_number >= self.params.eip86_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86)
}

fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
// Chain scoring: total weight is sqrt(U256::max_value())*height - view
let new_difficulty = U256::from(U128::max_value()) + consensus_view(parent).expect("Header has been verified; qed").into() - self.view.load(AtomicOrdering::SeqCst).into();
Expand Down
8 changes: 4 additions & 4 deletions ethcore/src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,13 @@ impl Engine for Arc<Ethash> {
} else if block_number < self.ethash_params.eip150_transition {
Schedule::new_homestead()
} else {
Schedule::new_post_eip150(
let mut schedule = Schedule::new_post_eip150(
self.ethash_params.max_code_size as usize,
block_number >= self.ethash_params.eip160_transition,
block_number >= self.ethash_params.eip161abc_transition,
block_number >= self.ethash_params.eip161d_transition,
block_number >= self.params.eip86_transition
)
block_number >= self.ethash_params.eip161d_transition);
schedule.apply_params(block_number, self.params());
schedule
}
}

Expand Down
4 changes: 3 additions & 1 deletion ethcore/src/evm/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ pub enum Error {
},
/// Built-in contract failed on given input
BuiltIn(&'static str),
/// Returned on evm internal error. Should never be ignored during development.
/// When execution tries to modify the state in static context
MutableCallInStaticContext,
/// Likely to cause consensus issues.
Internal(String),
}
Expand Down Expand Up @@ -90,6 +91,7 @@ impl fmt::Display for Error {
OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
Internal(ref msg) => write!(f, "Internal error: {}", msg),
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
}
}
}
Expand Down
21 changes: 10 additions & 11 deletions ethcore/src/evm/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,24 @@ pub enum CreateContractAddress {
}

/// Externalities interface for EVMs
// TODO: [rob] associated error type instead of `trie::Result`. Not all EVMs are trie powered.
pub trait Ext {
/// Returns a value for given key.
fn storage_at(&self, key: &H256) -> trie::Result<H256>;
fn storage_at(&self, key: &H256) -> evm::Result<H256>;

/// Stores a value for given key.
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()>;
fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()>;

/// Determine whether an account exists.
fn exists(&self, address: &Address) -> trie::Result<bool>;
fn exists(&self, address: &Address) -> evm::Result<bool>;

/// Determine whether an account exists and is not null (zero balance/nonce, no code).
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool>;
fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool>;

/// Balance of the origin account.
fn origin_balance(&self) -> trie::Result<U256>;
fn origin_balance(&self) -> evm::Result<U256>;

/// Returns address balance.
fn balance(&self, address: &Address) -> trie::Result<U256>;
fn balance(&self, address: &Address) -> evm::Result<U256>;

/// Returns the hash of one of the 256 most recent complete blocks.
fn blockhash(&mut self, number: &U256) -> H256;
Expand Down Expand Up @@ -99,21 +98,21 @@ pub trait Ext {
) -> MessageCallResult;

/// Returns code at given address
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>>;
fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>>;

/// Returns code size at given address
fn extcodesize(&self, address: &Address) -> trie::Result<usize>;
fn extcodesize(&self, address: &Address) -> evm::Result<usize>;

/// Creates log entry with given topics and data
fn log(&mut self, topics: Vec<H256>, data: &[u8]);
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()>;

/// Should be called when transaction calls `RETURN` opcode.
/// Returns gas_left if cost of returning the data is not too high.
fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result<U256>;

/// Should be called when contract commits suicide.
/// Address to which funds should be refunded.
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> ;
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> ;

/// Returns schedule.
fn schedule(&self) -> &Schedule;
Expand Down
3 changes: 3 additions & 0 deletions ethcore/src/evm/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ lazy_static! {
arr[CALLCODE as usize] = InstructionInfo::new("CALLCODE", 0, 7, 1, true, GasPriceTier::Special);
arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero);
arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special);
arr[STATICCALL as usize] = InstructionInfo::new("STATICCALL", 0, 6, 1, true, GasPriceTier::Special);
arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special);
arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 0, 3, 1, true, GasPriceTier::Special);
arr[REVERT as usize] = InstructionInfo::new("REVERT", 0, 2, 0, true, GasPriceTier::Zero);
Expand Down Expand Up @@ -565,6 +566,8 @@ pub const DELEGATECALL: Instruction = 0xf4;
pub const CREATE2: Instruction = 0xfb;
/// stop execution and revert state changes. Return output data.
pub const REVERT: Instruction = 0xfd;
/// like CALL but it does not take value, nor modify the state
pub const STATICCALL: Instruction = 0xfa;
/// halt execution and register account for later deletion
pub const SUICIDE: Instruction = 0xff;

2 changes: 1 addition & 1 deletion ethcore/src/evm/interpreter/gasometer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl<Gas: CostType> Gasometer<Gas> {

Request::GasMemProvide(gas, mem, Some(requested))
},
instructions::DELEGATECALL => {
instructions::DELEGATECALL | instructions::STATICCALL => {
let gas = Gas::from(schedule.call_gas);
let mem = cmp::max(
mem_needed(stack.peek(4), stack.peek(5))?,
Expand Down
9 changes: 6 additions & 3 deletions ethcore/src/evm/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ impl<Cost: CostType> Interpreter<Cost> {

if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
(instruction == instructions::CREATE2 && !schedule.have_create2) ||
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
(instruction == instructions::REVERT && !schedule.have_revert) {

return Err(evm::Error::BadInstruction {
Expand Down Expand Up @@ -312,14 +313,15 @@ impl<Cost: CostType> Interpreter<Cost> {
}
};
},
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => {
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {
assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible");

stack.pop_back();
let call_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed");
let code_address = stack.pop_back();
let code_address = u256_to_address(&code_address);

let value = if instruction == instructions::DELEGATECALL {
let value = if instruction == instructions::DELEGATECALL || instruction == instructions::STATICCALL {
None
} else {
Some(stack.pop_back())
Expand Down Expand Up @@ -347,6 +349,7 @@ impl<Cost: CostType> Interpreter<Cost> {
(&params.address, &params.address, has_balance, CallType::CallCode)
},
instructions::DELEGATECALL => (&params.sender, &params.address, true, CallType::DelegateCall),
instructions::STATICCALL => (&params.sender, &params.address, true, CallType::StaticCall),
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
};

Expand Down Expand Up @@ -405,7 +408,7 @@ impl<Cost: CostType> Interpreter<Cost> {
.iter()
.map(H256::from)
.collect();
ext.log(topics, self.mem.read_slice(offset, size));
ext.log(topics, self.mem.read_slice(offset, size))?;
},
instructions::PUSH1...instructions::PUSH32 => {
let bytes = instructions::get_push_bytes(instruction);
Expand Down
37 changes: 32 additions & 5 deletions ethcore/src/evm/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

//! Cost schedule and other parameterisations for the EVM.
use spec::CommonParams;

/// Definition of the cost schedule and other parameterisations for the EVM.
pub struct Schedule {
Expand Down Expand Up @@ -105,6 +106,8 @@ pub struct Schedule {
pub kill_empty: bool,
/// Blockhash instruction gas cost.
pub blockhash_gas: usize,
/// Static Call opcode enabled.
pub have_static_call: bool,
}

impl Schedule {
Expand All @@ -119,12 +122,12 @@ impl Schedule {
}

/// 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, have_metropolis_instructions: bool) -> Schedule {
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: have_metropolis_instructions,
have_revert: have_metropolis_instructions,
have_create2: false,
have_revert: false,
stack_limit: 1024,
max_depth: 1024,
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
Expand Down Expand Up @@ -163,13 +166,36 @@ impl Schedule {
sub_gas_cap_divisor: Some(64),
no_empty: no_empty,
kill_empty: kill_empty,
blockhash_gas: if have_metropolis_instructions { 350 } else { 20 },
blockhash_gas: 20,
have_static_call: false,
}
}

/// Schedule for the Metropolis era from common spec params.
pub fn from_params(block_number: u64, params: &CommonParams) -> Schedule {
let mut schedule = Schedule::new_post_eip150(usize::max_value(), true, true, true);
schedule.apply_params(block_number, params);
schedule
}

/// Apply common spec config parameters to the schedule.
pub fn apply_params(&mut self, block_number: u64, params: &CommonParams) {
self.have_create2 = block_number >= params.eip86_transition;
self.have_revert = block_number >= params.eip140_transition;
self.have_static_call = block_number >= params.eip214_transition;
if block_number >= params.eip210_transition {
self.blockhash_gas = 350;
}
}

/// Schedule for the Metropolis of the Ethereum main net.
pub fn new_metropolis() -> Schedule {
Self::new_post_eip150(24576, true, true, true, true)
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.blockhash_gas = 350;
schedule
}

fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
Expand Down Expand Up @@ -217,6 +243,7 @@ impl Schedule {
no_empty: false,
kill_empty: false,
blockhash_gas: 20,
have_static_call: false,
}
}
}
Expand Down
Loading

0 comments on commit edba366

Please sign in to comment.