Exemple #1
0
def mulmod(evm: Evm) -> None:
    """
    Modulo multiplication of the top 2 elements with the 3rd element. Pushes
    the result back on the stack.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `3`.
    OutOfGasError
        If `evm.gas_left` is less than `8`.
    """
    evm.gas_left = subtract_gas(evm.gas_left, GAS_MID)

    x = Uint(pop(evm.stack))
    y = Uint(pop(evm.stack))
    z = Uint(pop(evm.stack))

    if z == 0:
        result = U256(0)
    else:
        result = U256((x * y) % z)

    push(evm.stack, result)
Exemple #2
0
def exp(evm: Evm) -> None:
    """
    Exponential operation of the top 2 elements. Pushes the result back on
    the stack.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `2`.
    """
    base = Uint(pop(evm.stack))
    exponent = Uint(pop(evm.stack))

    gas_used = GAS_EXPONENTIATION
    if exponent != 0:
        # This is equivalent to 1 + floor(log(y, 256)). But in python the log
        # function is inaccurate leading to wrong results.
        exponent_bits = exponent.bit_length()
        exponent_bytes = (exponent_bits + 7) // 8
        gas_used += GAS_EXPONENTIATION * exponent_bytes
    evm.gas_left = subtract_gas(evm.gas_left, gas_used)

    result = U256(pow(base, exponent, U256_CEIL_VALUE))

    push(evm.stack, result)
Exemple #3
0
def mod(evm: Evm) -> None:
    """
    Modulo remainder of the top two elements of the stack. Pushes the result
    back on the stack.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `2`.
    OutOfGasError
        If `evm.gas_left` is less than `5`.
    """
    evm.gas_left = subtract_gas(evm.gas_left, GAS_LOW)

    x = pop(evm.stack)
    y = pop(evm.stack)
    if y == 0:
        remainder = U256(0)
    else:
        remainder = x % y

    push(evm.stack, remainder)
Exemple #4
0
def smod(evm: Evm) -> None:
    """
    Signed modulo remainder of the top two elements of the stack. Pushes the
    result back on the stack.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `2`.
    OutOfGasError
        If `evm.gas_left` is less than `5`.
    """
    evm.gas_left = subtract_gas(evm.gas_left, GAS_LOW)

    x = pop(evm.stack).to_signed()
    y = pop(evm.stack).to_signed()

    if y == 0:
        remainder = 0
    else:
        remainder = get_sign(x) * (abs(x) % abs(y))

    push(evm.stack, U256.from_signed(remainder))
Exemple #5
0
def sdiv(evm: Evm) -> None:
    """
    Signed integer division of the top two elements of the stack. Pushes the
    result back on the stack.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `2`.
    OutOfGasError
        If `evm.gas_left` is less than `5`.
    """
    evm.gas_left = subtract_gas(evm.gas_left, GAS_LOW)

    dividend = pop(evm.stack).to_signed()
    divisor = pop(evm.stack).to_signed()

    if divisor == 0:
        quotient = 0
    elif dividend == -U255_CEIL_VALUE and divisor == -1:
        quotient = -U255_CEIL_VALUE
    else:
        sign = get_sign(dividend * divisor)
        quotient = sign * (abs(dividend) // abs(divisor))

    push(evm.stack, U256.from_signed(quotient))
Exemple #6
0
def div(evm: Evm) -> None:
    """
    Integer division of the top two elements of the stack. Pushes the result
    back on the stack.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `2`.
    OutOfGasError
        If `evm.gas_left` is less than `5`.
    """
    evm.gas_left = subtract_gas(evm.gas_left, GAS_LOW)

    dividend = pop(evm.stack)
    divisor = pop(evm.stack)
    if divisor == 0:
        quotient = U256(0)
    else:
        quotient = dividend // divisor

    push(evm.stack, quotient)
Exemple #7
0
def push_n(evm: Evm, num_bytes: int) -> None:
    """
    Pushes a N-byte immediate onto the stack.

    Parameters
    ----------
    evm :
        The current EVM frame.

    num_bytes :
        The number of immediate bytes to be read from the code and pushed to
        the stack.

    Raises
    ------
    StackOverflowError
        If `len(stack)` is equals `1024`.
    OutOfGasError
        If `evm.gas_left` is less than `3`.
    """
    assert evm.pc + num_bytes < len(evm.code)
    evm.gas_left = subtract_gas(evm.gas_left, GAS_VERY_LOW)

    data_to_push = U256.from_be_bytes(evm.code[evm.pc + 1:evm.pc + num_bytes +
                                               1])
    push(evm.stack, data_to_push)

    evm.pc += num_bytes
Exemple #8
0
def signextend(evm: Evm) -> None:
    """
    Sign extend operation. In other words, extend a signed number which
    fits in N bytes to 32 bytes.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `2`.
    OutOfGasError
        If `evm.gas_left` is less than `5`.
    """
    evm.gas_left = subtract_gas(evm.gas_left, GAS_LOW)

    # byte_num would be 0-indexed when inserted to the stack.
    byte_num = pop(evm.stack)
    value = pop(evm.stack)

    if byte_num > 31:
        # Can't extend any further
        result = value
    else:
        # U256(0).to_be_bytes() gives b'' instead b'\x00'. # noqa: SC100
        value_bytes = value.to_be_bytes() or b"\x00"

        # Now among the obtained value bytes, consider only
        # N `least significant bytes`, where N is `byte_num + 1`.
        value_bytes = value_bytes[len(value_bytes) - 1 - byte_num:]
        sign_bit = value_bytes[0] >> 7
        if sign_bit == 0:
            result = U256.from_be_bytes(value_bytes)
        else:
            num_bytes_prepend = 32 - (byte_num + 1)
            result = U256.from_be_bytes(
                bytearray([0xFF] * num_bytes_prepend) + value_bytes)

    push(evm.stack, result)
Exemple #9
0
def json_to_state(raw: Any) -> State:
    state = {}
    for (addr, acc_state) in raw.items():
        account = Account(
            nonce=hex2uint(acc_state.get("nonce", "0x0")),
            balance=hex2uint(acc_state.get("balance", "0x0")),
            code=hex2bytes(acc_state.get("code", "")),
            storage={},
        )

        for (k, v) in acc_state.get("storage", {}).items():
            account.storage[hex2bytes32(k)] = U256.from_be_bytes(
                hex2bytes32(v)
            )

        state[hex2address(addr)] = account

    return state
Exemple #10
0
def sstore(evm: Evm) -> None:
    """
    Stores a value at a certain key in the current context's storage.

    Parameters
    ----------
    evm :
        The current EVM frame.

    Raises
    ------
    StackUnderflowError
        If `len(stack)` is less than `2`.
    OutOfGasError
        If `evm.gas_left` is less than `20000`.
    """
    key = pop(evm.stack).to_be_bytes32()
    new_value = pop(evm.stack)
    current_value = evm.env.state[evm.current].storage.get(key, U256(0))

    # TODO: SSTORE gas usage hasn't been tested yet. Testing this needs
    # other opcodes to be implemented.
    # Calculating the gas needed for the storage
    if new_value != 0 and current_value == 0:
        gas_cost = GAS_STORAGE_SET
    else:
        gas_cost = GAS_STORAGE_UPDATE

    evm.gas_left = subtract_gas(evm.gas_left, gas_cost)

    # TODO: Refund counter hasn't been tested yet. Testing this needs other
    # Opcodes to be implemented
    if new_value == 0 and current_value != 0:
        evm.refund_counter += GAS_STORAGE_CLEAR_REFUND

    if new_value == 0:
        # Deletes a k-v pair from dict if key is present, else does nothing
        evm.env.state[evm.current].storage.pop(key, None)
    else:
        evm.env.state[evm.current].storage[key] = new_value
Exemple #11
0
def test_u256_to_be_bytes32_max_value() -> None:
    encoded = U256(2**256 - 1).to_be_bytes32()
    assert encoded == bytes([
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
        0xFF,
    ])
Exemple #12
0
def test_u256_rdivmod_overflow() -> None:
    with pytest.raises(ValueError):
        divmod(2**256, U256(2))
Exemple #13
0
def test_u256_rdivmod_negative() -> None:
    with pytest.raises(ValueError):
        divmod(-5, U256(2))
Exemple #14
0
def test_u256_divmod_negative() -> None:
    with pytest.raises(ValueError):
        divmod(U256(5), -2)
Exemple #15
0
def test_u256_divmod_float() -> None:
    quotient, remainder = divmod(U256(5), 2.0)
    assert not isinstance(quotient, U256)
    assert not isinstance(remainder, U256)
    assert quotient == 2
    assert remainder == 1
Exemple #16
0
def test_u256_rdivmod_float() -> None:
    quotient, remainder = divmod(5.0, U256(2))
    assert not isinstance(quotient, U256)
    assert not isinstance(remainder, U256)
    assert quotient == 2
    assert remainder == 1
Exemple #17
0
def test_u256_rpow_overflow() -> None:
    with pytest.raises(ValueError):
        (2**256)**U256(2)
Exemple #18
0
def test_u256_pow_modulo_negative() -> None:
    with pytest.raises(ValueError):
        pow(U256(4), 2, -3)
Exemple #19
0
def test_u256_pow_modulo() -> None:
    value = pow(U256(4), 2, 3)
    assert isinstance(value, U256)
    assert value == 1
Exemple #20
0
def test_u256_pow_overflow() -> None:
    with pytest.raises(ValueError):
        U256(340282366920938463463374607431768211456)**3
Exemple #21
0
def test_u256_pow() -> None:
    value = U256(3)**2
    assert isinstance(value, U256)
    assert value == 9
Exemple #22
0
def test_u256_imod() -> None:
    value = U256(5)
    value %= 4
    assert isinstance(value, U256)
    assert value == 1
Exemple #23
0
def test_u256_pow_negative() -> None:
    with pytest.raises(ValueError):
        U256(3)**-2
Exemple #24
0
def test_u256_imod_overflow() -> None:
    value = U256(5)
    with pytest.raises(ValueError):
        value %= 2**256
Exemple #25
0
def test_u256_pow_modulo_overflow() -> None:
    with pytest.raises(ValueError):
        pow(U256(4), 2, 2**257)
Exemple #26
0
def test_u256_imod_negative() -> None:
    value = U256(5)
    with pytest.raises(ValueError):
        value %= -4
Exemple #27
0
def test_u256_rpow() -> None:
    value = 3**U256(2)
    assert isinstance(value, U256)
    assert value == 9
Exemple #28
0
def test_u256_imod_float() -> None:
    value = U256(5)
    value %= 1.0  # type: ignore
    assert not isinstance(value, int)
    assert value == 0.0
Exemple #29
0
.. contents:: Table of Contents
    :backlinks: none
    :local:

Introduction
------------

EVM gas constants and calculators.
"""

from ethereum.base_types import U256

from .error import OutOfGasError

GAS_VERY_LOW = U256(3)
GAS_STORAGE_SET = U256(20000)
GAS_STORAGE_UPDATE = U256(5000)
GAS_STORAGE_CLEAR_REFUND = U256(15000)
GAS_LOW = U256(5)
GAS_MID = U256(8)
GAS_EXPONENTIATION = U256(10)


def subtract_gas(gas_left: U256, amount: U256) -> U256:
    """
    Subtracts `amount` from `gas_left`.

    Parameters
    ----------
    gas_left :
Exemple #30
0
def test_u256_divmod_overflow() -> None:
    with pytest.raises(ValueError):
        divmod(U256(5), 2**256)