Skip to content

Commit 70e4332

Browse files
committed
Add SHL Opcode for Constantinople
Relates to ethereum#1104
1 parent 6e43044 commit 70e4332

File tree

7 files changed

+140
-4
lines changed

7 files changed

+140
-4
lines changed

eth/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
UINT256 = 'uint256'
1010
BYTES = 'bytes'
1111

12+
CONST_256 = 256
13+
CONST_0 = 0
14+
1215
UINT_256_MAX = 2**256 - 1
1316
UINT_256_CEILING = 2**256
1417
UINT_255_MAX = 2**255 - 1
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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from BitVector import (
2+
BitVector
3+
)
14
from cytoolz import (
25
curry,
36
)
@@ -177,3 +180,18 @@ def signextend(computation):
177180
result = value
178181

179182
computation.stack_push(result)
183+
184+
185+
def shl(computation):
186+
"""
187+
Bitwise left shift
188+
"""
189+
shift_length, value = computation.stack_pop(num_items=2, type_hint=constants.UINT256)
190+
bit_vector = BitVector(intVal=value, size=constants.CONST_256)
191+
192+
if shift_length >= constants.CONST_256:
193+
result = constants.CONST_0
194+
else:
195+
result = bit_vector.shift_left(shift_length).int_val()
196+
197+
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
#

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
deps = {
77
'eth': [
8+
"BitVector>=3.4.8, <4.0.0",
89
"cryptography>=2.0.3,<3.0.0",
910
"cytoolz>=0.9.0,<1.0.0",
1011
"eth-bloom>=1.0.0,<2.0.0",

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)