Use signed 256-bit integer for sstore gas refund substate (#9746)

* Add signed refund

* Use signed 256-bit integer for sstore gas refund substate

* Fix tests

* Remove signed mod and use i128 directly

* Fix evm test case casting

* Fix jsontests ext signature
This commit is contained in:
Wei Tang 2018-10-15 17:09:55 +08:00 committed by GitHub
parent 702311b6b2
commit 5319d33bc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 26 additions and 25 deletions

View File

@ -403,7 +403,7 @@ fn calculate_eip1283_sstore_gas<Gas: evm::CostType>(schedule: &Schedule, origina
} }
pub fn handle_eip1283_sstore_clears_refund(ext: &mut vm::Ext, original: &U256, current: &U256, new: &U256) { pub fn handle_eip1283_sstore_clears_refund(ext: &mut vm::Ext, original: &U256, current: &U256, new: &U256) {
let sstore_clears_schedule = U256::from(ext.schedule().sstore_refund_gas); let sstore_clears_schedule = ext.schedule().sstore_refund_gas;
if current == new { if current == new {
// 1. If current value equals new value (this is a no-op), 200 gas is deducted. // 1. If current value equals new value (this is a no-op), 200 gas is deducted.
@ -438,11 +438,11 @@ pub fn handle_eip1283_sstore_clears_refund(ext: &mut vm::Ext, original: &U256, c
// 2.2.2. If original value equals new value (this storage slot is reset) // 2.2.2. If original value equals new value (this storage slot is reset)
if original.is_zero() { if original.is_zero() {
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter. // 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
let refund = U256::from(ext.schedule().sstore_set_gas - ext.schedule().sload_gas); let refund = ext.schedule().sstore_set_gas - ext.schedule().sload_gas;
ext.add_sstore_refund(refund); ext.add_sstore_refund(refund);
} else { } else {
// 2.2.2.2. Otherwise, add 4800 gas to refund counter. // 2.2.2.2. Otherwise, add 4800 gas to refund counter.
let refund = U256::from(ext.schedule().sstore_reset_gas - ext.schedule().sload_gas); let refund = ext.schedule().sstore_reset_gas - ext.schedule().sload_gas;
ext.add_sstore_refund(refund); ext.add_sstore_refund(refund);
} }
} }

View File

@ -720,7 +720,7 @@ impl<Cost: CostType> Interpreter<Cost> {
gasometer::handle_eip1283_sstore_clears_refund(ext, &original_val, &current_val, &val); gasometer::handle_eip1283_sstore_clears_refund(ext, &original_val, &current_val, &val);
} else { } else {
if !current_val.is_zero() && val.is_zero() { if !current_val.is_zero() && val.is_zero() {
let sstore_clears_schedule = U256::from(ext.schedule().sstore_refund_gas); let sstore_clears_schedule = ext.schedule().sstore_refund_gas;
ext.add_sstore_refund(sstore_clears_schedule); ext.add_sstore_refund(sstore_clears_schedule);
} }
} }

View File

@ -716,7 +716,7 @@ fn test_jumps(factory: super::Factory) {
test_finalize(vm.exec(&mut ext).ok().unwrap()).unwrap() test_finalize(vm.exec(&mut ext).ok().unwrap()).unwrap()
}; };
assert_eq!(ext.sstore_clears, U256::from(ext.schedule().sstore_refund_gas)); assert_eq!(ext.sstore_clears, ext.schedule().sstore_refund_gas as i128);
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); // 5! assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); // 5!
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000078"); // 5! assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000078"); // 5!
assert_eq!(gas_left, U256::from(54_117)); assert_eq!(gas_left, U256::from(54_117));

View File

@ -1091,7 +1091,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let schedule = self.schedule; let schedule = self.schedule;
// refunds from SSTORE nonzero -> zero // refunds from SSTORE nonzero -> zero
let sstore_refunds = substate.sstore_clears_refund; assert!(substate.sstore_clears_refund >= 0, "On transaction level, sstore clears refund cannot go below zero.");
let sstore_refunds = U256::from(substate.sstore_clears_refund as u64);
// refunds from contract suicides // refunds from contract suicides
let suicide_refunds = U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len()); let suicide_refunds = U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len());
let refunds_bound = sstore_refunds + suicide_refunds; let refunds_bound = sstore_refunds + suicide_refunds;
@ -2095,7 +2096,7 @@ mod tests {
let gas_used = gas - gas_left; let gas_used = gas - gas_left;
// sstore: 0 -> (1) -> () -> (1 -> 0 -> 1) // sstore: 0 -> (1) -> () -> (1 -> 0 -> 1)
assert_eq!(gas_used, U256::from(41860)); assert_eq!(gas_used, U256::from(41860));
assert_eq!(refund, U256::from(19800)); assert_eq!(refund, 19800);
assert_eq!(state.storage_at(&operating_address, &k).unwrap(), H256::from(U256::from(1))); assert_eq!(state.storage_at(&operating_address, &k).unwrap(), H256::from(U256::from(1)));
// Test a call via top-level -> y2 -> x2 // Test a call via top-level -> y2 -> x2
@ -2113,7 +2114,7 @@ mod tests {
let gas_used = gas - gas_left; let gas_used = gas - gas_left;
// sstore: 1 -> (1) -> () -> (0 -> 1 -> 0) // sstore: 1 -> (1) -> () -> (0 -> 1 -> 0)
assert_eq!(gas_used, U256::from(11860)); assert_eq!(gas_used, U256::from(11860));
assert_eq!(refund, U256::from(19800)); assert_eq!(refund, 19800);
} }
fn wasm_sample_code() -> Arc<Vec<u8>> { fn wasm_sample_code() -> Arc<Vec<u8>> {

View File

@ -394,12 +394,12 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
self.depth self.depth
} }
fn add_sstore_refund(&mut self, value: U256) { fn add_sstore_refund(&mut self, value: usize) {
self.substate.sstore_clears_refund = self.substate.sstore_clears_refund.saturating_add(value); self.substate.sstore_clears_refund += value as i128;
} }
fn sub_sstore_refund(&mut self, value: U256) { fn sub_sstore_refund(&mut self, value: usize) {
self.substate.sstore_clears_refund = self.substate.sstore_clears_refund.saturating_sub(value); self.substate.sstore_clears_refund -= value as i128;
} }
fn trace_next_instruction(&mut self, pc: usize, instruction: u8, current_gas: U256) -> bool { fn trace_next_instruction(&mut self, pc: usize, instruction: u8, current_gas: U256) -> bool {

View File

@ -218,11 +218,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
false false
} }
fn add_sstore_refund(&mut self, value: U256) { fn add_sstore_refund(&mut self, value: usize) {
self.ext.add_sstore_refund(value) self.ext.add_sstore_refund(value)
} }
fn sub_sstore_refund(&mut self, value: U256) { fn sub_sstore_refund(&mut self, value: usize) {
self.ext.sub_sstore_refund(value) self.ext.sub_sstore_refund(value)
} }
} }

View File

@ -16,7 +16,7 @@
//! Execution environment substate. //! Execution environment substate.
use std::collections::HashSet; use std::collections::HashSet;
use ethereum_types::{U256, Address}; use ethereum_types::Address;
use log_entry::LogEntry; use log_entry::LogEntry;
use evm::{Schedule, CleanDustMode}; use evm::{Schedule, CleanDustMode};
use super::CleanupMode; use super::CleanupMode;
@ -35,7 +35,7 @@ pub struct Substate {
pub logs: Vec<LogEntry>, pub logs: Vec<LogEntry>,
/// Refund counter of SSTORE. /// Refund counter of SSTORE.
pub sstore_clears_refund: U256, pub sstore_clears_refund: i128,
/// Created contracts. /// Created contracts.
pub contracts_created: Vec<Address>, pub contracts_created: Vec<Address>,
@ -52,7 +52,7 @@ impl Substate {
self.suicides.extend(s.suicides); self.suicides.extend(s.suicides);
self.touched.extend(s.touched); self.touched.extend(s.touched);
self.logs.extend(s.logs); self.logs.extend(s.logs);
self.sstore_clears_refund = self.sstore_clears_refund + s.sstore_clears_refund; self.sstore_clears_refund += s.sstore_clears_refund;
self.contracts_created.extend(s.contracts_created); self.contracts_created.extend(s.contracts_created);
} }

View File

@ -151,10 +151,10 @@ pub trait Ext {
fn depth(&self) -> usize; fn depth(&self) -> usize;
/// Increments sstore refunds counter. /// Increments sstore refunds counter.
fn add_sstore_refund(&mut self, value: U256); fn add_sstore_refund(&mut self, value: usize);
/// Decrements sstore refunds counter. /// Decrements sstore refunds counter.
fn sub_sstore_refund(&mut self, value: U256); fn sub_sstore_refund(&mut self, value: usize);
/// Decide if any more operations should be traced. Passthrough for the VM trace. /// Decide if any more operations should be traced. Passthrough for the VM trace.
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _current_gas: U256) -> bool { false } fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _current_gas: U256) -> bool { false }

View File

@ -57,7 +57,7 @@ pub struct FakeExt {
pub store: HashMap<H256, H256>, pub store: HashMap<H256, H256>,
pub suicides: HashSet<Address>, pub suicides: HashSet<Address>,
pub calls: HashSet<FakeCall>, pub calls: HashSet<FakeCall>,
pub sstore_clears: U256, pub sstore_clears: i128,
pub depth: usize, pub depth: usize,
pub blockhashes: HashMap<U256, H256>, pub blockhashes: HashMap<U256, H256>,
pub codes: HashMap<Address, Arc<Bytes>>, pub codes: HashMap<Address, Arc<Bytes>>,
@ -231,12 +231,12 @@ impl Ext for FakeExt {
self.is_static self.is_static
} }
fn add_sstore_refund(&mut self, value: U256) { fn add_sstore_refund(&mut self, value: usize) {
self.sstore_clears = self.sstore_clears + value; self.sstore_clears += value as i128;
} }
fn sub_sstore_refund(&mut self, value: U256) { fn sub_sstore_refund(&mut self, value: usize) {
self.sstore_clears = self.sstore_clears - value; self.sstore_clears -= value as i128;
} }
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _gas: U256) -> bool { fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _gas: U256) -> bool {

View File

@ -285,7 +285,7 @@ impl<'a> Runtime<'a> {
self.ext.set_storage(key, val).map_err(|_| Error::StorageUpdateError)?; self.ext.set_storage(key, val).map_err(|_| Error::StorageUpdateError)?;
if former_val != H256::zero() && val == H256::zero() { if former_val != H256::zero() && val == H256::zero() {
let sstore_clears_schedule = U256::from(self.schedule().sstore_refund_gas); let sstore_clears_schedule = self.schedule().sstore_refund_gas;
self.ext.add_sstore_refund(sstore_clears_schedule); self.ext.add_sstore_refund(sstore_clears_schedule);
} }