Refactor static context check in CREATE. (#6886)

* Refactor static context check in CREATE.

* Fix wasm.
This commit is contained in:
Tomasz Drwięga 2017-10-25 11:27:18 +02:00 committed by Arkadiy Paronyan
parent b50ed887c7
commit 8dfdebc2a2
6 changed files with 38 additions and 24 deletions

View File

@ -322,20 +322,24 @@ impl<Cost: CostType> Interpreter<Cost> {
let init_off = stack.pop_back(); let init_off = stack.pop_back();
let init_size = stack.pop_back(); let init_size = stack.pop_back();
let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };
let create_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 `CREATE`; qed"); let create_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 `CREATE`; qed");
let contract_code = self.mem.read_slice(init_off, init_size); if ext.is_static() {
let can_create = ext.balance(&params.address)? >= endowment && ext.depth() < ext.schedule().max_depth; return Err(vm::Error::MutableCallInStaticContext);
}
// clear return data buffer before creating new call frame. // clear return data buffer before creating new call frame.
self.return_data = ReturnData::empty(); self.return_data = ReturnData::empty();
let can_create = ext.balance(&params.address)? >= endowment && ext.depth() < ext.schedule().max_depth;
if !can_create { if !can_create {
stack.push(U256::zero()); stack.push(U256::zero());
return Ok(InstructionResult::UnusedGas(create_gas)); return Ok(InstructionResult::UnusedGas(create_gas));
} }
let contract_code = self.mem.read_slice(init_off, init_size);
let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };
let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme); let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme);
return match create_result { return match create_result {
ContractCreateResult::Created(address, gas_left) => { ContractCreateResult::Created(address, gas_left) => {
@ -351,9 +355,6 @@ impl<Cost: CostType> Interpreter<Cost> {
stack.push(U256::zero()); stack.push(U256::zero());
Ok(InstructionResult::Ok) Ok(InstructionResult::Ok)
}, },
ContractCreateResult::FailedInStaticCall => {
Err(vm::Error::MutableCallInStaticContext)
},
}; };
}, },
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => { instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {

View File

@ -724,7 +724,6 @@ fn test_jumps(factory: super::Factory) {
assert_eq!(gas_left, U256::from(54_117)); assert_eq!(gas_left, U256::from(54_117));
} }
evm_test!{test_calls: test_calls_jit, test_calls_int} evm_test!{test_calls: test_calls_jit, test_calls_int}
fn test_calls(factory: super::Factory) { fn test_calls(factory: super::Factory) {
let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap(); let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap();
@ -769,6 +768,27 @@ fn test_calls(factory: super::Factory) {
assert_eq!(ext.calls.len(), 2); assert_eq!(ext.calls.len(), 2);
} }
evm_test!{test_create_in_staticcall: test_create_in_staticcall_jit, test_create_in_staticcall_int}
fn test_create_in_staticcall(factory: super::Factory) {
let code = "600060006064f000".from_hex().unwrap();
let address = Address::from(0x155);
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
params.address = address.clone();
let mut ext = FakeExt::new_byzantium();
ext.is_static = true;
let err = {
let mut vm = factory.create(params.gas);
test_finalize(vm.exec(params, &mut ext)).unwrap_err()
};
assert_eq!(err, vm::Error::MutableCallInStaticContext);
assert_eq!(ext.calls.len(), 0);
}
fn assert_set_contains<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, val: &T) { fn assert_set_contains<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, val: &T) {
let contains = set.contains(val); let contains = set.contains(val);
if !contains { if !contains {

View File

@ -240,7 +240,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
Ok(FinalizationResult{ gas_left, apply_state: false, return_data }) => { Ok(FinalizationResult{ gas_left, apply_state: false, return_data }) => {
ContractCreateResult::Reverted(gas_left, return_data) ContractCreateResult::Reverted(gas_left, return_data)
}, },
Err(vm::Error::MutableCallInStaticContext) => ContractCreateResult::FailedInStaticCall,
_ => ContractCreateResult::Failed, _ => ContractCreateResult::Failed,
} }
} }

View File

@ -35,9 +35,6 @@ pub enum ContractCreateResult {
/// Returned when contract creation failed. /// Returned when contract creation failed.
/// VM doesn't have to know the reason. /// VM doesn't have to know the reason.
Failed, Failed,
/// Returned when contract creation failed.
/// VM doesn't have to know the reason.
FailedInStaticCall,
/// Reverted with REVERT. /// Reverted with REVERT.
Reverted(U256, ReturnData), Reverted(U256, ReturnData),
} }

View File

@ -65,6 +65,7 @@ pub struct FakeExt {
pub schedule: Schedule, pub schedule: Schedule,
pub balances: HashMap<Address, U256>, pub balances: HashMap<Address, U256>,
pub tracing: bool, pub tracing: bool,
pub is_static: bool,
} }
// similar to the normal `finalize` function, but ignoring NeedsReturn. // similar to the normal `finalize` function, but ignoring NeedsReturn.
@ -192,7 +193,7 @@ impl Ext for FakeExt {
} }
fn is_static(&self) -> bool { fn is_static(&self) -> bool {
false self.is_static
} }
fn inc_sstore_clears(&mut self) { fn inc_sstore_clears(&mut self) {

View File

@ -221,8 +221,8 @@ impl<'a, 'b> Runtime<'a, 'b> {
} }
/// Charge gas according to closure /// Charge gas according to closure
pub fn charge<F>(&mut self, f: F) -> Result<(), InterpreterError> pub fn charge<F>(&mut self, f: F) -> Result<(), InterpreterError>
where F: FnOnce(&vm::Schedule) -> u64 where F: FnOnce(&vm::Schedule) -> u64
{ {
let amount = f(self.ext.schedule()); let amount = f(self.ext.schedule());
if !self.charge_gas(amount as u64) { if !self.charge_gas(amount as u64) {
@ -277,10 +277,6 @@ impl<'a, 'b> Runtime<'a, 'b> {
self.gas_counter = self.gas_limit - gas_left.low_u64(); self.gas_counter = self.gas_limit - gas_left.low_u64();
Ok(Some((-1i32).into())) Ok(Some((-1i32).into()))
}, },
vm::ContractCreateResult::FailedInStaticCall => {
trace!(target: "wasm", "runtime: create contract called in static context");
Err(interpreter::Error::Trap("CREATE in static context".to_owned()))
},
} }
} }
@ -615,11 +611,11 @@ impl<'a, 'b> Runtime<'a, 'b> {
} }
fn return_u256_ptr(&mut self, ptr: u32, val: U256) -> Result<(), InterpreterError> { fn return_u256_ptr(&mut self, ptr: u32, val: U256) -> Result<(), InterpreterError> {
let value: H256 = val.into(); let value: H256 = val.into();
self.charge(|schedule| schedule.wasm.static_u256 as u64)?; self.charge(|schedule| schedule.wasm.static_u256 as u64)?;
self.memory.set(ptr, &*value)?; self.memory.set(ptr, &*value)?;
Ok(()) Ok(())
} }
fn coinbase(&mut self, context: InterpreterCallerContext) fn coinbase(&mut self, context: InterpreterCallerContext)
-> Result<Option<interpreter::RuntimeValue>, InterpreterError> -> Result<Option<interpreter::RuntimeValue>, InterpreterError>
@ -640,7 +636,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
sender, sender,
)?; )?;
Ok(None) Ok(None)
} }
fn address(&mut self, context: InterpreterCallerContext) fn address(&mut self, context: InterpreterCallerContext)
@ -651,7 +647,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
addr, addr,
)?; )?;
Ok(None) Ok(None)
} }
fn origin(&mut self, context: InterpreterCallerContext) fn origin(&mut self, context: InterpreterCallerContext)
@ -662,7 +658,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
origin, origin,
)?; )?;
Ok(None) Ok(None)
} }
fn value(&mut self, context: InterpreterCallerContext) fn value(&mut self, context: InterpreterCallerContext)
@ -709,7 +705,7 @@ impl<'a, 'b> Runtime<'a, 'b> {
context.value_stack.pop_as::<i32>()? as u32, context.value_stack.pop_as::<i32>()? as u32,
gas_limit, gas_limit,
)?; )?;
Ok(None) Ok(None)
} }
fn return_i64(&mut self, val: i64) -> Result<Option<interpreter::RuntimeValue>, InterpreterError> { fn return_i64(&mut self, val: i64) -> Result<Option<interpreter::RuntimeValue>, InterpreterError> {