Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement SAR opcode #1134

Merged
merged 1 commit into from
Aug 7, 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
1 change: 1 addition & 0 deletions eth/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
UINT_256_CEILING = 2**256
UINT_255_MAX = 2**255 - 1
UINT_255_CEILING = 2**255
UINT_255_NEGATIVE_ONE = -1 + UINT_256_CEILING
NULL_BYTE = b'\x00'
EMPTY_WORD = NULL_BYTE * 32

Expand Down
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note, I just realized that we use keyword style calling for all stack operations, and a while back @davesque uncovered that calling things with positional arguments is significantly faster than keyword style calling. We should look into updating all of these call sites to use positional arguments.

value = unsigned_to_signed(value)

if shift_length >= 256:
result = 0 if value >= 0 else constants.UINT_255_NEGATIVE_ONE
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(
# EIP: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-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