Skip to content

Commit c53e66a

Browse files
committed
Add SHL Opcode for Constantinople
Relates to #1104
1 parent de60bdb commit c53e66a

File tree

5 files changed

+132
-4
lines changed

5 files changed

+132
-4
lines changed
Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,35 @@
11
import copy
2+
from cytoolz import (
3+
merge
4+
)
25

6+
from eth import (
7+
constants
8+
)
9+
from eth.vm import (
10+
mnemonics,
11+
opcode_values,
12+
)
313
from eth.vm.forks.byzantium.opcodes import (
414
BYZANTIUM_OPCODES
515
)
16+
from eth.vm.logic import (
17+
arithmetic
18+
)
19+
from eth.vm.opcode import (
20+
as_opcode
21+
)
22+
623

24+
UPDATED_OPCODES = {
25+
opcode_values.SHL: as_opcode(
26+
logic_fn=arithmetic.shl,
27+
mnemonic=mnemonics.SHL,
28+
gas_cost=constants.GAS_VERYLOW,
29+
),
30+
}
731

8-
CONSTANTINOPLE_OPCODES = copy.deepcopy(BYZANTIUM_OPCODES)
32+
CONSTANTINOPLE_OPCODES = merge(
33+
copy.deepcopy(BYZANTIUM_OPCODES),
34+
UPDATED_OPCODES,
35+
)

eth/vm/logic/arithmetic.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,17 @@ def signextend(computation):
177177
result = value
178178

179179
computation.stack_push(result)
180+
181+
182+
def shl(computation):
183+
"""
184+
Bitwise left shift
185+
"""
186+
shift_length, value = computation.stack_pop(num_items=2, type_hint=constants.UINT256)
187+
188+
if shift_length >= 256:
189+
result = 0
190+
else:
191+
result = (value << shift_length) & constants.UINT_256_MAX
192+
193+
computation.stack_push(result)

eth/vm/mnemonics.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
MULMOD = 'MULMOD'
1414
EXP = 'EXP'
1515
SIGNEXTEND = 'SIGNEXTEND'
16+
SHL = 'SHL'
1617
#
1718
# Comparisons
1819
#

eth/vm/opcode_values.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
XOR = 0x18
3030
NOT = 0x19
3131
BYTE = 0x1a
32+
SHL = 0x1b
3233

3334

3435
#

tests/core/opcodes/test_opcodes.py

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import pytest
22

33
from eth_utils import (
4+
decode_hex,
5+
encode_hex,
46
to_canonical_address,
7+
int_to_big_endian,
58
)
69

710
from eth import (
811
constants
912
)
13+
from eth.utils.padding import (
14+
pad32
15+
)
1016
from eth.vm import (
1117
opcode_values
1218
)
13-
from eth.vm.forks.byzantium.opcodes import (
14-
BYZANTIUM_OPCODES
15-
)
1619
from eth.vm.forks import (
20+
ConstantinopleVM,
1721
ByzantiumVM,
1822
SpuriousDragonVM,
1923
TangerineWhistleVM,
@@ -98,3 +102,84 @@ def test_mul(vm_class, val1, val2, expected):
98102
assert result == expected
99103

100104

105+
@pytest.mark.parametrize(
106+
# Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left
107+
'vm_class, val1, val2, expected',
108+
(
109+
(
110+
ConstantinopleVM,
111+
'0x0000000000000000000000000000000000000000000000000000000000000001',
112+
'0x00',
113+
'0x0000000000000000000000000000000000000000000000000000000000000001',
114+
),
115+
(
116+
ConstantinopleVM,
117+
'0x0000000000000000000000000000000000000000000000000000000000000001',
118+
'0x01',
119+
'0x0000000000000000000000000000000000000000000000000000000000000002',
120+
),
121+
(
122+
ConstantinopleVM,
123+
'0x0000000000000000000000000000000000000000000000000000000000000001',
124+
'0xff',
125+
'0x8000000000000000000000000000000000000000000000000000000000000000',
126+
),
127+
(
128+
ConstantinopleVM,
129+
'0x0000000000000000000000000000000000000000000000000000000000000001',
130+
'0x0100',
131+
'0x0000000000000000000000000000000000000000000000000000000000000000',
132+
),
133+
(
134+
ConstantinopleVM,
135+
'0x0000000000000000000000000000000000000000000000000000000000000001',
136+
'0x0101',
137+
'0x0000000000000000000000000000000000000000000000000000000000000000',
138+
),
139+
(
140+
ConstantinopleVM,
141+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
142+
'0x00',
143+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
144+
),
145+
(
146+
ConstantinopleVM,
147+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
148+
'0x01',
149+
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe',
150+
),
151+
(
152+
ConstantinopleVM,
153+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
154+
'0xff',
155+
'0x8000000000000000000000000000000000000000000000000000000000000000',
156+
),
157+
(
158+
ConstantinopleVM,
159+
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
160+
'0x0100',
161+
'0x0000000000000000000000000000000000000000000000000000000000000000',
162+
),
163+
(
164+
ConstantinopleVM,
165+
'0x0000000000000000000000000000000000000000000000000000000000000000',
166+
'0x01',
167+
'0x0000000000000000000000000000000000000000000000000000000000000000',
168+
),
169+
(
170+
ConstantinopleVM,
171+
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
172+
'0x01',
173+
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe',
174+
),
175+
)
176+
)
177+
def test_shl(vm_class, val1, val2, expected):
178+
computation = prepare_computation(vm_class)
179+
computation.stack_push(decode_hex(val1))
180+
computation.stack_push(decode_hex(val2))
181+
computation.opcodes[opcode_values.SHL](computation)
182+
183+
result = computation.stack_pop(type_hint=constants.UINT256)
184+
185+
assert encode_hex(pad32(int_to_big_endian(result))) == expected

0 commit comments

Comments
 (0)