Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

EIP 145: Bitwise shifting instructions in EVM #8451

Merged
merged 7 commits into from
May 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion ethcore/evm/src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ lazy_static! {
arr[OR as usize] = InstructionInfo::new("OR", 2, 1, GasPriceTier::VeryLow);
arr[XOR as usize] = InstructionInfo::new("XOR", 2, 1, GasPriceTier::VeryLow);
arr[BYTE as usize] = InstructionInfo::new("BYTE", 2, 1, GasPriceTier::VeryLow);
arr[SHL as usize] = InstructionInfo::new("SHL", 2, 1, GasPriceTier::VeryLow);
arr[SHR as usize] = InstructionInfo::new("SHR", 2, 1, GasPriceTier::VeryLow);
arr[SAR as usize] = InstructionInfo::new("SAR", 2, 1, GasPriceTier::VeryLow);
arr[ADDMOD as usize] = InstructionInfo::new("ADDMOD", 3, 1, GasPriceTier::Mid);
arr[MULMOD as usize] = InstructionInfo::new("MULMOD", 3, 1, GasPriceTier::Mid);
arr[SIGNEXTEND as usize] = InstructionInfo::new("SIGNEXTEND", 2, 1, GasPriceTier::Low);
Expand Down Expand Up @@ -354,6 +357,12 @@ pub const XOR: Instruction = 0x18;
pub const NOT: Instruction = 0x19;
/// retrieve single byte from word
pub const BYTE: Instruction = 0x1a;
/// shift left operation
pub const SHL: Instruction = 0x1b;
/// logical shift right operation
pub const SHR: Instruction = 0x1c;
/// arithmetic shift right operation
pub const SAR: Instruction = 0x1d;

/// compute SHA3-256 hash
pub const SHA3: Instruction = 0x20;
Expand Down Expand Up @@ -589,4 +598,3 @@ pub const REVERT: Instruction = 0xfd;
pub const STATICCALL: Instruction = 0xfa;
/// halt execution and register account for later deletion
pub const SUICIDE: Instruction = 0xff;

55 changes: 54 additions & 1 deletion ethcore/evm/src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
268 changes: 267 additions & 1 deletion ethcore/evm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,273 @@ fn test_create_in_staticcall(factory: super::Factory) {
assert_eq!(ext.calls.len(), 0);
}

evm_test!{test_shl: test_shl_int}
fn test_shl(factory: super::Factory) {
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"0000000000000000000000000000000000000000000000000000000000000001",
"00",
"0000000000000000000000000000000000000000000000000000000000000001");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"0000000000000000000000000000000000000000000000000000000000000001",
"01",
"0000000000000000000000000000000000000000000000000000000000000002");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"0000000000000000000000000000000000000000000000000000000000000001",
"ff",
"8000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"0000000000000000000000000000000000000000000000000000000000000001",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"0000000000000000000000000000000000000000000000000000000000000001",
"0101",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"8000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"0000000000000000000000000000000000000000000000000000000000000000",
"01",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1b,
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
}

evm_test!{test_shr: test_shr_int}
fn test_shr(factory: super::Factory) {
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"0000000000000000000000000000000000000000000000000000000000000001",
"00",
"0000000000000000000000000000000000000000000000000000000000000001");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"0000000000000000000000000000000000000000000000000000000000000001",
"01",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"8000000000000000000000000000000000000000000000000000000000000000",
"01",
"4000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"8000000000000000000000000000000000000000000000000000000000000000",
"ff",
"0000000000000000000000000000000000000000000000000000000000000001");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"8000000000000000000000000000000000000000000000000000000000000000",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"8000000000000000000000000000000000000000000000000000000000000000",
"0101",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"0000000000000000000000000000000000000000000000000000000000000001");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1c,
"0000000000000000000000000000000000000000000000000000000000000000",
"01",
"0000000000000000000000000000000000000000000000000000000000000000");
}

evm_test!{test_sar: test_sar_int}
fn test_sar(factory: super::Factory) {
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"0000000000000000000000000000000000000000000000000000000000000001",
"00",
"0000000000000000000000000000000000000000000000000000000000000001");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"0000000000000000000000000000000000000000000000000000000000000001",
"01",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"8000000000000000000000000000000000000000000000000000000000000000",
"01",
"c000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"8000000000000000000000000000000000000000000000000000000000000000",
"ff",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"8000000000000000000000000000000000000000000000000000000000000000",
"0100",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"8000000000000000000000000000000000000000000000000000000000000000",
"0101",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"00",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"01",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"0000000000000000000000000000000000000000000000000000000000000000",
"01",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"4000000000000000000000000000000000000000000000000000000000000000",
"fe",
"0000000000000000000000000000000000000000000000000000000000000001");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"f8",
"000000000000000000000000000000000000000000000000000000000000007f");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"fe",
"0000000000000000000000000000000000000000000000000000000000000001");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ff",
"0000000000000000000000000000000000000000000000000000000000000000");
push_two_pop_one_constantinople_test(
&factory,
0x1d,
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0100",
"0000000000000000000000000000000000000000000000000000000000000000");
}

fn push_two_pop_one_constantinople_test(factory: &super::Factory, opcode: u8, push1: &str, push2: &str, result: &str) {
let mut push1 = push1.from_hex().unwrap();
let mut push2 = push2.from_hex().unwrap();
assert!(push1.len() <= 32 && push1.len() != 0);
assert!(push2.len() <= 32 && push2.len() != 0);

let mut code = Vec::new();
code.push(0x60 + ((push1.len() - 1) as u8));
code.append(&mut push1);
code.push(0x60 + ((push2.len() - 1) as u8));
code.append(&mut push2);
code.push(opcode);
code.append(&mut vec![0x60, 0x00, 0x55]);

let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
let mut ext = FakeExt::new_constantinople();

let _ = {
let mut vm = factory.create(&params.gas);
test_finalize(vm.exec(params, &mut ext)).unwrap()
};

assert_store(&ext, 0, result);
}

fn assert_set_contains<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, val: &T) {
let contains = set.contains(val);
if !contains {
Expand All @@ -799,4 +1066,3 @@ fn assert_set_contains<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, val:
fn assert_store(ext: &FakeExt, pos: u64, val: &str) {
assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap());
}

Loading