Optimizing mem gas cost
This commit is contained in:
parent
edaf24a2ce
commit
f1edd3d683
@ -107,6 +107,11 @@ pub trait CostType: ops::Mul<Output=Self> + ops::Div<Output=Self> + ops::Add<Out
|
||||
fn overflow_add(self, other: Self) -> (Self, bool);
|
||||
/// Multiple with overflow
|
||||
fn overflow_mul(self, other: Self) -> (Self, bool);
|
||||
/// Divide with overflow
|
||||
fn overflow_div(self, other: Self) -> (Self, bool);
|
||||
/// Single-step full multiplication and division: `self*other/div`
|
||||
/// Should not overflow on intermediate steps
|
||||
fn overflow_mul_div(self, other: Self, div: Self) -> (Self, bool);
|
||||
}
|
||||
|
||||
impl CostType for U256 {
|
||||
@ -129,6 +134,21 @@ impl CostType for U256 {
|
||||
fn overflow_mul(self, other: Self) -> (Self, bool) {
|
||||
Uint::overflowing_mul(self, other)
|
||||
}
|
||||
|
||||
fn overflow_div(self, other: Self) -> (Self, bool) {
|
||||
Uint::overflowing_div(self, other)
|
||||
}
|
||||
|
||||
fn overflow_mul_div(self, other: Self, div: Self) -> (Self, bool) {
|
||||
let x = self.full_mul(other);
|
||||
let (U512(parts), o) = Uint::overflowing_div(x, U512::from(div));
|
||||
let overflow = (parts[4] | parts[5] | parts[6] | parts[7]) > 0;
|
||||
|
||||
(
|
||||
U256([parts[0], parts[1], parts[2], parts[3]]),
|
||||
o | overflow
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl CostType for usize {
|
||||
@ -154,6 +174,18 @@ impl CostType for usize {
|
||||
fn overflow_mul(self, other: Self) -> (Self, bool) {
|
||||
self.overflowing_mul(other)
|
||||
}
|
||||
|
||||
fn overflow_div(self, other: Self) -> (Self, bool) {
|
||||
self.overflowing_div(other)
|
||||
}
|
||||
|
||||
fn overflow_mul_div(self, other: Self, div: Self) -> (Self, bool) {
|
||||
let (c, o) = U128::from(self).overflowing_mul(U128::from(other));
|
||||
let (U128(parts), o1) = c.overflowing_div(U128::from(div));
|
||||
let result = parts[0] as usize;
|
||||
let overflow = o | o1 | (parts[1] > 0) | (parts[0] > result as u64);
|
||||
(result, overflow)
|
||||
}
|
||||
}
|
||||
|
||||
/// Evm interface
|
||||
@ -164,3 +196,41 @@ pub trait Evm {
|
||||
/// to compute the final gas left.
|
||||
fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result<GasLeft>;
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn should_calculate_overflow_mul_div_without_overflow() {
|
||||
// given
|
||||
let num = 10_000_000;
|
||||
|
||||
// when
|
||||
let (res1, o1) = U256::from(num).overflow_mul_div(U256::from(num), U256::from(num));
|
||||
let (res2, o2) = num.overflow_mul_div(num, num);
|
||||
|
||||
// then
|
||||
assert_eq!(res1, U256::from(num));
|
||||
assert!(!o1);
|
||||
assert_eq!(res2, num);
|
||||
assert!(!o2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_calculate_overflow_mul_div_with_overflow() {
|
||||
// given
|
||||
let max = ::std::u64::MAX;
|
||||
let num1 = U256([max, max, max, max]);
|
||||
let num2 = ::std::usize::MAX;
|
||||
|
||||
// when
|
||||
let (res1, o1) = num1.overflow_mul_div(num1, num1 - U256::from(2));
|
||||
let (res2, o2) = num2.overflow_mul_div(num2, num2 - 2);
|
||||
|
||||
// then
|
||||
// (x+2)^2/x = (x^2 + 4x + 4)/x = x + 4 + 4/x ~ (MAX-2) + 4 + 0 = 1
|
||||
assert_eq!(res2, 1);
|
||||
assert!(o2);
|
||||
|
||||
assert_eq!(res1, U256::from(1));
|
||||
assert!(o1);
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,9 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
let default_gas = Gas::from(schedule.tier_step_gas[tier]);
|
||||
|
||||
let cost = match instruction {
|
||||
instructions::JUMPDEST => {
|
||||
InstructionCost::Gas(Gas::from(1))
|
||||
},
|
||||
instructions::SSTORE => {
|
||||
let address = H256::from(stack.peek(0));
|
||||
let newval = stack.peek(1);
|
||||
@ -106,9 +109,6 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
instructions::EXTCODECOPY => {
|
||||
InstructionCost::GasMemCopy(default_gas, try!(self.mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3))))
|
||||
},
|
||||
instructions::JUMPDEST => {
|
||||
InstructionCost::Gas(Gas::from(1))
|
||||
},
|
||||
instructions::LOG0...instructions::LOG4 => {
|
||||
let no_of_topics = instructions::get_log_topics(instruction);
|
||||
let log_gas = schedule.log_gas + schedule.log_topic_gas * no_of_topics;
|
||||
@ -199,14 +199,12 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
let s = mem_size >> 5;
|
||||
// s * memory_gas + s * s / quad_coeff_div
|
||||
let a = overflowing!(s.overflow_mul(Gas::from(schedule.memory_gas)));
|
||||
// We need to go to U512 to calculate s*s/quad_coeff_div
|
||||
let b = U512::from(s.as_u256()) * U512::from(s.as_u256()) / U512::from(schedule.quad_coeff_div);
|
||||
if b > U512::from(!U256::zero()) {
|
||||
Err(evm::Error::OutOfGas)
|
||||
} else {
|
||||
Ok(overflowing!(a.overflow_add(try!(Gas::from_u256(U256::from(b))))))
|
||||
}
|
||||
|
||||
// Calculate s*s/quad_coeff_div
|
||||
let b = overflowing!(s.overflow_mul_div(s, Gas::from(schedule.quad_coeff_div)));
|
||||
Ok(overflowing!(a.overflow_add(b)))
|
||||
};
|
||||
|
||||
let current_mem_size = Gas::from(current_mem_size);
|
||||
let req_mem_size_rounded = (overflowing!(mem_size.overflow_add(Gas::from(31 as usize))) >> 5) << 5;
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
//! Parity EVM interpreter binary.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
extern crate ethcore;
|
||||
extern crate rustc_serialize;
|
||||
extern crate docopt;
|
||||
|
Loading…
Reference in New Issue
Block a user