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 committed Mar 10, 2017
1 parent ea02094 commit c5494f7
Show file tree
Hide file tree
Showing 18 changed files with 120 additions and 44 deletions.
2 changes: 1 addition & 1 deletion ethcore/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,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)
Schedule::new_post_eip150(24576, true, true, true, true)
}

fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
Expand Down
5 changes: 3 additions & 2 deletions ethcore/src/engines/authority_round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,9 @@ impl Engine for AuthorityRound {
]
}

fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
Schedule::new_post_eip150(usize::max_value(), true, true, true)
fn schedule(&self, env_info: &EnvInfo) -> Schedule {
let eip214 = env_info.number >= self.params.eip214_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip214)
}

fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
Expand Down
5 changes: 3 additions & 2 deletions ethcore/src/engines/instant_seal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ impl Engine for InstantSeal {
&self.builtins
}

fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
Schedule::new_post_eip150(usize::max_value(), true, true, true)
fn schedule(&self, env_info: &EnvInfo) -> Schedule {
let eip214 = env_info.number >= self.params.eip214_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip214)
}

fn seals_internally(&self) -> Option<bool> { Some(true) }
Expand Down
5 changes: 3 additions & 2 deletions ethcore/src/engines/tendermint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,9 @@ impl Engine for Tendermint {
]
}

fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
Schedule::new_post_eip150(usize::max_value(), true, true, true)
fn schedule(&self, env_info: &EnvInfo) -> Schedule {
let eip214 = env_info.number >= self.params.eip214_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip214)
}

fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
Expand Down
3 changes: 2 additions & 1 deletion ethcore/src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ impl Engine for Ethash {
self.ethash_params.max_code_size as usize,
env_info.number >= self.ethash_params.eip160_transition,
env_info.number >= self.ethash_params.eip161abc_transition,
env_info.number >= self.ethash_params.eip161d_transition
env_info.number >= self.ethash_params.eip161d_transition,
env_info.number >= self.params.eip214_transition,
)
}
}
Expand Down
3 changes: 3 additions & 0 deletions ethcore/src/evm/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ pub enum Error {
/// What was the stack limit
limit: usize
},
/// When execution tries to modify the state in static context
MutableCallInStaticContext,
/// Returned on evm internal error. Should never be ignored during development.
/// Likely to cause consensus issues.
Internal(String),
Expand All @@ -79,6 +81,7 @@ impl fmt::Display for Error {
BadInstruction { .. } => "Bad instruction",
StackUnderflow { .. } => "Stack underflow",
OutOfStack { .. } => "Out of stack",
MutableCallInStaticContext => "Mutable call in static context",
Internal(ref msg) => msg,
};
message.fmt(f)
Expand Down
6 changes: 3 additions & 3 deletions ethcore/src/evm/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub trait Ext {
fn storage_at(&self, key: &H256) -> trie::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>;
Expand Down Expand Up @@ -94,15 +94,15 @@ pub trait Ext {
fn extcodesize(&self, address: &Address) -> trie::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: &[u8]) -> evm::Result<U256> where Self: Sized;

/// 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 @@ -277,6 +277,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
};
Expand Down Expand Up @@ -553,6 +554,8 @@ pub const CALLCODE: Instruction = 0xf2;
pub const RETURN: Instruction = 0xf3;
/// like CALLCODE but keeps caller's value and sender
pub const DELEGATECALL: Instruction = 0xf4;
/// 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;

14 changes: 11 additions & 3 deletions ethcore/src/evm/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,14 +292,21 @@ 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");
if instruction == instructions::STATICCALL && !ext.schedule().static_call {
// STATICCALL is not enabled, yet called
return Err(evm::Error::BadInstruction {
instruction: instruction
});
}

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 @@ -327,6 +334,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 @@ -378,7 +386,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
6 changes: 5 additions & 1 deletion ethcore/src/evm/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ pub struct Schedule {
pub no_empty: bool,
/// Kill empty accounts if touched.
pub kill_empty: bool,
/// Static Call opcode enabled.
pub static_call: bool,
}

impl Schedule {
Expand All @@ -113,7 +115,7 @@ 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) -> Schedule {
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, static_call: bool) -> Schedule {
Schedule {
exceptional_failed_code_deposit: true,
have_delegate_call: true,
Expand Down Expand Up @@ -155,6 +157,7 @@ impl Schedule {
sub_gas_cap_divisor: Some(64),
no_empty: no_empty,
kill_empty: kill_empty,
static_call: static_call,
}
}

Expand Down Expand Up @@ -200,6 +203,7 @@ impl Schedule {
sub_gas_cap_divisor: None,
no_empty: false,
kill_empty: false,
static_call: false,
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions ethcore/src/evm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Ext for FakeExt {
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
}

fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> {
fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> {
self.store.insert(key, value);
Ok(())
}
Expand Down Expand Up @@ -155,18 +155,19 @@ impl Ext for FakeExt {
Ok(self.codes.get(address).map_or(0, |c| c.len()))
}

fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
self.logs.push(FakeLogEntry {
topics: topics,
data: data.to_vec()
});
Ok(())
}

fn ret(self, _gas: &U256, _data: &[u8]) -> evm::Result<U256> {
unimplemented!();
}

fn suicide(&mut self, _refund_address: &Address) -> trie::Result<()> {
fn suicide(&mut self, _refund_address: &Address) -> evm::Result<()> {
unimplemented!();
}

Expand Down
29 changes: 22 additions & 7 deletions ethcore/src/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub struct Executive<'a, B: 'a + StateBackend> {
engine: &'a Engine,
vm_factory: &'a Factory,
depth: usize,
static_flag: bool,
}

impl<'a, B: 'a + StateBackend> Executive<'a, B> {
Expand All @@ -73,17 +74,19 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
engine: engine,
vm_factory: vm_factory,
depth: 0,
static_flag: false,
}
}

/// Populates executive from parent properties. Increments executive depth.
pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize) -> Self {
pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize, static_flag: bool) -> Self {
Executive {
state: state,
info: info,
engine: engine,
vm_factory: vm_factory,
depth: parent_depth + 1,
static_flag: static_flag,
}
}

Expand All @@ -94,9 +97,11 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
substate: &'any mut Substate,
output: OutputPolicy<'any, 'any>,
tracer: &'any mut T,
vm_tracer: &'any mut V
vm_tracer: &'any mut V,
static_call: bool,
) -> Externalities<'any, T, V, B> where T: Tracer, V: VMTracer {
Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer, vm_tracer)
let is_static = self.static_flag || static_call;
Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer, vm_tracer, is_static)
}

/// This function should be used to execute transaction.
Expand Down Expand Up @@ -216,11 +221,12 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
) -> evm::Result<U256> where T: Tracer, V: VMTracer {

let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
let static_call = params.call_type == CallType::StaticCall;

// Ordinary execution - keep VM in same thread
if (self.depth + 1) % depth_threshold != 0 {
let vm_factory = self.vm_factory;
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer);
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
return vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext);
}
Expand All @@ -230,7 +236,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// https://github.com/aturon/crossbeam/issues/16
crossbeam::scope(|scope| {
let vm_factory = self.vm_factory;
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer);
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);

scope.spawn(move || {
vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext)
Expand All @@ -253,13 +259,17 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// backup used in case of running out of gas
self.state.checkpoint();

trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
if (params.call_type == CallType::StaticCall || self.static_flag) && params.value.value() > 0.into() {
return Err(evm::Error::MutableCallInStaticContext);
}

let schedule = self.engine.schedule(self.info);

// at first, transfer value to destination
if let ActionValue::Transfer(val) = params.value {
self.state.transfer_balance(&params.sender, &params.address, &val, substate.to_cleanup_mode(&schedule))?;
}
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);

if self.engine.is_builtin(&params.code_address) {
// if destination is builtin, try to execute it
Expand Down Expand Up @@ -359,6 +369,10 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// backup used in case of running out of gas
self.state.checkpoint();

if params.call_type == CallType::StaticCall || self.static_flag {
return Err(evm::Error::MutableCallInStaticContext);
}

// part of substate that may be reverted
let mut unconfirmed_substate = Substate::new();

Expand Down Expand Up @@ -492,7 +506,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
| Err(evm::Error::BadJumpDestination {..})
| Err(evm::Error::BadInstruction {.. })
| Err(evm::Error::StackUnderflow {..})
| Err(evm::Error::OutOfStack {..}) => {
| Err(evm::Error::OutOfStack {..})
| Err(evm::Error::MutableCallInStaticContext) => {
self.state.revert_to_checkpoint();
},
Ok(_) | Err(evm::Error::Internal(_)) => {
Expand Down
Loading

0 comments on commit c5494f7

Please sign in to comment.