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

Commit

Permalink
More STATICALL fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
arkpar committed Sep 8, 2017
1 parent 22269b6 commit 42f0ae1
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 3 deletions.
12 changes: 10 additions & 2 deletions ethcore/evm/src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,9 @@ impl<Cost: CostType> Interpreter<Cost> {
// Get sender & receive addresses, check if we have balance
let (sender_address, receive_address, has_balance, call_type) = match instruction {
instructions::CALL => {
if ext.is_static() && value.map_or(false, |v| !v.is_zero()) {
return Err(vm::Error::MutableCallInStaticContext);
}
let has_balance = ext.balance(&params.address)? >= value.expect("value set for all but delegate call and staticcall; qed");
(&params.address, &code_address, has_balance, CallType::Call)
},
Expand All @@ -388,11 +391,11 @@ 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, &code_address, true, CallType::StaticCall),
instructions::STATICCALL => (&params.address, &code_address, true, CallType::StaticCall),
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
};

// clear return data buffer before crearing new call frame.
// clear return data buffer before creating new call frame.
self.return_data = ReturnData::empty();

let can_call = has_balance && ext.depth() < ext.schedule().max_depth;
Expand All @@ -415,6 +418,11 @@ impl<Cost: CostType> Interpreter<Cost> {
self.return_data = data;
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater then current one")))
},
MessageCallResult::Reverted(gas_left, data) => {
stack.push(U256::zero());
self.return_data = data;
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater then current one")))
},
MessageCallResult::Failed => {
stack.push(U256::zero());
Ok(InstructionResult::Ok)
Expand Down
7 changes: 6 additions & 1 deletion ethcore/src/externalities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
}
}

fn is_static(&self) -> bool {
return self.static_flag
}

fn exists(&self, address: &Address) -> vm::Result<bool> {
self.state.exists(address).map_err(Into::into)
}
Expand Down Expand Up @@ -276,7 +280,8 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);

match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) {
Ok(FinalizationResult{ gas_left, return_data, .. }) => MessageCallResult::Success(gas_left, return_data),
Ok(FinalizationResult{ gas_left, return_data, apply_state: true }) => MessageCallResult::Success(gas_left, return_data),
Ok(FinalizationResult{ gas_left, return_data, apply_state: false }) => MessageCallResult::Reverted(gas_left, return_data),
_ => MessageCallResult::Failed
}
}
Expand Down
4 changes: 4 additions & 0 deletions ethcore/src/json_tests/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
0
}

fn is_static(&self) -> bool {
false
}

fn inc_sstore_clears(&mut self) {
self.ext.inc_sstore_clears()
}
Expand Down
6 changes: 6 additions & 0 deletions ethcore/vm/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ pub enum MessageCallResult {
/// Returned when message call failed.
/// VM doesn't have to know the reason.
Failed,
/// Returned when message call was reverted.
/// Contains gas left and output data.
Reverted(U256, ReturnData),
}

/// Specifies how an address is calculated for a new contract.
Expand Down Expand Up @@ -143,4 +146,7 @@ pub trait Ext {

/// Trace the finalised execution of a single instruction.
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}

/// Check if running in static context.
fn is_static(&self) -> bool;
}
4 changes: 4 additions & 0 deletions ethcore/vm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ impl Ext for FakeExt {
self.depth
}

fn is_static(&self) -> bool {
false
}

fn inc_sstore_clears(&mut self) {
self.sstore_clears += 1;
}
Expand Down
5 changes: 5 additions & 0 deletions ethcore/wasm/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ impl<'a, 'b> Runtime<'a, 'b> {
self.memory.set(result_ptr, &result)?;
Ok(Some(0i32.into()))
},
vm::MessageCallResult::Reverted(gas_left, _) => {
self.gas_counter = self.gas_limit - gas_left.low_u64();
self.memory.set(result_ptr, &result)?;
Ok(Some((-1i32).into()))
},
vm::MessageCallResult::Failed => {
Ok(Some((-1i32).into()))
}
Expand Down

0 comments on commit 42f0ae1

Please sign in to comment.