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

Commit db3a989

Browse files
andresilva5chdn
authored andcommitted
[stable] Backport constantinople changes (#9723)
* ethash: implement EIP-1234 (#9187) * 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 * Comply EIP-86 with the new definition (#9140) * Comply EIP-86 with the new CREATE2 opcode * Fix rpc compile * Fix interpreter CREATE/CREATE2 stack pop difference * Add unreachable! to fix compile * Fix instruction_info * Fix gas check due to new stack item * Add new tests in executive * Fix have_create2 comment * Remove all unused references of eip86_transition and block_number * Implement KIP4: create2 for wasm (#9277) * Basic implementation for kip4 * Add KIP-4 config flags * typo: docs fix * Fix args offset * Add tests for create2 * tests: evm * Update wasm-tests and fix all gas costs * Update wasm-tests * Update wasm-tests and fix gas costs * `gasleft` extern implemented for WASM runtime (kip-6) (#9357) * Wasm gasleft extern added * wasm_gasleft_activation_transition -> kip4_transition * use kip-6 switch * gasleft_panic -> gasleft_fail rename * call_msg_gasleft test added and gas_left agustments because this openethereum/wasm-tests#52 * change .. to _ * fix comment for the have_gasleft param * update tests (openethereum/wasm-tests@0edbf86) * Add EIP-1014 transition config flag (#9268) * Add EIP-1014 transition config flag * Remove EIP-86 configs * Change CREATE2 opcode index to 0xf5 * Move salt to the last item in the stack * Change sendersaltandaddress scheme to comply with current EIP-1014 * Fix json configs * Fix create2 test * Fix deprecated comments * EIP 1283: Net gas metering for SSTORE without dirty maps (#9319) * Implement last_checkpoint_storage_at * Add reverted_storage_at for externalities * sstore_clears_count -> sstore_clears_refund * Implement eip1283 for evm * Add eip1283Transition params * evm: fix tests * jsontests: fix test * Return checkpoint index when creating * Comply with spec Version II * Fix docs * Fix jsontests feature compile * Address grumbles * Fix no-checkpoint-entry case * Remove unnecessary expect * Add test for State::checkpoint_storage_at * Add executive level test for eip1283 * Hard-code transaction_checkpoint_index to 0 * Fix jsontests * Add tests for checkpoint discard/revert * Require checkpoint to be empty for kill_account and commit * Get code coverage * Use saturating_add/saturating_sub * Fix issues in insert_cache * Clear the state again * Fix original_storage_at * Early return for empty RLP trie storage * Update comments * Fix borrow_mut issue * Simplify checkpoint_storage_at if branches * Better commenting for gas handling code * Address naming grumbles * More tests * Fix an issue in overwrite_with * Add another test * Fix comment * Remove unnecessary bracket * Move orig to inner if * Remove test coverage for this PR * Add tests for executive original value * Add warn! for an unreachable cause * Update state tests execution model (#9440) * Update & fix JSON state tests. * Update tests to be able to run ethtest at 021fe3d410773024cd5f0387e62db6e6ec800f32. - Touch user in state - Adjust transaction tests to new json format * Switch to same commit for submodule ethereum/test as geth (next includes constantinople changes). Added test `json_tests::trie::generic::TrieTests_trieanyorder` and a few difficulty tests. * Remove trietestnextprev as it would require to parse differently and implement it. * Support new (shitty) format of transaction tests. * Ignore junk in ethereum/tests repo. * Ignore incorrect test. * Update to a later commit * Move block number to a constant. * Fix ZK2 test - touched account should also be cleared. * Fix conflict resolution * Fix checkpointing when creating contract failed (#9514) * In create memory calculation is the same for create2 because the additional parameter was popped before. (#9522) * Enable all Constantinople hard fork changes in constantinople_test.json (#9505) * Enable all Constantinople hard fork changes in constantinople_test.json * Address grumbles * Remove EIP-210 activation * 8m -> 5m * Temporarily add back eip210 transition so we can get test passed * Add eip210_test and remove eip210 transition from const_test * Add constantinople conf to EvmTestClient. (#9570) * Add constantinople conf to EvmTestClient. * Skip some test to update submodule etheureum/tests submodule to latest. * Put skipping 'under issue' test behind a feature. * Change blockReward for const-test to pass ethereum/tests * Update tests to new constantinple definition (change of reward at block 5). Switch 'reference' to string, that way we can include issues from others repo (more flexible)Update tests to new constantinple definition (change of reward at block 5). Switch 'reference' to string, that way we can include issues from others repo (more flexible). * Fix modexp and bn128_mul gas prices in chain config * Changes `run_test_path` method to append its directory results (without that it stop testing at the first file failure). Add some missing tests. Add skip for those (block create2 is one hundred percent false but on hive we can see that geth and aleth got similar issue for this item). * retab current.json * Update reference to parity issue for failing tests. * Hardfork the testnets (#9562) * ethcore: propose hardfork block number 4230000 for ropsten * ethcore: propose hardfork block number 9000000 for kovan * ethcore: enable kip-4 and kip-6 on kovan * etcore: bump kovan hardfork to block 9.2M * ethcore: fix ropsten constantinople block number to 4.2M * ethcore: disable difficulty_test_ropsten until ethereum/tests are updated upstream * Don't hash the init_code of CREATE. (#9688) * Implement CREATE2 gas changes and fix some potential overflowing (#9694) * Implement CREATE2 gas changes and fix some potential overflowing * Ignore create2 state tests * Split CREATE and CREATE2 in gasometer * Generalize rounding (x + 31) / 32 to to_word_size * ethcore: delay ropsten hardfork (#9704) * Add hardcoded headers (#9730) * add foundation hardcoded header #6486017 * add ropsten hardcoded headers #4202497 * add kovan hardcoded headers #9023489 * gitlab ci: releasable_branches: change variables condition to schedule (#9729) * HF in POA Core (2018-10-22) (#9724) poanetwork/poa-chain-spec#87
1 parent 93b25d5 commit db3a989

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2692
-479
lines changed

.gitlab-ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ cache:
2424
- stable
2525
- beta
2626
- tags
27+
- schedules
2728

2829
.collect_artifacts: &collect_artifacts
2930
artifacts:

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ daemonize = { git = "https://github.com/paritytech/daemonize" }
8989
[features]
9090
miner-debug = ["ethcore/miner-debug"]
9191
json-tests = ["ethcore/json-tests"]
92+
ci-skip-issue = ["ethcore/ci-skip-issue"]
9293
test-heavy = ["ethcore/test-heavy"]
9394
evm-debug = ["ethcore/evm-debug"]
9495
evm-debug-tests = ["ethcore/evm-debug-tests"]

ethcore/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"]
102102
slow-blocks = []
103103
# Run JSON consensus tests.
104104
json-tests = ["ethcore-transaction/json-tests", "test-helpers", "tempdir"]
105+
# Skip JSON consensus tests with pending issues.
106+
ci-skip-issue = []
105107
# Run memory/cpu heavy tests.
106108
test-heavy = []
107109
# Compile benches

ethcore/evm/src/evm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl Finalize for Result<GasLeft> {
5757

5858
/// Cost calculation type. For low-gas usage we calculate costs using usize instead of U256
5959
pub trait CostType: Sized + From<usize> + Copy
60-
+ ops::Mul<Output=Self> + ops::Div<Output=Self> + ops::Add<Output=Self> +ops::Sub<Output=Self>
60+
+ ops::Mul<Output=Self> + ops::Div<Output=Self> + ops::Add<Output=Self> + ops::Sub<Output=Self>
6161
+ ops::Shr<usize, Output=Self> + ops::Shl<usize, Output=Self>
6262
+ cmp::Ord + fmt::Debug {
6363
/// Converts this cost into `U256`

ethcore/evm/src/instructions.rs

Lines changed: 5 additions & 2 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,
@@ -326,7 +328,7 @@ enum_with_from_u8! {
326328
#[doc = "like CALLCODE but keeps caller's value and sender"]
327329
DELEGATECALL = 0xf4,
328330
#[doc = "create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160"]
329-
CREATE2 = 0xfb,
331+
CREATE2 = 0xf5,
330332
#[doc = "stop execution and revert state changes. Return output data."]
331333
REVERT = 0xfd,
332334
#[doc = "like CALL but it does not take value, nor modify the state"]
@@ -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));
@@ -591,7 +594,7 @@ lazy_static! {
591594
arr[DELEGATECALL as usize] = Some(InstructionInfo::new("DELEGATECALL", 6, 1, GasPriceTier::Special));
592595
arr[STATICCALL as usize] = Some(InstructionInfo::new("STATICCALL", 6, 1, GasPriceTier::Special));
593596
arr[SUICIDE as usize] = Some(InstructionInfo::new("SUICIDE", 1, 0, GasPriceTier::Special));
594-
arr[CREATE2 as usize] = Some(InstructionInfo::new("CREATE2", 3, 1, GasPriceTier::Special));
597+
arr[CREATE2 as usize] = Some(InstructionInfo::new("CREATE2", 4, 1, GasPriceTier::Special));
595598
arr[REVERT as usize] = Some(InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero));
596599
arr
597600
};

ethcore/evm/src/interpreter/gasometer.rs

Lines changed: 128 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,17 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
125125
let newval = stack.peek(1);
126126
let val = U256::from(&*ext.storage_at(&address)?);
127127

128-
let gas = if val.is_zero() && !newval.is_zero() {
129-
schedule.sstore_set_gas
128+
let gas = if schedule.eip1283 {
129+
let orig = U256::from(&*ext.initial_storage_at(&address)?);
130+
calculate_eip1283_sstore_gas(schedule, &orig, &val, &newval)
130131
} else {
131-
// Refund for below case is added when actually executing sstore
132-
// !is_zero(&val) && is_zero(newval)
133-
schedule.sstore_reset_gas
132+
if val.is_zero() && !newval.is_zero() {
133+
schedule.sstore_set_gas
134+
} else {
135+
// Refund for below case is added when actually executing sstore
136+
// !is_zero(&val) && is_zero(newval)
137+
schedule.sstore_reset_gas
138+
}
134139
};
135140
Request::Gas(Gas::from(gas))
136141
},
@@ -143,6 +148,9 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
143148
instructions::EXTCODESIZE => {
144149
Request::Gas(Gas::from(schedule.extcodesize_gas))
145150
},
151+
instructions::EXTCODEHASH => {
152+
Request::Gas(Gas::from(schedule.extcodehash_gas))
153+
},
146154
instructions::SUICIDE => {
147155
let mut gas = Gas::from(schedule.suicide_gas);
148156

@@ -168,9 +176,8 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
168176
Request::GasMem(default_gas, mem_needed(stack.peek(0), stack.peek(1))?)
169177
},
170178
instructions::SHA3 => {
171-
let w = overflowing!(add_gas_usize(Gas::from_u256(*stack.peek(1))?, 31));
172-
let words = w >> 5;
173-
let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words);
179+
let words = overflowing!(to_word_size(Gas::from_u256(*stack.peek(1))?));
180+
let gas = overflowing!(Gas::from(schedule.sha3_gas).overflow_add(overflowing!(Gas::from(schedule.sha3_word_gas).overflow_mul(words))));
174181
Request::GasMem(gas, mem_needed(stack.peek(0), stack.peek(1))?)
175182
},
176183
instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => {
@@ -223,9 +230,24 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
223230

224231
Request::GasMemProvide(gas, mem, Some(requested))
225232
},
226-
instructions::CREATE | instructions::CREATE2 => {
233+
instructions::CREATE => {
234+
let start = stack.peek(1);
235+
let len = stack.peek(2);
236+
227237
let gas = Gas::from(schedule.create_gas);
228-
let mem = mem_needed(stack.peek(1), stack.peek(2))?;
238+
let mem = mem_needed(start, len)?;
239+
240+
Request::GasMemProvide(gas, mem, None)
241+
},
242+
instructions::CREATE2 => {
243+
let start = stack.peek(1);
244+
let len = stack.peek(2);
245+
246+
let base = Gas::from(schedule.create_gas);
247+
let word = overflowing!(to_word_size(Gas::from_u256(*len)?));
248+
let word_gas = overflowing!(Gas::from(schedule.sha3_word_gas).overflow_mul(word));
249+
let gas = overflowing!(base.overflow_add(word_gas));
250+
let mem = mem_needed(start, len)?;
229251

230252
Request::GasMemProvide(gas, mem, None)
231253
},
@@ -275,8 +297,8 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
275297
},
276298
Request::GasMemCopy(gas, mem_size, copy) => {
277299
let (mem_gas_cost, new_mem_gas, new_mem_size) = self.mem_gas_cost(schedule, current_mem_size, &mem_size)?;
278-
let copy = overflowing!(add_gas_usize(copy, 31)) >> 5;
279-
let copy_gas = Gas::from(schedule.copy_gas) * copy;
300+
let copy = overflowing!(to_word_size(copy));
301+
let copy_gas = overflowing!(Gas::from(schedule.copy_gas).overflow_mul(copy));
280302
let gas = overflowing!(gas.overflow_add(copy_gas));
281303
let gas = overflowing!(gas.overflow_add(mem_gas_cost));
282304

@@ -303,7 +325,7 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
303325
};
304326

305327
let current_mem_size = Gas::from(current_mem_size);
306-
let req_mem_size_rounded = (overflowing!(mem_size.overflow_add(Gas::from(31 as usize))) >> 5) << 5;
328+
let req_mem_size_rounded = overflowing!(to_word_size(*mem_size)) << 5;
307329

308330
let (mem_gas_cost, new_mem_gas) = if req_mem_size_rounded > current_mem_size {
309331
let new_mem_gas = gas_for_mem(req_mem_size_rounded)?;
@@ -335,6 +357,99 @@ fn add_gas_usize<Gas: evm::CostType>(value: Gas, num: usize) -> (Gas, bool) {
335357
value.overflow_add(Gas::from(num))
336358
}
337359

360+
#[inline]
361+
fn to_word_size<Gas: evm::CostType>(value: Gas) -> (Gas, bool) {
362+
let (gas, overflow) = add_gas_usize(value, 31);
363+
if overflow {
364+
return (gas, overflow);
365+
}
366+
367+
(gas >> 5, false)
368+
}
369+
370+
#[inline]
371+
fn calculate_eip1283_sstore_gas<Gas: evm::CostType>(schedule: &Schedule, original: &U256, current: &U256, new: &U256) -> Gas {
372+
Gas::from(
373+
if current == new {
374+
// 1. If current value equals new value (this is a no-op), 200 gas is deducted.
375+
schedule.sload_gas
376+
} else {
377+
// 2. If current value does not equal new value
378+
if original == current {
379+
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context)
380+
if original.is_zero() {
381+
// 2.1.1. If original value is 0, 20000 gas is deducted.
382+
schedule.sstore_set_gas
383+
} else {
384+
// 2.1.2. Otherwise, 5000 gas is deducted.
385+
schedule.sstore_reset_gas
386+
387+
// 2.1.2.1. If new value is 0, add 15000 gas to refund counter.
388+
}
389+
} else {
390+
// 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses.
391+
schedule.sload_gas
392+
393+
// 2.2.1. If original value is not 0
394+
// 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0.
395+
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter.
396+
397+
// 2.2.2. If original value equals new value (this storage slot is reset)
398+
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
399+
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
400+
}
401+
}
402+
)
403+
}
404+
405+
pub fn handle_eip1283_sstore_clears_refund(ext: &mut vm::Ext, original: &U256, current: &U256, new: &U256) {
406+
let sstore_clears_schedule = U256::from(ext.schedule().sstore_refund_gas);
407+
408+
if current == new {
409+
// 1. If current value equals new value (this is a no-op), 200 gas is deducted.
410+
} else {
411+
// 2. If current value does not equal new value
412+
if original == current {
413+
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context)
414+
if original.is_zero() {
415+
// 2.1.1. If original value is 0, 20000 gas is deducted.
416+
} else {
417+
// 2.1.2. Otherwise, 5000 gas is deducted.
418+
if new.is_zero() {
419+
// 2.1.2.1. If new value is 0, add 15000 gas to refund counter.
420+
ext.add_sstore_refund(sstore_clears_schedule);
421+
}
422+
}
423+
} else {
424+
// 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses.
425+
426+
if !original.is_zero() {
427+
// 2.2.1. If original value is not 0
428+
if current.is_zero() {
429+
// 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0.
430+
ext.sub_sstore_refund(sstore_clears_schedule);
431+
} else if new.is_zero() {
432+
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter.
433+
ext.add_sstore_refund(sstore_clears_schedule);
434+
}
435+
}
436+
437+
if original == new {
438+
// 2.2.2. If original value equals new value (this storage slot is reset)
439+
if original.is_zero() {
440+
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
441+
let refund = U256::from(ext.schedule().sstore_set_gas - ext.schedule().sload_gas);
442+
ext.add_sstore_refund(refund);
443+
} else {
444+
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
445+
let refund = U256::from(ext.schedule().sstore_reset_gas - ext.schedule().sload_gas);
446+
ext.add_sstore_refund(refund);
447+
}
448+
}
449+
}
450+
}
451+
}
452+
338453
#[test]
339454
fn test_mem_gas_cost() {
340455
// given

ethcore/evm/src/interpreter/mod.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,7 @@ impl<Cost: CostType> vm::Vm for Interpreter<Cost> {
186186
match result {
187187
InstructionResult::JumpToPosition(position) => {
188188
if valid_jump_destinations.is_none() {
189-
let code_hash = params.code_hash.clone().unwrap_or_else(|| keccak(code.as_ref()));
190-
valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, code));
189+
valid_jump_destinations = Some(self.cache.jump_destinations(&params.code_hash, code));
191190
}
192191
let jump_destinations = valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed");
193192
let pos = self.verify_jump(position, jump_destinations)?;
@@ -230,8 +229,9 @@ impl<Cost: CostType> Interpreter<Cost> {
230229
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
231230
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
232231
(instruction == instructions::REVERT && !schedule.have_revert) ||
233-
((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) {
234-
232+
((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) ||
233+
(instruction == instructions::EXTCODEHASH && !schedule.have_extcodehash)
234+
{
235235
return Err(vm::Error::BadInstruction {
236236
instruction: instruction as u8
237237
});
@@ -318,6 +318,11 @@ impl<Cost: CostType> Interpreter<Cost> {
318318
let endowment = stack.pop_back();
319319
let init_off = stack.pop_back();
320320
let init_size = stack.pop_back();
321+
let address_scheme = match instruction {
322+
instructions::CREATE => CreateContractAddress::FromSenderAndNonce,
323+
instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(stack.pop_back().into()),
324+
_ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"),
325+
};
321326

322327
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");
323328

@@ -335,7 +340,6 @@ impl<Cost: CostType> Interpreter<Cost> {
335340
}
336341

337342
let contract_code = self.mem.read_slice(init_off, init_size);
338-
let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };
339343

340344
let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme);
341345
return match create_result {
@@ -510,8 +514,14 @@ impl<Cost: CostType> Interpreter<Cost> {
510514

511515
let current_val = U256::from(&*ext.storage_at(&address)?);
512516
// Increase refund for clear
513-
if !self.is_zero(&current_val) && self.is_zero(&val) {
514-
ext.inc_sstore_clears();
517+
if ext.schedule().eip1283 {
518+
let original_val = U256::from(&*ext.initial_storage_at(&address)?);
519+
gasometer::handle_eip1283_sstore_clears_refund(ext, &original_val, &current_val, &val);
520+
} else {
521+
if !current_val.is_zero() && val.is_zero() {
522+
let sstore_clears_schedule = U256::from(ext.schedule().sstore_refund_gas);
523+
ext.add_sstore_refund(sstore_clears_schedule);
524+
}
515525
}
516526
ext.set_storage(address, H256::from(&val))?;
517527
},
@@ -568,9 +578,14 @@ impl<Cost: CostType> Interpreter<Cost> {
568578
},
569579
instructions::EXTCODESIZE => {
570580
let address = u256_to_address(&stack.pop_back());
571-
let len = ext.extcodesize(&address)?;
581+
let len = ext.extcodesize(&address)?.unwrap_or(0);
572582
stack.push(U256::from(len));
573583
},
584+
instructions::EXTCODEHASH => {
585+
let address = u256_to_address(&stack.pop_back());
586+
let hash = ext.extcodehash(&address)?.unwrap_or_else(H256::zero);
587+
stack.push(U256::from(hash));
588+
},
574589
instructions::CALLDATACOPY => {
575590
Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
576591
},
@@ -591,7 +606,11 @@ impl<Cost: CostType> Interpreter<Cost> {
591606
instructions::EXTCODECOPY => {
592607
let address = u256_to_address(&stack.pop_back());
593608
let code = ext.extcode(&address)?;
594-
Self::copy_data_to_memory(&mut self.mem, stack, &code);
609+
Self::copy_data_to_memory(
610+
&mut self.mem,
611+
stack,
612+
code.as_ref().map(|c| &(*c)[..]).unwrap_or(&[])
613+
);
595614
},
596615
instructions::GASPRICE => {
597616
stack.push(params.gas_price.clone());

ethcore/evm/src/interpreter/shared_cache.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,22 @@ impl SharedCache {
5050
}
5151

5252
/// Get jump destinations bitmap for a contract.
53-
pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc<BitSet> {
54-
if code_hash == &KECCAK_EMPTY {
55-
return Self::find_jump_destinations(code);
56-
}
53+
pub fn jump_destinations(&self, code_hash: &Option<H256>, code: &[u8]) -> Arc<BitSet> {
54+
if let Some(ref code_hash) = code_hash {
55+
if code_hash == &KECCAK_EMPTY {
56+
return Self::find_jump_destinations(code);
57+
}
5758

58-
if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
59-
return d.0.clone();
59+
if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) {
60+
return d.0.clone();
61+
}
6062
}
6163

6264
let d = Self::find_jump_destinations(code);
63-
self.jump_destinations.lock().insert(code_hash.clone(), Bits(d.clone()));
65+
66+
if let Some(ref code_hash) = code_hash {
67+
self.jump_destinations.lock().insert(*code_hash, Bits(d.clone()));
68+
}
6469

6570
d
6671
}

0 commit comments

Comments
 (0)