EIP 145: Bitwise shifting instructions in EVM (#8451)

* Add SHL, SHR, SAR opcodes

* Add have_bitwise_shifting schedule flag

* Add all EIP tests for SHL

* Add SHR implementation and tests

* Implement SAR and add tests

* Add eip145transition config param

* Change map_or to map_or_else when possible
This commit is contained in:
Wei Tang
2018-05-05 16:23:50 +08:00
committed by Marek Kotewicz
parent f0c6d17ad8
commit a4c7843a07
7 changed files with 374 additions and 20 deletions

View File

@@ -224,7 +224,8 @@ impl<Cost: CostType> Interpreter<Cost> {
(instruction == instructions::CREATE2 && !schedule.have_create2) ||
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
(instruction == instructions::REVERT && !schedule.have_revert) {
(instruction == instructions::REVERT && !schedule.have_revert) ||
((instruction == instructions::SHL || instruction == instructions::SHR || instruction == instructions::SAR) && !schedule.have_bitwise_shifting) {
return Err(vm::Error::BadInstruction {
instruction: instruction
@@ -871,6 +872,58 @@ impl<Cost: CostType> Interpreter<Cost> {
});
}
},
instructions::SHL => {
const CONST_256: U256 = U256([256, 0, 0, 0]);
let shift = stack.pop_back();
let value = stack.pop_back();
let result = if shift >= CONST_256 {
U256::zero()
} else {
value << (shift.as_u32() as usize)
};
stack.push(result);
},
instructions::SHR => {
const CONST_256: U256 = U256([256, 0, 0, 0]);
let shift = stack.pop_back();
let value = stack.pop_back();
let result = if shift >= CONST_256 {
U256::zero()
} else {
value >> (shift.as_u32() as usize)
};
stack.push(result);
},
instructions::SAR => {
// We cannot use get_and_reset_sign/set_sign here, because the rounding looks different.
const CONST_256: U256 = U256([256, 0, 0, 0]);
const CONST_HIBIT: U256 = U256([0, 0, 0, 0x8000000000000000]);
let shift = stack.pop_back();
let value = stack.pop_back();
let sign = value & CONST_HIBIT != U256::zero();
let result = if shift >= CONST_256 {
if sign {
U256::max_value()
} else {
U256::zero()
}
} else {
let shift = shift.as_u32() as usize;
let mut shifted = value >> shift;
if sign {
shifted = shifted | (U256::max_value() << (256 - shift));
}
shifted
};
stack.push(result);
},
_ => {
return Err(vm::Error::BadInstruction {
instruction: instruction