Skip to content

Commit

Permalink
Implement SAR opcode for Constantinople
Browse files Browse the repository at this point in the history
Closes #1104
  • Loading branch information
cburgdorf committed Aug 1, 2018
1 parent 888f496 commit d31c552
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 0 deletions.
5 changes: 5 additions & 0 deletions eth/vm/forks/constantinople/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
mnemonic=mnemonics.SHR,
gas_cost=constants.GAS_VERYLOW,
),
opcode_values.SAR: as_opcode(
logic_fn=arithmetic.sar,
mnemonic=mnemonics.SAR,
gas_cost=constants.GAS_VERYLOW,
),
}

CONSTANTINOPLE_OPCODES = merge(
Expand Down
15 changes: 15 additions & 0 deletions eth/vm/logic/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,18 @@ def shr(computation):
result = (value >> shift_length) & constants.UINT_256_MAX

computation.stack_push(result)


def sar(computation):
"""
Arithmetic bitwise right shift
"""
shift_length, value = computation.stack_pop(num_items=2, type_hint=constants.UINT256)
value = unsigned_to_signed(value)

if shift_length >= 256:
result = 0 if value >= 0 else signed_to_unsigned(-1)
else:
result = (value >> shift_length) & constants.UINT_256_MAX

computation.stack_push(result)
1 change: 1 addition & 0 deletions eth/vm/mnemonics.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
SIGNEXTEND = 'SIGNEXTEND'
SHL = 'SHL'
SHR = 'SHR'
SAR = 'SAR'
#
# Comparisons
#
Expand Down
1 change: 1 addition & 0 deletions eth/vm/opcode_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
BYTE = 0x1a
SHL = 0x1b
SHR = 0x1c
SAR = 0x1d


#
Expand Down
113 changes: 113 additions & 0 deletions tests/core/opcodes/test_opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,116 @@ def test_shr(vm_class, val1, val2, expected):

result = computation.stack_pop(type_hint=constants.UINT256)
assert encode_hex(pad32(int_to_big_endian(result))) == expected


@pytest.mark.parametrize(
# Cases: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right
'vm_class, val1, val2, expected',
(
(
ConstantinopleVM,
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x00',
'0x0000000000000000000000000000000000000000000000000000000000000001',
),
(
ConstantinopleVM,
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x01',
'0x0000000000000000000000000000000000000000000000000000000000000000',
),
(
ConstantinopleVM,
'0x8000000000000000000000000000000000000000000000000000000000000000',
'0x01',
'0xc000000000000000000000000000000000000000000000000000000000000000',
),
(
ConstantinopleVM,
'0x8000000000000000000000000000000000000000000000000000000000000000',
'0xff',
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
),
(
ConstantinopleVM,
'0x8000000000000000000000000000000000000000000000000000000000000000',
'0x0100',
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
),
(
ConstantinopleVM,
'0x8000000000000000000000000000000000000000000000000000000000000000',
'0x0101',
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
),
(
ConstantinopleVM,
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0x00',
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
),
(
ConstantinopleVM,
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0x01',
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
),
(
ConstantinopleVM,
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0xff',
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
),
(
ConstantinopleVM,
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0x0100',
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
),
(
ConstantinopleVM,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x01',
'0x0000000000000000000000000000000000000000000000000000000000000000',
),
(
ConstantinopleVM,
'0x4000000000000000000000000000000000000000000000000000000000000000',
'0xfe',
'0x0000000000000000000000000000000000000000000000000000000000000001',
),
(
ConstantinopleVM,
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0xf8',
'0x000000000000000000000000000000000000000000000000000000000000007f',
),
(
ConstantinopleVM,
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0xfe',
'0x0000000000000000000000000000000000000000000000000000000000000001',
),
(
ConstantinopleVM,
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0xff',
'0x0000000000000000000000000000000000000000000000000000000000000000',
),
(
ConstantinopleVM,
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
'0x0100',
'0x0000000000000000000000000000000000000000000000000000000000000000',
),
)
)
def test_sar(vm_class, val1, val2, expected):
computation = prepare_computation(vm_class)
computation.stack_push(decode_hex(val1))
computation.stack_push(decode_hex(val2))
computation.opcodes[opcode_values.SAR](computation)

result = computation.stack_pop(type_hint=constants.UINT256)
assert encode_hex(pad32(int_to_big_endian(result))) == expected

0 comments on commit d31c552

Please sign in to comment.