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

Commit c5494f7

Browse files
committed
eip214, #4833
1 parent ea02094 commit c5494f7

File tree

18 files changed

+120
-44
lines changed

18 files changed

+120
-44
lines changed

ethcore/src/client/test_client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
352352

353353
impl MiningBlockChainClient for TestBlockChainClient {
354354
fn latest_schedule(&self) -> Schedule {
355-
Schedule::new_post_eip150(24576, true, true, true)
355+
Schedule::new_post_eip150(24576, true, true, true, true)
356356
}
357357

358358
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {

ethcore/src/engines/authority_round.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,9 @@ impl Engine for AuthorityRound {
230230
]
231231
}
232232

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

237238
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {

ethcore/src/engines/instant_seal.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ impl Engine for InstantSeal {
5858
&self.builtins
5959
}
6060

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

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

ethcore/src/engines/tendermint/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,9 @@ impl Engine for Tendermint {
401401
]
402402
}
403403

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

408409
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {

ethcore/src/ethereum/ethash.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ impl Engine for Ethash {
173173
self.ethash_params.max_code_size as usize,
174174
env_info.number >= self.ethash_params.eip160_transition,
175175
env_info.number >= self.ethash_params.eip161abc_transition,
176-
env_info.number >= self.ethash_params.eip161d_transition
176+
env_info.number >= self.ethash_params.eip161d_transition,
177+
env_info.number >= self.params.eip214_transition,
177178
)
178179
}
179180
}

ethcore/src/evm/evm.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ pub enum Error {
5959
/// What was the stack limit
6060
limit: usize
6161
},
62+
/// When execution tries to modify the state in static context
63+
MutableCallInStaticContext,
6264
/// Returned on evm internal error. Should never be ignored during development.
6365
/// Likely to cause consensus issues.
6466
Internal(String),
@@ -79,6 +81,7 @@ impl fmt::Display for Error {
7981
BadInstruction { .. } => "Bad instruction",
8082
StackUnderflow { .. } => "Stack underflow",
8183
OutOfStack { .. } => "Out of stack",
84+
MutableCallInStaticContext => "Mutable call in static context",
8285
Internal(ref msg) => msg,
8386
};
8487
message.fmt(f)

ethcore/src/evm/ext.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub trait Ext {
4848
fn storage_at(&self, key: &H256) -> trie::Result<H256>;
4949

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

5353
/// Determine whether an account exists.
5454
fn exists(&self, address: &Address) -> trie::Result<bool>;
@@ -94,15 +94,15 @@ pub trait Ext {
9494
fn extcodesize(&self, address: &Address) -> trie::Result<usize>;
9595

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

9999
/// Should be called when transaction calls `RETURN` opcode.
100100
/// Returns gas_left if cost of returning the data is not too high.
101101
fn ret(self, gas: &U256, data: &[u8]) -> evm::Result<U256> where Self: Sized;
102102

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

107107
/// Returns schedule.
108108
fn schedule(&self) -> &Schedule;

ethcore/src/evm/instructions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ lazy_static! {
277277
arr[CALLCODE as usize] = InstructionInfo::new("CALLCODE", 0, 7, 1, true, GasPriceTier::Special);
278278
arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero);
279279
arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special);
280+
arr[STATICCALL as usize] = InstructionInfo::new("STATICCALL", 0, 6, 1, true, GasPriceTier::Special);
280281
arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special);
281282
arr
282283
};
@@ -553,6 +554,8 @@ pub const CALLCODE: Instruction = 0xf2;
553554
pub const RETURN: Instruction = 0xf3;
554555
/// like CALLCODE but keeps caller's value and sender
555556
pub const DELEGATECALL: Instruction = 0xf4;
557+
/// like CALL but it does not take value, nor modify the state
558+
pub const STATICCALL: Instruction = 0xfa;
556559
/// halt execution and register account for later deletion
557560
pub const SUICIDE: Instruction = 0xff;
558561

ethcore/src/evm/interpreter/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,21 @@ impl<Cost: CostType> Interpreter<Cost> {
292292
}
293293
};
294294
},
295-
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => {
295+
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {
296296
assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible");
297+
if instruction == instructions::STATICCALL && !ext.schedule().static_call {
298+
// STATICCALL is not enabled, yet called
299+
return Err(evm::Error::BadInstruction {
300+
instruction: instruction
301+
});
302+
}
303+
297304
stack.pop_back();
298305
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");
299306
let code_address = stack.pop_back();
300307
let code_address = u256_to_address(&code_address);
301308

302-
let value = if instruction == instructions::DELEGATECALL {
309+
let value = if instruction == instructions::DELEGATECALL || instruction == instructions::STATICCALL {
303310
None
304311
} else {
305312
Some(stack.pop_back())
@@ -327,6 +334,7 @@ impl<Cost: CostType> Interpreter<Cost> {
327334
(&params.address, &params.address, has_balance, CallType::CallCode)
328335
},
329336
instructions::DELEGATECALL => (&params.sender, &params.address, true, CallType::DelegateCall),
337+
instructions::STATICCALL => (&params.sender, &params.address, true, CallType::StaticCall),
330338
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
331339
};
332340

@@ -378,7 +386,7 @@ impl<Cost: CostType> Interpreter<Cost> {
378386
.iter()
379387
.map(H256::from)
380388
.collect();
381-
ext.log(topics, self.mem.read_slice(offset, size));
389+
ext.log(topics, self.mem.read_slice(offset, size))?;
382390
},
383391
instructions::PUSH1...instructions::PUSH32 => {
384392
let bytes = instructions::get_push_bytes(instruction);

ethcore/src/evm/schedule.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ pub struct Schedule {
9999
pub no_empty: bool,
100100
/// Kill empty accounts if touched.
101101
pub kill_empty: bool,
102+
/// Static Call opcode enabled.
103+
pub static_call: bool,
102104
}
103105

104106
impl Schedule {
@@ -113,7 +115,7 @@ impl Schedule {
113115
}
114116

115117
/// Schedule for the post-EIP-150-era of the Ethereum main net.
116-
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule {
118+
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, static_call: bool) -> Schedule {
117119
Schedule {
118120
exceptional_failed_code_deposit: true,
119121
have_delegate_call: true,
@@ -155,6 +157,7 @@ impl Schedule {
155157
sub_gas_cap_divisor: Some(64),
156158
no_empty: no_empty,
157159
kill_empty: kill_empty,
160+
static_call: static_call,
158161
}
159162
}
160163

@@ -200,6 +203,7 @@ impl Schedule {
200203
sub_gas_cap_divisor: None,
201204
no_empty: false,
202205
kill_empty: false,
206+
static_call: false,
203207
}
204208
}
205209
}

ethcore/src/evm/tests.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl Ext for FakeExt {
8686
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
8787
}
8888

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

158-
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
158+
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
159159
self.logs.push(FakeLogEntry {
160160
topics: topics,
161161
data: data.to_vec()
162162
});
163+
Ok(())
163164
}
164165

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

169-
fn suicide(&mut self, _refund_address: &Address) -> trie::Result<()> {
170+
fn suicide(&mut self, _refund_address: &Address) -> evm::Result<()> {
170171
unimplemented!();
171172
}
172173

ethcore/src/executive.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub struct Executive<'a, B: 'a + StateBackend> {
6262
engine: &'a Engine,
6363
vm_factory: &'a Factory,
6464
depth: usize,
65+
static_flag: bool,
6566
}
6667

6768
impl<'a, B: 'a + StateBackend> Executive<'a, B> {
@@ -73,17 +74,19 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
7374
engine: engine,
7475
vm_factory: vm_factory,
7576
depth: 0,
77+
static_flag: false,
7678
}
7779
}
7880

7981
/// Populates executive from parent properties. Increments executive depth.
80-
pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize) -> Self {
82+
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 {
8183
Executive {
8284
state: state,
8385
info: info,
8486
engine: engine,
8587
vm_factory: vm_factory,
8688
depth: parent_depth + 1,
89+
static_flag: static_flag,
8790
}
8891
}
8992

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

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

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

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

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

262+
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
263+
if (params.call_type == CallType::StaticCall || self.static_flag) && params.value.value() > 0.into() {
264+
return Err(evm::Error::MutableCallInStaticContext);
265+
}
266+
256267
let schedule = self.engine.schedule(self.info);
257268

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

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

372+
if params.call_type == CallType::StaticCall || self.static_flag {
373+
return Err(evm::Error::MutableCallInStaticContext);
374+
}
375+
362376
// part of substate that may be reverted
363377
let mut unconfirmed_substate = Substate::new();
364378

@@ -492,7 +506,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
492506
| Err(evm::Error::BadJumpDestination {..})
493507
| Err(evm::Error::BadInstruction {.. })
494508
| Err(evm::Error::StackUnderflow {..})
495-
| Err(evm::Error::OutOfStack {..}) => {
509+
| Err(evm::Error::OutOfStack {..})
510+
| Err(evm::Error::MutableCallInStaticContext) => {
496511
self.state.revert_to_checkpoint();
497512
},
498513
Ok(_) | Err(evm::Error::Internal(_)) => {

0 commit comments

Comments
 (0)