Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 44 additions & 15 deletions src/ethereum/frontier/vm/instructions/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
from ethereum.base_types import U256, Uint
from ethereum.frontier.state import get_account
from ethereum.frontier.utils.address import to_address
from ethereum.frontier.vm.error import OutOfGasError
from ethereum.frontier.vm.memory import extend_memory, memory_write
from ethereum.utils.numeric import ceil32
from ethereum.utils.safe_arithmetic import u256_safe_add, u256_safe_multiply

from .. import Evm
from ..gas import (
Expand Down Expand Up @@ -202,12 +204,21 @@ def calldatacopy(evm: Evm) -> None:
size = pop(evm.stack)

words = ceil32(Uint(size)) // 32
gas_cost = (
GAS_VERY_LOW
+ (GAS_COPY * words)
+ calculate_gas_extend_memory(evm.memory, memory_start_index, size)
copy_gas_cost = u256_safe_multiply(
GAS_COPY,
words,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, gas_cost)
memory_extend_gas_cost = calculate_gas_extend_memory(
evm.memory, memory_start_index, size
)
total_gas_cost = u256_safe_add(
GAS_VERY_LOW,
copy_gas_cost,
memory_extend_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)

if size == 0:
return
Expand Down Expand Up @@ -264,12 +275,21 @@ def codecopy(evm: Evm) -> None:
size = pop(evm.stack)

words = ceil32(Uint(size)) // 32
gas_cost = (
GAS_VERY_LOW
+ (GAS_COPY * words)
+ calculate_gas_extend_memory(evm.memory, memory_start_index, size)
copy_gas_cost = u256_safe_multiply(
GAS_COPY,
words,
exception_type=OutOfGasError,
)
memory_extend_gas_cost = calculate_gas_extend_memory(
evm.memory, memory_start_index, size
)
evm.gas_left = subtract_gas(evm.gas_left, gas_cost)
total_gas_cost = u256_safe_add(
GAS_VERY_LOW,
copy_gas_cost,
memory_extend_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)

if size == 0:
return
Expand Down Expand Up @@ -355,12 +375,21 @@ def extcodecopy(evm: Evm) -> None:
size = pop(evm.stack)

words = ceil32(Uint(size)) // 32
gas_cost = (
GAS_EXTERNAL
+ (GAS_COPY * words)
+ calculate_gas_extend_memory(evm.memory, memory_start_index, size)
copy_gas_cost = u256_safe_multiply(
GAS_COPY,
words,
exception_type=OutOfGasError,
)
memory_extend_gas_cost = calculate_gas_extend_memory(
evm.memory, memory_start_index, size
)
total_gas_cost = u256_safe_add(
GAS_EXTERNAL,
copy_gas_cost,
memory_extend_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, gas_cost)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)

if size == 0:
return
Expand Down
21 changes: 16 additions & 5 deletions src/ethereum/frontier/vm/instructions/keccak.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

from ethereum.base_types import U256, Uint
from ethereum.crypto import keccak256
from ethereum.frontier.vm.error import OutOfGasError
from ethereum.utils.numeric import ceil32
from ethereum.utils.safe_arithmetic import u256_safe_add, u256_safe_multiply

from .. import Evm
from ..gas import (
Expand Down Expand Up @@ -50,12 +52,21 @@ def keccak(evm: Evm) -> None:
size = pop(evm.stack)

words = ceil32(Uint(size)) // 32
gas_cost = (
GAS_KECCAK256
+ (GAS_KECCAK256_WORD * words)
+ calculate_gas_extend_memory(evm.memory, memory_start_index, size)
word_gas_cost = u256_safe_multiply(
GAS_KECCAK256_WORD,
words,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, gas_cost)
memory_extend_gas_cost = calculate_gas_extend_memory(
evm.memory, memory_start_index, size
)
total_gas_cost = u256_safe_add(
GAS_KECCAK256,
word_gas_cost,
memory_extend_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)

extend_memory(evm.memory, memory_start_index, size)

Expand Down
32 changes: 23 additions & 9 deletions src/ethereum/frontier/vm/instructions/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
Implementations of the EVM Memory instructions.
"""
from ethereum.base_types import U8_MAX_VALUE, U256, Uint
from ethereum.frontier.vm.error import OutOfGasError
from ethereum.utils.safe_arithmetic import u256_safe_add

from .. import Evm
from ..gas import (
Expand Down Expand Up @@ -47,9 +49,13 @@ def mstore(evm: Evm) -> None:
start_position = Uint(pop(evm.stack))
value = pop(evm.stack).to_be_bytes32()

total_gas_cost = (
calculate_gas_extend_memory(evm.memory, start_position, U256(32))
+ GAS_VERY_LOW
gas_cost_memory_extend = calculate_gas_extend_memory(
evm.memory, start_position, U256(32)
)
total_gas_cost = u256_safe_add(
GAS_VERY_LOW,
gas_cost_memory_extend,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)

Expand Down Expand Up @@ -83,9 +89,13 @@ def mstore8(evm: Evm) -> None:
# make sure that value doesn't exceed 1 byte
normalized_bytes_value = (value & U8_MAX_VALUE).to_be_bytes()

total_gas_cost = (
calculate_gas_extend_memory(evm.memory, start_position, U256(1))
+ GAS_VERY_LOW
memory_extend_gas_cost = calculate_gas_extend_memory(
evm.memory, start_position, U256(1)
)
total_gas_cost = u256_safe_add(
GAS_VERY_LOW,
memory_extend_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)

Expand Down Expand Up @@ -114,9 +124,13 @@ def mload(evm: Evm) -> None:
# convert to Uint as start_position + size_to_extend can overflow.
start_position = Uint(pop(evm.stack))

total_gas_cost = (
calculate_gas_extend_memory(evm.memory, start_position, U256(32))
+ GAS_VERY_LOW
memory_extend_gas_cost = calculate_gas_extend_memory(
evm.memory, start_position, U256(32)
)
total_gas_cost = u256_safe_add(
GAS_VERY_LOW,
memory_extend_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)

Expand Down
23 changes: 19 additions & 4 deletions src/ethereum/frontier/vm/instructions/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
Implementations of the EVM system related instructions.
"""
from ethereum.base_types import U256, Uint
from ethereum.frontier.vm.error import OutOfGasError
from ethereum.utils.safe_arithmetic import u256_safe_add

from ...state import get_account, increment_nonce, set_account_balance
from ...utils.address import compute_contract_address, to_address
Expand Down Expand Up @@ -45,10 +47,15 @@ def create(evm: Evm) -> None:
memory_start_position = Uint(pop(evm.stack))
memory_size = pop(evm.stack)

gas_cost = GAS_CREATE + calculate_gas_extend_memory(
extend_memory_gas_cost = calculate_gas_extend_memory(
evm.memory, memory_start_position, memory_size
)
evm.gas_left = subtract_gas(evm.gas_left, gas_cost)
total_gas_cost = u256_safe_add(
GAS_CREATE,
extend_memory_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)
extend_memory(evm.memory, memory_start_position, memory_size)
sender_address = evm.env.origin
sender = get_account(evm.env.state, sender_address)
Expand Down Expand Up @@ -141,7 +148,11 @@ def call(evm: Evm) -> None:
memory_output_size = pop(evm.stack)

call_gas_fee = calculate_call_gas_cost(evm.env.state, gas, to, value)
message_call_gas_fee = gas + calculate_message_call_gas_stipend(value)
message_call_gas_fee = u256_safe_add(
gas,
calculate_message_call_gas_stipend(value),
exception_type=OutOfGasError,
)

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

Expand Down Expand Up @@ -225,7 +236,11 @@ def callcode(evm: Evm) -> None:
to = evm.message.current_target

call_gas_fee = calculate_call_gas_cost(evm.env.state, gas, to, value)
message_call_gas_fee = gas + calculate_message_call_gas_stipend(value)
message_call_gas_fee = u256_safe_add(
gas,
calculate_message_call_gas_stipend(value),
exception_type=OutOfGasError,
)

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

Expand Down
15 changes: 13 additions & 2 deletions src/ethereum/frontier/vm/precompiled_contracts/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
Implementation of the `IDENTITY` precompiled contract.
"""
from ethereum.base_types import Uint
from ethereum.frontier.vm.error import OutOfGasError
from ethereum.utils.numeric import ceil32
from ethereum.utils.safe_arithmetic import u256_safe_add, u256_safe_multiply

from ...vm import Evm
from ...vm.gas import GAS_IDENTITY, GAS_IDENTITY_WORD, subtract_gas
Expand All @@ -29,6 +31,15 @@ def identity(evm: Evm) -> None:
"""
data = evm.message.data
word_count = ceil32(Uint(len(data))) // 32
gas_fee = GAS_IDENTITY + word_count * GAS_IDENTITY_WORD
evm.gas_left = subtract_gas(evm.gas_left, gas_fee)
word_count_gas_cost = u256_safe_multiply(
word_count,
GAS_IDENTITY_WORD,
exception_type=OutOfGasError,
)
total_gas_cost = u256_safe_add(
GAS_IDENTITY,
word_count_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)
evm.output = data
15 changes: 13 additions & 2 deletions src/ethereum/frontier/vm/precompiled_contracts/ripemd160.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
import hashlib

from ethereum.base_types import Uint
from ethereum.frontier.vm.error import OutOfGasError
from ethereum.utils.byte import left_pad_zero_bytes
from ethereum.utils.numeric import ceil32
from ethereum.utils.safe_arithmetic import u256_safe_add, u256_safe_multiply

from ...vm import Evm
from ...vm.gas import GAS_RIPEMD160, GAS_RIPEMD160_WORD, subtract_gas
Expand All @@ -32,8 +34,17 @@ def ripemd160(evm: Evm) -> None:
"""
data = evm.message.data
word_count = ceil32(Uint(len(data))) // 32
gas_fee = GAS_RIPEMD160 + word_count * GAS_RIPEMD160_WORD
evm.gas_left = subtract_gas(evm.gas_left, gas_fee)
word_count_gas_cost = u256_safe_multiply(
word_count,
GAS_RIPEMD160_WORD,
exception_type=OutOfGasError,
)
total_gas_cost = u256_safe_add(
GAS_RIPEMD160,
word_count_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)
hash_bytes = hashlib.new("ripemd160", data).digest()
padded_hash = left_pad_zero_bytes(hash_bytes, 32)
evm.output = padded_hash
15 changes: 13 additions & 2 deletions src/ethereum/frontier/vm/precompiled_contracts/sha256.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
import hashlib

from ethereum.base_types import Uint
from ethereum.frontier.vm.error import OutOfGasError
from ethereum.utils.numeric import ceil32
from ethereum.utils.safe_arithmetic import u256_safe_add, u256_safe_multiply

from ...vm import Evm
from ...vm.gas import GAS_SHA256, GAS_SHA256_WORD, subtract_gas
Expand All @@ -31,6 +33,15 @@ def sha256(evm: Evm) -> None:
"""
data = evm.message.data
word_count = ceil32(Uint(len(data))) // 32
gas_fee = GAS_SHA256 + word_count * GAS_SHA256_WORD
evm.gas_left = subtract_gas(evm.gas_left, gas_fee)
word_count_gas_cost = u256_safe_multiply(
word_count,
GAS_SHA256_WORD,
exception_type=OutOfGasError,
)
total_gas_cost = u256_safe_add(
GAS_SHA256,
word_count_gas_cost,
exception_type=OutOfGasError,
)
evm.gas_left = subtract_gas(evm.gas_left, total_gas_cost)
evm.output = hashlib.sha256(data).digest()
12 changes: 7 additions & 5 deletions src/ethereum/utils/safe_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@

Safe arithmetic utility functions for U256 integer type.
"""
from typing import Optional, Type
from typing import Optional, Type, Union

from ethereum.base_types import U256
from ethereum.base_types import U256, Uint


def u256_safe_add(
*numbers: U256, exception_type: Optional[Type[BaseException]] = None
*numbers: Union[U256, Uint],
exception_type: Optional[Type[BaseException]] = None
) -> U256:
"""
Adds together the given sequence of numbers. If the total sum of the
Expand Down Expand Up @@ -54,7 +55,8 @@ def u256_safe_add(


def u256_safe_multiply(
*numbers: U256, exception_type: Optional[Type[BaseException]] = None
*numbers: Union[U256, Uint],
exception_type: Optional[Type[BaseException]] = None
) -> U256:
"""
Multiplies together the given sequence of numbers. If the net product of
Expand Down Expand Up @@ -85,7 +87,7 @@ def u256_safe_multiply(
try:
for number in numbers[1:]:
result *= number
return result
return U256(result)
except ValueError as e:
if exception_type:
raise exception_type from e
Expand Down