Skip to content

Commit c7a1baf

Browse files
committed
Implement SAR opcode for Constantinople
Closes #1104
1 parent bf1d3c2 commit c7a1baf

File tree

6 files changed

+136
-0
lines changed

6 files changed

+136
-0
lines changed

eth/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
UINT_256_CEILING = 2**256
1414
UINT_255_MAX = 2**255 - 1
1515
UINT_255_CEILING = 2**255
16+
UINT_255_NEGATIVE_ONE = -1 + UINT_256_CEILING
1617
NULL_BYTE = b'\x00'
1718
EMPTY_WORD = NULL_BYTE * 32
1819

eth/vm/forks/constantinople/opcodes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
mnemonic=mnemonics.SHR,
3333
gas_cost=constants.GAS_VERYLOW,
3434
),
35+
opcode_values.SAR: as_opcode(
36+
logic_fn=arithmetic.sar,
37+
mnemonic=mnemonics.SAR,
38+
gas_cost=constants.GAS_VERYLOW,
39+
),
3540
}
3641

3742
CONSTANTINOPLE_OPCODES = merge(

eth/vm/logic/arithmetic.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,18 @@ def shr(computation):
205205
result = (value >> shift_length) & constants.UINT_256_MAX
206206

207207
computation.stack_push(result)
208+
209+
210+
def sar(computation):
211+
"""
212+
Arithmetic bitwise right shift
213+
"""
214+
shift_length, value = computation.stack_pop(num_items=2, type_hint=constants.UINT256)
215+
value = unsigned_to_signed(value)
216+
217+
if shift_length >= 256:
218+
result = 0 if value >= 0 else constants.UINT_255_NEGATIVE_ONE
219+
else:
220+
result = (value >> shift_length) & constants.UINT_256_MAX
221+
222+
computation.stack_push(result)

eth/vm/mnemonics.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
SIGNEXTEND = 'SIGNEXTEND'
1616
SHL = 'SHL'
1717
SHR = 'SHR'
18+
SAR = 'SAR'
1819
#
1920
# Comparisons
2021
#

eth/vm/opcode_values.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
BYTE = 0x1a
3232
SHL = 0x1b
3333
SHR = 0x1c
34+
SAR = 0x1d
3435

3536

3637
#

tests/core/opcodes/test_opcodes.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,116 @@ def test_shr(vm_class, val1, val2, expected):
265265

266266
result = computation.stack_pop(type_hint=constants.UINT256)
267267
assert encode_hex(pad32(int_to_big_endian(result))) == expected
268+
269+
270+
@pytest.mark.parametrize(
271+
# EIP: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right
272+
'vm_class, val1, val2, expected',
273+
(
274+
(
275+
ConstantinopleVM,
276+
'0x0000000000000000000000000000000000000000000000000000000000000001',
277+
'0x00',
278+
'0x0000000000000000000000000000000000000000000000000000000000000001',
279+
),
280+
(
281+
ConstantinopleVM,
282+
'0x0000000000000000000000000000000000000000000000000000000000000001',
283+
'0x01',
284+
'0x0000000000000000000000000000000000000000000000000000000000000000',
285+
),
286+
(
287+
ConstantinopleVM,
288+
'0x8000000000000000000000000000000000000000000000000000000000000000',
289+
'0x01',
290+
'0xc000000000000000000000000000000000000000000000000000000000000000',
291+
),
292+
(
293+
ConstantinopleVM,
294+
'0x8000000000000000000000000000000000000000000000000000000000000000',
295+
'0xff',
296+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
297+
),
298+
(
299+
ConstantinopleVM,
300+
'0x8000000000000000000000000000000000000000000000000000000000000000',
301+
'0x0100',
302+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
303+
),
304+
(
305+
ConstantinopleVM,
306+
'0x8000000000000000000000000000000000000000000000000000000000000000',
307+
'0x0101',
308+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
309+
),
310+
(
311+
ConstantinopleVM,
312+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
313+
'0x00',
314+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
315+
),
316+
(
317+
ConstantinopleVM,
318+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
319+
'0x01',
320+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
321+
),
322+
(
323+
ConstantinopleVM,
324+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
325+
'0xff',
326+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
327+
),
328+
(
329+
ConstantinopleVM,
330+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
331+
'0x0100',
332+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
333+
),
334+
(
335+
ConstantinopleVM,
336+
'0x0000000000000000000000000000000000000000000000000000000000000000',
337+
'0x01',
338+
'0x0000000000000000000000000000000000000000000000000000000000000000',
339+
),
340+
341+
(
342+
ConstantinopleVM,
343+
'0x4000000000000000000000000000000000000000000000000000000000000000',
344+
'0xfe',
345+
'0x0000000000000000000000000000000000000000000000000000000000000001',
346+
),
347+
(
348+
ConstantinopleVM,
349+
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
350+
'0xf8',
351+
'0x000000000000000000000000000000000000000000000000000000000000007f',
352+
),
353+
(
354+
ConstantinopleVM,
355+
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
356+
'0xfe',
357+
'0x0000000000000000000000000000000000000000000000000000000000000001',
358+
),
359+
(
360+
ConstantinopleVM,
361+
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
362+
'0xff',
363+
'0x0000000000000000000000000000000000000000000000000000000000000000',
364+
),
365+
(
366+
ConstantinopleVM,
367+
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
368+
'0x0100',
369+
'0x0000000000000000000000000000000000000000000000000000000000000000',
370+
),
371+
)
372+
)
373+
def test_sar(vm_class, val1, val2, expected):
374+
computation = prepare_computation(vm_class)
375+
computation.stack_push(decode_hex(val1))
376+
computation.stack_push(decode_hex(val2))
377+
computation.opcodes[opcode_values.SAR](computation)
378+
379+
result = computation.stack_pop(type_hint=constants.UINT256)
380+
assert encode_hex(pad32(int_to_big_endian(result))) == expected

0 commit comments

Comments
 (0)