示例#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)
示例#2
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)
示例#3
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)
示例#4
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)
示例#5
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
示例#6
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,
    ])
示例#7
0
def test_u256_rpow_overflow() -> None:
    with pytest.raises(ValueError):
        (2**256)**U256(2)
示例#8
0
def test_u256_pow_modulo_negative() -> None:
    with pytest.raises(ValueError):
        pow(U256(4), 2, -3)
示例#9
0
def test_u256_pow_modulo() -> None:
    value = pow(U256(4), 2, 3)
    assert isinstance(value, U256)
    assert value == 1
示例#10
0
def test_u256_pow_overflow() -> None:
    with pytest.raises(ValueError):
        U256(340282366920938463463374607431768211456)**3
示例#11
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
示例#12
0
def test_u256_rdivmod_overflow() -> None:
    with pytest.raises(ValueError):
        divmod(2**256, U256(2))
示例#13
0
def test_u256_mod_overflow() -> None:
    with pytest.raises(ValueError):
        U256(5) % (2**256)
示例#14
0
def test_u256_rmod_float() -> None:
    value = (6.0) % U256(5)
    assert not isinstance(value, int)
    assert value == 1.0
示例#15
0
def test_u256_rmod() -> None:
    value = 6 % U256(5)
    assert isinstance(value, U256)
    assert value == 1
示例#16
0
def test_u256_divmod_negative() -> None:
    with pytest.raises(ValueError):
        divmod(U256(5), -2)
示例#17
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
示例#18
0
def test_u256_mod_negative() -> None:
    with pytest.raises(ValueError):
        U256(5) % (-4)
示例#19
0
def test_u256_rdivmod_negative() -> None:
    with pytest.raises(ValueError):
        divmod(-5, U256(2))
示例#20
0
def test_u256_mod_float() -> None:
    value = U256(5) % (1.0)
    assert not isinstance(value, int)
    assert value == 0.0
示例#21
0
def test_u256_pow() -> None:
    value = U256(3)**2
    assert isinstance(value, U256)
    assert value == 9
示例#22
0
def test_u256_imod() -> None:
    value = U256(5)
    value %= 4
    assert isinstance(value, U256)
    assert value == 1
示例#23
0
def test_u256_pow_negative() -> None:
    with pytest.raises(ValueError):
        U256(3)**-2
示例#24
0
def test_u256_imod_overflow() -> None:
    value = U256(5)
    with pytest.raises(ValueError):
        value %= 2**256
示例#25
0
def test_u256_pow_modulo_overflow() -> None:
    with pytest.raises(ValueError):
        pow(U256(4), 2, 2**257)
示例#26
0
def test_u256_imod_negative() -> None:
    value = U256(5)
    with pytest.raises(ValueError):
        value %= -4
示例#27
0
def test_u256_rpow() -> None:
    value = 3**U256(2)
    assert isinstance(value, U256)
    assert value == 9
示例#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
示例#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 :
示例#30
0
def test_u256_divmod_overflow() -> None:
    with pytest.raises(ValueError):
        divmod(U256(5), 2**256)