Implementing Signextend and fixing signed operations
This commit is contained in:
parent
b7e7518b8e
commit
7af4825b15
@ -43,7 +43,6 @@ impl<S : fmt::Display> Stack<S> for Vec<S> {
|
|||||||
|
|
||||||
fn pop_back(&mut self) -> S {
|
fn pop_back(&mut self) -> S {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
println!("Popping from stack.");
|
|
||||||
match val {
|
match val {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => panic!("Tried to pop from empty stack.")
|
None => panic!("Tried to pop from empty stack.")
|
||||||
@ -60,7 +59,7 @@ impl<S : fmt::Display> Stack<S> for Vec<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, elem: S) {
|
fn push(&mut self, elem: S) {
|
||||||
println!("Pushing to stack: {}", elem);
|
// println!("Pushing to stack: {}", elem);
|
||||||
self.push(elem);
|
self.push(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +115,6 @@ impl Memory for Vec<u8> {
|
|||||||
|
|
||||||
// TODO [todr] Optimize?
|
// TODO [todr] Optimize?
|
||||||
for pos in off..off+slice.len() {
|
for pos in off..off+slice.len() {
|
||||||
println!("Writing {:x}", slice[pos - off]);
|
|
||||||
self[pos] = slice[pos - off];
|
self[pos] = slice[pos - off];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,8 +200,11 @@ impl evm::Evm for Interpreter {
|
|||||||
let gas_cost = try!(self.get_gas_cost_and_expand_mem(ext, instruction, &mut mem, &stack));
|
let gas_cost = try!(self.get_gas_cost_and_expand_mem(ext, instruction, &mut mem, &stack));
|
||||||
try!(self.verify_gas(¤t_gas, &gas_cost));
|
try!(self.verify_gas(¤t_gas, &gas_cost));
|
||||||
current_gas = current_gas - gas_cost;
|
current_gas = current_gas - gas_cost;
|
||||||
println!("Gas cost: {} (left: {})", gas_cost, current_gas);
|
// println!("Executing: {} (0x{:x}) [Gas Cost: {} (Left: {})]",
|
||||||
println!("Executing: {} ({:x})", instructions::get_info(instruction).name, instruction);
|
// instructions::get_info(instruction).name, instruction,
|
||||||
|
// gas_cost,
|
||||||
|
// current_gas
|
||||||
|
// );
|
||||||
// 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
|
||||||
@ -337,8 +338,8 @@ impl Interpreter {
|
|||||||
},
|
},
|
||||||
instructions::EXP => {
|
instructions::EXP => {
|
||||||
let expon = stack.peek(1);
|
let expon = stack.peek(1);
|
||||||
let first_bits = (expon.byte(0) / 8) as usize;
|
let bytes = ((expon.bits() + 7) / 8) as usize;
|
||||||
let gas = U256::from(schedule.exp_gas + schedule.exp_byte_gas * (32 - first_bits));
|
let gas = U256::from(schedule.exp_gas + schedule.exp_byte_gas * bytes);
|
||||||
InstructionCost::Gas(gas)
|
InstructionCost::Gas(gas)
|
||||||
},
|
},
|
||||||
_ => InstructionCost::Gas(default_gas)
|
_ => InstructionCost::Gas(default_gas)
|
||||||
@ -408,8 +409,8 @@ impl Interpreter {
|
|||||||
));
|
));
|
||||||
},
|
},
|
||||||
instructions::JUMPI => {
|
instructions::JUMPI => {
|
||||||
let condition = stack.pop_back();
|
|
||||||
let jump = stack.pop_back();
|
let jump = stack.pop_back();
|
||||||
|
let condition = stack.pop_back();
|
||||||
if !self.is_zero(&condition) {
|
if !self.is_zero(&condition) {
|
||||||
return Ok(InstructionResult::JumpToPosition(
|
return Ok(InstructionResult::JumpToPosition(
|
||||||
jump
|
jump
|
||||||
@ -627,8 +628,14 @@ impl Interpreter {
|
|||||||
let offset = stack.pop_back();
|
let offset = stack.pop_back();
|
||||||
let index = stack.pop_back().low_u64() as usize;
|
let index = stack.pop_back().low_u64() as usize;
|
||||||
let size = stack.pop_back().low_u64() as usize;
|
let size = stack.pop_back().low_u64() as usize;
|
||||||
|
let data_size = data.len();
|
||||||
|
let bound_size = if size + index > data_size {
|
||||||
|
data_size
|
||||||
|
} else {
|
||||||
|
size + index
|
||||||
|
};
|
||||||
|
|
||||||
mem.write_slice(offset, &data[index..index+size]);
|
mem.write_slice(offset, &data[index..bound_size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_instructions_requirements(&self,
|
fn verify_instructions_requirements(&self,
|
||||||
@ -737,31 +744,29 @@ impl Interpreter {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
instructions::SDIV => {
|
instructions::SDIV => {
|
||||||
let ua = stack.pop_back();
|
let (a, sign_a) = get_and_reset_sign(stack.pop_back());
|
||||||
let ub = stack.pop_back();
|
let (b, sign_b) = get_and_reset_sign(stack.pop_back());
|
||||||
let (a, sign_a) = get_and_reset_sign(ua);
|
|
||||||
let (b, sign_b) = get_and_reset_sign(ub);
|
|
||||||
|
|
||||||
println!("Values: {}({}), {}({})", a, sign_a, b, sign_b);
|
// -2^255
|
||||||
let max = !U256::zero();
|
let min = U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
|
||||||
println!("Max: {}", max);
|
stack.push(if self.is_zero(&b) {
|
||||||
stack.push(if self.is_zero(&ub) {
|
|
||||||
U256::zero()
|
U256::zero()
|
||||||
} else if ub == max || sign_a && self.is_zero(&a) {
|
} else if a == min && b == !U256::zero() {
|
||||||
max
|
min
|
||||||
} else {
|
} else {
|
||||||
let (c, _overflow) = a.overflowing_div(b);
|
let (c, _overflow) = a.overflowing_div(b);
|
||||||
set_sign(c, sign_a ^ sign_b)
|
set_sign(c, sign_a ^ sign_b)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
instructions::SMOD => {
|
instructions::SMOD => {
|
||||||
let (a, sign_a) = get_and_reset_sign(stack.pop_back());
|
let ua = stack.pop_back();
|
||||||
let ub = stack.pop_back();
|
let ub = stack.pop_back();
|
||||||
let (b, sign_b) = get_and_reset_sign(ub);
|
let (a, sign_a) = get_and_reset_sign(ua);
|
||||||
|
let (b, _sign_b) = get_and_reset_sign(ub);
|
||||||
|
|
||||||
stack.push(if !self.is_zero(&ub) {
|
stack.push(if !self.is_zero(&b) {
|
||||||
let (c, _overflow) = a.overflowing_rem(b);
|
let (c, _overflow) = a.overflowing_rem(b);
|
||||||
set_sign(c, sign_a ^ sign_b)
|
set_sign(c, sign_a)
|
||||||
} else {
|
} else {
|
||||||
U256::zero()
|
U256::zero()
|
||||||
});
|
});
|
||||||
@ -868,7 +873,21 @@ impl Interpreter {
|
|||||||
U256::zero()
|
U256::zero()
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
instructions::SIGNEXTEND => {},
|
instructions::SIGNEXTEND => {
|
||||||
|
let bit = stack.pop_back();
|
||||||
|
if bit < U256::from(32) {
|
||||||
|
let number = stack.pop_back();
|
||||||
|
let bit_position = (bit.low_u64() * 8 + 7) as usize;
|
||||||
|
|
||||||
|
let bit = number.bit(bit_position);
|
||||||
|
let mask = (U256::one() << bit_position) - U256::one();
|
||||||
|
stack.push(if bit {
|
||||||
|
number | !mask
|
||||||
|
} else {
|
||||||
|
number & mask
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(evm::Error::BadInstruction {
|
return Err(evm::Error::BadInstruction {
|
||||||
instruction: instruction
|
instruction: instruction
|
||||||
@ -899,12 +918,17 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_and_reset_sign(value: U256) -> (U256, bool) {
|
fn get_and_reset_sign(value: U256) -> (U256, bool) {
|
||||||
let sign = value.bit(255);
|
let sign = (value >> 255).low_u64() == 1;
|
||||||
(set_sign(value, false), sign)
|
(set_sign(value, sign), sign)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_sign(value: U256, sign: bool) -> U256 {
|
pub fn set_sign(value: U256, sign: bool) -> U256 {
|
||||||
value | (U256::from(sign as usize) << 256)
|
if sign {
|
||||||
|
let (val, _overflow) = (!U256::zero() ^ value).overflowing_add(U256::one());
|
||||||
|
val
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_u256_usize(value: &U256, num: usize) -> U256 {
|
fn add_u256_usize(value: &U256, num: usize) -> U256 {
|
||||||
|
@ -158,7 +158,6 @@ impl<'a> Ext for TestExt<'a> {
|
|||||||
|
|
||||||
fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
||||||
let vms = VMType::all();
|
let vms = VMType::all();
|
||||||
|
|
||||||
vms
|
vms
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|vm| do_json_test_for(vm, json_data))
|
.flat_map(|vm| do_json_test_for(vm, json_data))
|
||||||
@ -169,9 +168,9 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
|
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
|
||||||
let mut failed = Vec::new();
|
let mut failed = Vec::new();
|
||||||
for (name, test) in json.as_object().unwrap() {
|
for (name, test) in json.as_object().unwrap() {
|
||||||
if name != "addmod1_overflow3" {
|
// if name != "signextend_Overflow_dj42" {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
println!("name: {:?}", name);
|
println!("name: {:?}", name);
|
||||||
// sync io is usefull when something crashes in jit
|
// sync io is usefull when something crashes in jit
|
||||||
// ::std::io::stdout().write(&name.as_bytes());
|
// ::std::io::stdout().write(&name.as_bytes());
|
||||||
|
Loading…
Reference in New Issue
Block a user