Fixing required memory calculation

This commit is contained in:
Tomusdrw 2016-01-14 14:49:41 +01:00
parent eebcd0f35b
commit 0a5bec821f

View File

@ -74,7 +74,7 @@ trait Memory {
/// Resize (shrink or expand) the memory to specified size (fills 0) /// Resize (shrink or expand) the memory to specified size (fills 0)
fn resize(&mut self, new_size: usize); fn resize(&mut self, new_size: usize);
/// Resize the memory only if its smaller /// Resize the memory only if its smaller
fn expand(&mut self, new_size: U256); fn expand(&mut self, new_size: usize);
/// Write single byte to memory /// Write single byte to memory
fn write_byte(&mut self, offset: U256, value: U256); fn write_byte(&mut self, offset: U256, value: U256);
/// Write a word to memory. Does not resize memory! /// Write a word to memory. Does not resize memory!
@ -141,8 +141,7 @@ impl Memory for Vec<u8> {
self.resize(new_size, 0); self.resize(new_size, 0);
} }
fn expand(&mut self, new_size: U256) { fn expand(&mut self, size: usize) {
let size = new_size.low_u64() as usize;
if size > self.len() { if size > self.len() {
Memory::resize(self, size) Memory::resize(self, size)
} }
@ -203,7 +202,7 @@ impl evm::Evm for Interpreter {
try!(self.verify_gas(&current_gas, &gas_cost)); try!(self.verify_gas(&current_gas, &gas_cost));
current_gas = current_gas - gas_cost; current_gas = current_gas - gas_cost;
println!("Gas cost: {} (left: {})", gas_cost, current_gas); println!("Gas cost: {} (left: {})", gas_cost, current_gas);
println!("Executing: {} ", instructions::get_info(instruction).name); println!("Executing: {} ({:x})", instructions::get_info(instruction).name, instruction);
// Execute instruction // Execute instruction
let result = try!(self.exec_instruction( let result = try!(self.exec_instruction(
current_gas, params, ext, instruction, &mut reader, &mut mem, &mut stack current_gas, params, ext, instruction, &mut reader, &mut mem, &mut stack
@ -346,36 +345,37 @@ impl Interpreter {
Ok(gas) Ok(gas)
}, },
InstructionCost::GasMem(gas, mem_size) => { InstructionCost::GasMem(gas, mem_size) => {
let mem_gas = self.mem_gas_cost(schedule, mem.size(), &mem_size); let (mem_gas, new_mem_size) = self.mem_gas_cost(schedule, mem.size(), &mem_size);
// Expand after calculating the cost // Expand after calculating the cost
mem.expand(mem_size); mem.expand(new_mem_size);
Ok(gas + mem_gas) Ok(gas + mem_gas)
}, },
InstructionCost::GasMemCopy(gas, mem_size, copy) => { InstructionCost::GasMemCopy(gas, mem_size, copy) => {
let mem_gas = self.mem_gas_cost(schedule, mem.size(), &mem_size); let (mem_gas, new_mem_size) = self.mem_gas_cost(schedule, mem.size(), &mem_size);
let copy_gas = U256::from(schedule.copy_gas) * (add_u256_usize(&copy, 31) / U256::from(32)); let copy_gas = U256::from(schedule.copy_gas) * (add_u256_usize(&copy, 31) / U256::from(32));
// Expand after calculating the cost // Expand after calculating the cost
mem.expand(mem_size); mem.expand(new_mem_size);
Ok(gas + copy_gas + mem_gas) Ok(gas + copy_gas + mem_gas)
} }
} }
} }
fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &U256) -> U256 { fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &U256) -> (U256, usize) {
let gas_for_mem = |mem_size: usize| { let gas_for_mem = |mem_size: usize| {
let s = mem_size / 32; let s = mem_size / 32;
schedule.memory_gas * s + s * s / schedule.quad_coeff_div schedule.memory_gas * s + s * s / schedule.quad_coeff_div
}; };
let mem_size_rounded = add_u256_usize(mem_size, 31).low_u64() as usize / 32 * 32; let req_mem_size = mem_size.low_u64() as usize;
let mem_gas = gas_for_mem(mem_size_rounded); let req_mem_size_rounded = (req_mem_size + 31) / 32 * 32;
let new_mem_gas = gas_for_mem(req_mem_size_rounded);
let current_mem_gas = gas_for_mem(current_mem_size); let current_mem_gas = gas_for_mem(current_mem_size);
U256::from(if mem_gas > current_mem_gas { (if req_mem_size_rounded > current_mem_size {
mem_gas - current_mem_gas U256::from(new_mem_gas - current_mem_gas)
} else { } else {
0 U256::zero()
}) }, req_mem_size_rounded)
} }
@ -582,9 +582,6 @@ impl Interpreter {
instructions::EXTCODECOPY => { instructions::EXTCODECOPY => {
let address = u256_to_address(&stack.pop_back()); let address = u256_to_address(&stack.pop_back());
let code = ext.extcode(&address); let code = ext.extcode(&address);
for b in &code {
println!("Code: {:x}", b);
}
self.copy_data_to_memory(mem, stack, &code); self.copy_data_to_memory(mem, stack, &code);
}, },
instructions::GASPRICE => { instructions::GASPRICE => {
@ -820,6 +817,7 @@ fn address_to_u256(value: Address) -> U256 {
mod tests { mod tests {
use common::*; use common::*;
use super::*; use super::*;
use evm;
#[test] #[test]
fn test_find_jump_destinations() { fn test_find_jump_destinations() {
@ -834,6 +832,22 @@ mod tests {
assert!(valid_jump_destinations.contains(&66)); assert!(valid_jump_destinations.contains(&66));
} }
#[test]
fn test_calculate_mem_cost() {
// given
let interpreter = Interpreter;
let schedule = evm::Schedule::default();
let current_mem_size = 0;
let mem_size = U256::from(5);
// when
let (mem_cost, mem_size) = interpreter.mem_gas_cost(&schedule, current_mem_size, &mem_size);
// then
assert_eq!(mem_cost, U256::from(3));
assert_eq!(mem_size, 32);
}
#[test] #[test]
fn test_memory_read_and_write() { fn test_memory_read_and_write() {
// given // given