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

Commit eefc94e

Browse files
sorpaasandresilva
authored andcommitted
Implement EIP-1052 (EXTCODEHASH) and fix several issues in state account cache (#9234)
* Implement EIP-1052 and fix several issues related to account cache * Fix jsontests * Merge two matches together * Avoid making unnecessary Arc<Vec> * Address grumbles
1 parent 93b25d5 commit eefc94e

File tree

15 files changed

+111
-43
lines changed

15 files changed

+111
-43
lines changed

ethcore/evm/src/instructions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ enum_with_from_u8! {
134134
RETURNDATASIZE = 0x3d,
135135
#[doc = "copy return data buffer to memory"]
136136
RETURNDATACOPY = 0x3e,
137+
#[doc = "return the keccak256 hash of contract code"]
138+
EXTCODEHASH = 0x3f,
137139

138140
#[doc = "get hash of most recent complete block"]
139141
BLOCKHASH = 0x40,
@@ -492,6 +494,7 @@ lazy_static! {
492494
arr[CALLDATALOAD as usize] = Some(InstructionInfo::new("CALLDATALOAD", 1, 1, GasPriceTier::VeryLow));
493495
arr[CALLDATASIZE as usize] = Some(InstructionInfo::new("CALLDATASIZE", 0, 1, GasPriceTier::Base));
494496
arr[CALLDATACOPY as usize] = Some(InstructionInfo::new("CALLDATACOPY", 3, 0, GasPriceTier::VeryLow));
497+
arr[EXTCODEHASH as usize] = Some(InstructionInfo::new("EXTCODEHASH", 1, 1, GasPriceTier::Special));
495498
arr[CODESIZE as usize] = Some(InstructionInfo::new("CODESIZE", 0, 1, GasPriceTier::Base));
496499
arr[CODECOPY as usize] = Some(InstructionInfo::new("CODECOPY", 3, 0, GasPriceTier::VeryLow));
497500
arr[GASPRICE as usize] = Some(InstructionInfo::new("GASPRICE", 0, 1, GasPriceTier::Base));

ethcore/evm/src/interpreter/gasometer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
143143
instructions::EXTCODESIZE => {
144144
Request::Gas(Gas::from(schedule.extcodesize_gas))
145145
},
146+
instructions::EXTCODEHASH => {
147+
Request::Gas(Gas::from(schedule.extcodehash_gas))
148+
},
146149
instructions::SUICIDE => {
147150
let mut gas = Gas::from(schedule.suicide_gas);
148151

ethcore/evm/src/interpreter/mod.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,9 @@ impl<Cost: CostType> Interpreter<Cost> {
230230
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
231231
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
232232
(instruction == instructions::REVERT && !schedule.have_revert) ||
233-
((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) {
234-
233+
((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) ||
234+
(instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash)
235+
{
235236
return Err(vm::Error::BadInstruction {
236237
instruction: instruction as u8
237238
});
@@ -568,9 +569,14 @@ impl<Cost: CostType> Interpreter<Cost> {
568569
},
569570
instructions::EXTCODESIZE => {
570571
let address = u256_to_address(&stack.pop_back());
571-
let len = ext.extcodesize(&address)?;
572+
let len = ext.extcodesize(&address)?.unwrap_or(0);
572573
stack.push(U256::from(len));
573574
},
575+
instructions::EXTCODEHASH => {
576+
let address = u256_to_address(&stack.pop_back());
577+
let hash = ext.extcodehash(&address)?.unwrap_or_else(H256::zero);
578+
stack.push(U256::from(hash));
579+
},
574580
instructions::CALLDATACOPY => {
575581
Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
576582
},
@@ -591,7 +597,11 @@ impl<Cost: CostType> Interpreter<Cost> {
591597
instructions::EXTCODECOPY => {
592598
let address = u256_to_address(&stack.pop_back());
593599
let code = ext.extcode(&address)?;
594-
Self::copy_data_to_memory(&mut self.mem, stack, &code);
600+
Self::copy_data_to_memory(
601+
&mut self.mem,
602+
stack,
603+
code.as_ref().map(|c| &(*c)[..]).unwrap_or(&[])
604+
);
595605
},
596606
instructions::GASPRICE => {
597607
stack.push(params.gas_price.clone());

ethcore/src/client/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,7 @@ impl BlockInfo for Client {
13491349
}
13501350

13511351
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> {
1352-
self.state_at(id).and_then(|s| s.code_hash(address).ok())
1352+
self.state_at(id).and_then(|s| s.code_hash(address).unwrap_or(None))
13531353
}
13541354
}
13551355

ethcore/src/executive.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
320320
gas_price: t.gas_price,
321321
value: ActionValue::Transfer(t.value),
322322
code: self.state.code(address)?,
323-
code_hash: Some(self.state.code_hash(address)?),
323+
code_hash: self.state.code_hash(address)?,
324324
data: Some(t.data.clone()),
325325
call_type: CallType::Call,
326326
params_type: vm::ParamsType::Separate,

ethcore/src/externalities.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
163163
gas: self.machine.params().eip210_contract_gas,
164164
gas_price: 0.into(),
165165
code: code,
166-
code_hash: Some(code_hash),
166+
code_hash: code_hash,
167167
data: Some(H256::from(number).to_vec()),
168168
call_type: CallType::Call,
169169
params_type: vm::ParamsType::Separate,
@@ -270,7 +270,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
270270
gas: *gas,
271271
gas_price: self.origin_info.gas_price,
272272
code: code,
273-
code_hash: Some(code_hash),
273+
code_hash: code_hash,
274274
data: Some(data.to_vec()),
275275
call_type: call_type,
276276
params_type: vm::ParamsType::Separate,
@@ -289,12 +289,16 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
289289
}
290290
}
291291

292-
fn extcode(&self, address: &Address) -> vm::Result<Arc<Bytes>> {
293-
Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![])))
292+
fn extcode(&self, address: &Address) -> vm::Result<Option<Arc<Bytes>>> {
293+
Ok(self.state.code(address)?)
294+
}
295+
296+
fn extcodehash(&self, address: &Address) -> vm::Result<Option<H256>> {
297+
Ok(self.state.code_hash(address)?)
294298
}
295299

296-
fn extcodesize(&self, address: &Address) -> vm::Result<usize> {
297-
Ok(self.state.code_size(address)?.unwrap_or(0))
300+
fn extcodesize(&self, address: &Address) -> vm::Result<Option<usize>> {
301+
Ok(self.state.code_size(address)?)
298302
}
299303

300304
fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> vm::Result<U256>

ethcore/src/json_tests/executive.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,18 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
165165
MessageCallResult::Success(*gas, ReturnData::empty())
166166
}
167167

168-
fn extcode(&self, address: &Address) -> vm::Result<Arc<Bytes>> {
168+
fn extcode(&self, address: &Address) -> vm::Result<Option<Arc<Bytes>>> {
169169
self.ext.extcode(address)
170170
}
171171

172-
fn extcodesize(&self, address: &Address) -> vm::Result<usize> {
172+
fn extcodesize(&self, address: &Address) -> vm::Result<Option<usize>> {
173173
self.ext.extcodesize(address)
174174
}
175175

176+
fn extcodehash(&self, address: &Address) -> vm::Result<Option<H256>> {
177+
self.ext.extcodehash(address)
178+
}
179+
176180
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> vm::Result<()> {
177181
self.ext.log(topics, data)
178182
}

ethcore/src/machine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl EthereumMachine {
140140
gas_price: 0.into(),
141141
value: ActionValue::Transfer(0.into()),
142142
code: state.code(&contract_address)?,
143-
code_hash: Some(state.code_hash(&contract_address)?),
143+
code_hash: state.code_hash(&contract_address)?,
144144
data: data,
145145
call_type: CallType::Call,
146146
params_type: ParamsType::Separate,

ethcore/src/spec/spec.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ pub struct CommonParams {
115115
pub eip214_transition: BlockNumber,
116116
/// Number of first block where EIP-145 rules begin.
117117
pub eip145_transition: BlockNumber,
118+
/// Number of first block where EIP-1052 rules begin.
119+
pub eip1052_transition: BlockNumber,
118120
/// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin.
119121
pub dust_protection_transition: BlockNumber,
120122
/// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled.
@@ -174,6 +176,7 @@ impl CommonParams {
174176
schedule.have_static_call = block_number >= self.eip214_transition;
175177
schedule.have_return_data = block_number >= self.eip211_transition;
176178
schedule.have_bitwise_shifting = block_number >= self.eip145_transition;
179+
schedule.have_extcodehash = block_number >= self.eip1052_transition;
177180
if block_number >= self.eip210_transition {
178181
schedule.blockhash_gas = 800;
179182
}
@@ -270,6 +273,10 @@ impl From<ethjson::spec::Params> for CommonParams {
270273
BlockNumber::max_value,
271274
Into::into,
272275
),
276+
eip1052_transition: p.eip1052_transition.map_or_else(
277+
BlockNumber::max_value,
278+
Into::into,
279+
),
273280
dust_protection_transition: p.dust_protection_transition.map_or_else(
274281
BlockNumber::max_value,
275282
Into::into,

ethcore/src/state/account.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,12 +278,13 @@ impl Account {
278278
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == KECCAK_EMPTY)
279279
}
280280

281-
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code.
281+
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code. Returns the cached code, if successful.
282+
#[must_use]
282283
pub fn cache_code(&mut self, db: &HashDB<KeccakHasher>) -> Option<Arc<Bytes>> {
283284
// TODO: fill out self.code_cache;
284285
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
285286

286-
if self.is_cached() { return Some(self.code_cache.clone()) }
287+
if self.is_cached() { return Some(self.code_cache.clone()); }
287288

288289
match db.get(&self.code_hash) {
289290
Some(x) => {
@@ -298,16 +299,17 @@ impl Account {
298299
}
299300
}
300301

301-
/// Provide code to cache. For correctness, should be the correct code for the
302-
/// account.
302+
/// Provide code to cache. For correctness, should be the correct code for the account.
303303
pub fn cache_given_code(&mut self, code: Arc<Bytes>) {
304304
trace!("Account::cache_given_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
305305

306306
self.code_size = Some(code.len());
307307
self.code_cache = code;
308308
}
309309

310-
/// Provide a database to get `code_size`. Should not be called if it is a contract without code.
310+
/// Provide a database to get `code_size`. Should not be called if it is a contract without code. Returns whether
311+
/// the cache succeeds.
312+
#[must_use]
311313
pub fn cache_code_size(&mut self, db: &HashDB<KeccakHasher>) -> bool {
312314
// TODO: fill out self.code_cache;
313315
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
@@ -324,7 +326,9 @@ impl Account {
324326
},
325327
}
326328
} else {
327-
false
329+
// If the code hash is empty hash, then the code size is zero.
330+
self.code_size = Some(0);
331+
true
328332
}
329333
}
330334

0 commit comments

Comments
 (0)