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);
|
fn overflow_add(self, other: Self) -> (Self, bool);
|
||||||
/// Multiple with overflow
|
/// Multiple with overflow
|
||||||
fn overflow_mul(self, other: Self) -> (Self, bool);
|
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 {
|
impl CostType for U256 {
|
||||||
@ -129,6 +134,21 @@ impl CostType for U256 {
|
|||||||
fn overflow_mul(self, other: Self) -> (Self, bool) {
|
fn overflow_mul(self, other: Self) -> (Self, bool) {
|
||||||
Uint::overflowing_mul(self, other)
|
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 {
|
impl CostType for usize {
|
||||||
@ -154,6 +174,18 @@ impl CostType for usize {
|
|||||||
fn overflow_mul(self, other: Self) -> (Self, bool) {
|
fn overflow_mul(self, other: Self) -> (Self, bool) {
|
||||||
self.overflowing_mul(other)
|
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
|
/// Evm interface
|
||||||
@ -164,3 +196,41 @@ pub trait Evm {
|
|||||||
/// to compute the final gas left.
|
/// to compute the final gas left.
|
||||||
fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result<GasLeft>;
|
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 default_gas = Gas::from(schedule.tier_step_gas[tier]);
|
||||||
|
|
||||||
let cost = match instruction {
|
let cost = match instruction {
|
||||||
|
instructions::JUMPDEST => {
|
||||||
|
InstructionCost::Gas(Gas::from(1))
|
||||||
|
},
|
||||||
instructions::SSTORE => {
|
instructions::SSTORE => {
|
||||||
let address = H256::from(stack.peek(0));
|
let address = H256::from(stack.peek(0));
|
||||||
let newval = stack.peek(1);
|
let newval = stack.peek(1);
|
||||||
@ -106,9 +109,6 @@ impl<Gas: CostType> Gasometer<Gas> {
|
|||||||
instructions::EXTCODECOPY => {
|
instructions::EXTCODECOPY => {
|
||||||
InstructionCost::GasMemCopy(default_gas, try!(self.mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3))))
|
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 => {
|
instructions::LOG0...instructions::LOG4 => {
|
||||||
let no_of_topics = instructions::get_log_topics(instruction);
|
let no_of_topics = instructions::get_log_topics(instruction);
|
||||||
let log_gas = schedule.log_gas + schedule.log_topic_gas * no_of_topics;
|
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;
|
let s = mem_size >> 5;
|
||||||
// s * memory_gas + s * s / quad_coeff_div
|
// s * memory_gas + s * s / quad_coeff_div
|
||||||
let a = overflowing!(s.overflow_mul(Gas::from(schedule.memory_gas)));
|
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);
|
// Calculate s*s/quad_coeff_div
|
||||||
if b > U512::from(!U256::zero()) {
|
let b = overflowing!(s.overflow_mul_div(s, Gas::from(schedule.quad_coeff_div)));
|
||||||
Err(evm::Error::OutOfGas)
|
Ok(overflowing!(a.overflow_add(b)))
|
||||||
} else {
|
|
||||||
Ok(overflowing!(a.overflow_add(try!(Gas::from_u256(U256::from(b))))))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let current_mem_size = Gas::from(current_mem_size);
|
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;
|
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.
|
//! Parity EVM interpreter binary.
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
#![allow(dead_code)]
|
||||||
extern crate ethcore;
|
extern crate ethcore;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
|
Loading…
Reference in New Issue
Block a user