ethereum.forks.london.vm.instructions.arithmetic

Ethereum Virtual Machine (EVM) Arithmetic Instructions.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementations of the EVM Arithmetic instructions.

add

Adds the top two elements of the stack together, and pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def add(evm: Evm) -> None:
28
    """
29
    Adds the top two elements of the stack together, and pushes the result back
30
    on the stack.
31
32
    Parameters
33
    ----------
34
    evm :
35
        The current EVM frame.
36
37
    """
38
    # STACK
39
    x = pop(evm.stack)
40
    y = pop(evm.stack)
41
42
    # GAS
43
    charge_gas(evm, GasCosts.OPCODE_ADD)
44
45
    # OPERATION
46
    result = x.wrapping_add(y)
47
48
    push(evm.stack, result)
49
50
    # PROGRAM COUNTER
51
    evm.pc += Uint(1)

sub

Subtracts the top two elements of the stack, and pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def sub(evm: Evm) -> None:
55
    """
56
    Subtracts the top two elements of the stack, and pushes the result back
57
    on the stack.
58
59
    Parameters
60
    ----------
61
    evm :
62
        The current EVM frame.
63
64
    """
65
    # STACK
66
    x = pop(evm.stack)
67
    y = pop(evm.stack)
68
69
    # GAS
70
    charge_gas(evm, GasCosts.OPCODE_SUB)
71
72
    # OPERATION
73
    result = x.wrapping_sub(y)
74
75
    push(evm.stack, result)
76
77
    # PROGRAM COUNTER
78
    evm.pc += Uint(1)

mul

Multiplies the top two elements of the stack, and pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def mul(evm: Evm) -> None:
82
    """
83
    Multiplies the top two elements of the stack, and pushes the result back
84
    on the stack.
85
86
    Parameters
87
    ----------
88
    evm :
89
        The current EVM frame.
90
91
    """
92
    # STACK
93
    x = pop(evm.stack)
94
    y = pop(evm.stack)
95
96
    # GAS
97
    charge_gas(evm, GasCosts.OPCODE_MUL)
98
99
    # OPERATION
100
    result = x.wrapping_mul(y)
101
102
    push(evm.stack, result)
103
104
    # PROGRAM COUNTER
105
    evm.pc += Uint(1)

div

Integer division of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def div(evm: Evm) -> None:
109
    """
110
    Integer division of the top two elements of the stack. Pushes the result
111
    back on the stack.
112
113
    Parameters
114
    ----------
115
    evm :
116
        The current EVM frame.
117
118
    """
119
    # STACK
120
    dividend = pop(evm.stack)
121
    divisor = pop(evm.stack)
122
123
    # GAS
124
    charge_gas(evm, GasCosts.OPCODE_DIV)
125
126
    # OPERATION
127
    if divisor == 0:
128
        quotient = U256(0)
129
    else:
130
        quotient = dividend // divisor
131
132
    push(evm.stack, quotient)
133
134
    # PROGRAM COUNTER
135
    evm.pc += Uint(1)

U255_CEIL_VALUE

138
U255_CEIL_VALUE = 2**255

sdiv

Signed integer division of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def sdiv(evm: Evm) -> None:
142
    """
143
    Signed integer division of the top two elements of the stack. Pushes the
144
    result back on the stack.
145
146
    Parameters
147
    ----------
148
    evm :
149
        The current EVM frame.
150
151
    """
152
    # STACK
153
    dividend = pop(evm.stack).to_signed()
154
    divisor = pop(evm.stack).to_signed()
155
156
    # GAS
157
    charge_gas(evm, GasCosts.OPCODE_SDIV)
158
159
    # OPERATION
160
    if divisor == 0:
161
        quotient = 0
162
    elif dividend == -U255_CEIL_VALUE and divisor == -1:
163
        quotient = -U255_CEIL_VALUE
164
    else:
165
        sign = get_sign(dividend * divisor)
166
        quotient = sign * (abs(dividend) // abs(divisor))
167
168
    push(evm.stack, U256.from_signed(quotient))
169
170
    # PROGRAM COUNTER
171
    evm.pc += Uint(1)

mod

Modulo remainder of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def mod(evm: Evm) -> None:
175
    """
176
    Modulo remainder of the top two elements of the stack. Pushes the result
177
    back on the stack.
178
179
    Parameters
180
    ----------
181
    evm :
182
        The current EVM frame.
183
184
    """
185
    # STACK
186
    x = pop(evm.stack)
187
    y = pop(evm.stack)
188
189
    # GAS
190
    charge_gas(evm, GasCosts.OPCODE_MOD)
191
192
    # OPERATION
193
    if y == 0:
194
        remainder = U256(0)
195
    else:
196
        remainder = x % y
197
198
    push(evm.stack, remainder)
199
200
    # PROGRAM COUNTER
201
    evm.pc += Uint(1)

smod

Signed modulo remainder of the top two elements of the stack. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def smod(evm: Evm) -> None:
205
    """
206
    Signed modulo remainder of the top two elements of the stack. Pushes the
207
    result back on the stack.
208
209
    Parameters
210
    ----------
211
    evm :
212
        The current EVM frame.
213
214
    """
215
    # STACK
216
    x = pop(evm.stack).to_signed()
217
    y = pop(evm.stack).to_signed()
218
219
    # GAS
220
    charge_gas(evm, GasCosts.OPCODE_SMOD)
221
222
    # OPERATION
223
    if y == 0:
224
        remainder = 0
225
    else:
226
        remainder = get_sign(x) * (abs(x) % abs(y))
227
228
    push(evm.stack, U256.from_signed(remainder))
229
230
    # PROGRAM COUNTER
231
    evm.pc += Uint(1)

addmod

Modulo addition of the top 2 elements with the 3rd element. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def addmod(evm: Evm) -> None:
235
    """
236
    Modulo addition of the top 2 elements with the 3rd element. Pushes the
237
    result back on the stack.
238
239
    Parameters
240
    ----------
241
    evm :
242
        The current EVM frame.
243
244
    """
245
    # STACK
246
    x = Uint(pop(evm.stack))
247
    y = Uint(pop(evm.stack))
248
    z = Uint(pop(evm.stack))
249
250
    # GAS
251
    charge_gas(evm, GasCosts.OPCODE_ADDMOD)
252
253
    # OPERATION
254
    if z == 0:
255
        result = U256(0)
256
    else:
257
        result = U256((x + y) % z)
258
259
    push(evm.stack, result)
260
261
    # PROGRAM COUNTER
262
    evm.pc += Uint(1)

mulmod

Modulo multiplication of the top 2 elements with the 3rd element. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def mulmod(evm: Evm) -> None:
266
    """
267
    Modulo multiplication of the top 2 elements with the 3rd element. Pushes
268
    the result back on the stack.
269
270
    Parameters
271
    ----------
272
    evm :
273
        The current EVM frame.
274
275
    """
276
    # STACK
277
    x = Uint(pop(evm.stack))
278
    y = Uint(pop(evm.stack))
279
    z = Uint(pop(evm.stack))
280
281
    # GAS
282
    charge_gas(evm, GasCosts.OPCODE_MULMOD)
283
284
    # OPERATION
285
    if z == 0:
286
        result = U256(0)
287
    else:
288
        result = U256((x * y) % z)
289
290
    push(evm.stack, result)
291
292
    # PROGRAM COUNTER
293
    evm.pc += Uint(1)

exp

Exponential operation of the top 2 elements. Pushes the result back on the stack.

Parameters

evm : The current EVM frame.

def exp(evm: Evm) -> None:
297
    """
298
    Exponential operation of the top 2 elements. Pushes the result back on
299
    the stack.
300
301
    Parameters
302
    ----------
303
    evm :
304
        The current EVM frame.
305
306
    """
307
    # STACK
308
    base = Uint(pop(evm.stack))
309
    exponent = Uint(pop(evm.stack))
310
311
    # GAS
312
    # This is equivalent to 1 + floor(log(y, 256)). But in python the log
313
    # function is inaccurate leading to wrong results.
314
    exponent_bits = exponent.bit_length()
315
    exponent_bytes = (exponent_bits + Uint(7)) // Uint(8)
316
    charge_gas(
317
        evm,
318
        GasCosts.OPCODE_EXP_BASE
319
        + GasCosts.OPCODE_EXP_PER_BYTE * exponent_bytes,
320
    )
321
322
    # OPERATION
323
    result = U256(pow(base, exponent, Uint(U256.MAX_VALUE) + Uint(1)))
324
325
    push(evm.stack, result)
326
327
    # PROGRAM COUNTER
328
    evm.pc += Uint(1)

signextend

Sign extend operation. In other words, extend a signed number which fits in N bytes to 32 bytes.

Parameters

evm : The current EVM frame.

def signextend(evm: Evm) -> None:
332
    """
333
    Sign extend operation. In other words, extend a signed number which
334
    fits in N bytes to 32 bytes.
335
336
    Parameters
337
    ----------
338
    evm :
339
        The current EVM frame.
340
341
    """
342
    # STACK
343
    byte_num = pop(evm.stack)
344
    value = pop(evm.stack)
345
346
    # GAS
347
    charge_gas(evm, GasCosts.OPCODE_SIGNEXTEND)
348
349
    # OPERATION
350
    if byte_num > U256(31):
351
        # Can't extend any further
352
        result = value
353
    else:
354
        # U256(0).to_be_bytes() gives b'' instead of b'\x00'.
355
        value_bytes = Bytes(value.to_be_bytes32())
356
        # Now among the obtained value bytes, consider only
357
        # N `least significant bytes`, where N is `byte_num + 1`.
358
        value_bytes = value_bytes[31 - int(byte_num) :]
359
        sign_bit = value_bytes[0] >> 7
360
        if sign_bit == 0:
361
            result = U256.from_be_bytes(value_bytes)
362
        else:
363
            num_bytes_prepend = U256(32) - (byte_num + U256(1))
364
            result = U256.from_be_bytes(
365
                bytearray([0xFF] * num_bytes_prepend) + value_bytes
366
            )
367
368
    push(evm.stack, result)
369
370
    # PROGRAM COUNTER
371
    evm.pc += Uint(1)