Skip to content
6 changes: 6 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ packages =
ethereum/tangerine_whistle/vm/instructions
ethereum/tangerine_whistle/vm/precompiled_contracts
ethereum_optimized/tangerine_whistle
ethereum/spurious_dragon
ethereum/spurious_dragon/utils
ethereum/spurious_dragon/vm
ethereum/spurious_dragon/vm/instructions
ethereum/spurious_dragon/vm/precompiled_contracts
ethereum_optimized/spurious_dragon

package_dir =
=src
Expand Down
1 change: 1 addition & 0 deletions src/ethereum/dao_fork/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
"""

MAINNET_FORK_BLOCK = 1920000
CHAIN_ID = 1
31 changes: 28 additions & 3 deletions src/ethereum/dao_fork/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,33 @@ def set_account(
state: State, address: Address, account: Optional[Account]
) -> None:
"""
Set the `Account` object at an address. Setting to `None` deletes
the account (but not its storage, see `destroy_account()`).
Set the `Account` object at an address.

You may delete an account with this function even if it has storage.

Parameters
----------
state: `State`
The state
address : `Address`
Address to set.
account : `Account`
Account to set at address.
"""
if account is None:
destroy_account(state, address)
else:
set_account_internal(state, address, account)


def set_account_internal(
state: State, address: Address, account: Optional[Account]
) -> None:
"""
Set the `Account` object at an address.

You must not set an account to `None` with this function if it has non-zero
storage keys (use `destroy_account()`).

Parameters
----------
Expand Down Expand Up @@ -184,7 +209,7 @@ def destroy_account(state: State, address: Address) -> None:
"""
if address in state._storage_tries:
del state._storage_tries[address]
set_account(state, address, None)
set_account_internal(state, address, None)


def get_storage(state: State, address: Address, key: Bytes) -> U256:
Expand Down
1 change: 1 addition & 0 deletions src/ethereum/dao_fork/vm/gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
GAS_MID = U256(8)
GAS_HIGH = U256(10)
GAS_EXPONENTIATION = U256(10)
GAS_EXPONENTIATION_PER_BYTE = U256(10)
GAS_MEMORY = U256(3)
GAS_KECCAK256 = U256(30)
GAS_KECCAK256_WORD = U256(6)
Expand Down
3 changes: 2 additions & 1 deletion src/ethereum/dao_fork/vm/instructions/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .. import Evm
from ..gas import (
GAS_EXPONENTIATION,
GAS_EXPONENTIATION_PER_BYTE,
GAS_LOW,
GAS_MID,
GAS_VERY_LOW,
Expand Down Expand Up @@ -329,7 +330,7 @@ def exp(evm: Evm) -> None:
# function is inaccurate leading to wrong results.
exponent_bits = exponent.bit_length()
exponent_bytes = (exponent_bits + 7) // 8
gas_used += GAS_EXPONENTIATION * exponent_bytes
gas_used += GAS_EXPONENTIATION_PER_BYTE * exponent_bytes
evm.gas_left = subtract_gas(evm.gas_left, gas_used)

result = U256(pow(base, exponent, U256_CEIL_VALUE))
Expand Down
1 change: 1 addition & 0 deletions src/ethereum/frontier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
"""

MAINNET_FORK_BLOCK = 0
CHAIN_ID = 1
31 changes: 28 additions & 3 deletions src/ethereum/frontier/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,33 @@ def set_account(
state: State, address: Address, account: Optional[Account]
) -> None:
"""
Set the `Account` object at an address. Setting to `None` deletes
the account (but not its storage, see `destroy_account()`).
Set the `Account` object at an address.

You may delete an account with this function even if it has storage.

Parameters
----------
state: `State`
The state
address : `Address`
Address to set.
account : `Account`
Account to set at address.
"""
if account is None:
destroy_account(state, address)
else:
set_account_internal(state, address, account)


def set_account_internal(
state: State, address: Address, account: Optional[Account]
) -> None:
"""
Set the `Account` object at an address.

You must not set an account to `None` with this function if it has non-zero
storage keys (use `destroy_account()`).

Parameters
----------
Expand Down Expand Up @@ -184,7 +209,7 @@ def destroy_account(state: State, address: Address) -> None:
"""
if address in state._storage_tries:
del state._storage_tries[address]
set_account(state, address, None)
set_account_internal(state, address, None)


def get_storage(state: State, address: Address, key: Bytes) -> U256:
Expand Down
1 change: 1 addition & 0 deletions src/ethereum/frontier/vm/gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
GAS_MID = U256(8)
GAS_HIGH = U256(10)
GAS_EXPONENTIATION = U256(10)
GAS_EXPONENTIATION_PER_BYTE = U256(10)
GAS_MEMORY = U256(3)
GAS_KECCAK256 = U256(30)
GAS_KECCAK256_WORD = U256(6)
Expand Down
3 changes: 2 additions & 1 deletion src/ethereum/frontier/vm/instructions/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .. import Evm
from ..gas import (
GAS_EXPONENTIATION,
GAS_EXPONENTIATION_PER_BYTE,
GAS_LOW,
GAS_MID,
GAS_VERY_LOW,
Expand Down Expand Up @@ -329,7 +330,7 @@ def exp(evm: Evm) -> None:
# function is inaccurate leading to wrong results.
exponent_bits = exponent.bit_length()
exponent_bytes = (exponent_bits + 7) // 8
gas_used += GAS_EXPONENTIATION * exponent_bytes
gas_used += GAS_EXPONENTIATION_PER_BYTE * exponent_bytes
evm.gas_left = subtract_gas(evm.gas_left, gas_used)

result = U256(pow(base, exponent, U256_CEIL_VALUE))
Expand Down
1 change: 1 addition & 0 deletions src/ethereum/homestead/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
"""

MAINNET_FORK_BLOCK = 1150000
CHAIN_ID = 1
31 changes: 28 additions & 3 deletions src/ethereum/homestead/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,33 @@ def set_account(
state: State, address: Address, account: Optional[Account]
) -> None:
"""
Set the `Account` object at an address. Setting to `None` deletes
the account (but not its storage, see `destroy_account()`).
Set the `Account` object at an address.

You may delete an account with this function even if it has storage.

Parameters
----------
state: `State`
The state
address : `Address`
Address to set.
account : `Account`
Account to set at address.
"""
if account is None:
destroy_account(state, address)
else:
set_account_internal(state, address, account)


def set_account_internal(
state: State, address: Address, account: Optional[Account]
) -> None:
"""
Set the `Account` object at an address.

You must not set an account to `None` with this function if it has non-zero
storage keys (use `destroy_account()`).

Parameters
----------
Expand Down Expand Up @@ -184,7 +209,7 @@ def destroy_account(state: State, address: Address) -> None:
"""
if address in state._storage_tries:
del state._storage_tries[address]
set_account(state, address, None)
set_account_internal(state, address, None)


def get_storage(state: State, address: Address, key: Bytes) -> U256:
Expand Down
1 change: 1 addition & 0 deletions src/ethereum/homestead/vm/gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
GAS_MID = U256(8)
GAS_HIGH = U256(10)
GAS_EXPONENTIATION = U256(10)
GAS_EXPONENTIATION_PER_BYTE = U256(10)
GAS_MEMORY = U256(3)
GAS_KECCAK256 = U256(30)
GAS_KECCAK256_WORD = U256(6)
Expand Down
3 changes: 2 additions & 1 deletion src/ethereum/homestead/vm/instructions/arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .. import Evm
from ..gas import (
GAS_EXPONENTIATION,
GAS_EXPONENTIATION_PER_BYTE,
GAS_LOW,
GAS_MID,
GAS_VERY_LOW,
Expand Down Expand Up @@ -329,7 +330,7 @@ def exp(evm: Evm) -> None:
# function is inaccurate leading to wrong results.
exponent_bits = exponent.bit_length()
exponent_bytes = (exponent_bits + 7) // 8
gas_used += GAS_EXPONENTIATION * exponent_bytes
gas_used += GAS_EXPONENTIATION_PER_BYTE * exponent_bytes
evm.gas_left = subtract_gas(evm.gas_left, gas_used)

result = U256(pow(base, exponent, U256_CEIL_VALUE))
Expand Down
9 changes: 9 additions & 0 deletions src/ethereum/spurious_dragon/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""
Ethereum Spurious Dragon Hardfork
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The fourth Ethereum hardfork.
"""

MAINNET_FORK_BLOCK = 2675000
CHAIN_ID = 1
76 changes: 76 additions & 0 deletions src/ethereum/spurious_dragon/bloom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""
Ethereum Logs Bloom
^^^^^^^^^^^^^^^^^^^

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

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

Logs Bloom related functionalities used in Ethereum.
"""

from typing import Tuple

from ethereum.base_types import Uint
from ethereum.crypto import keccak256

from .eth_types import Bloom, Log


def add_to_bloom(bloom: bytearray, bloom_entry: bytes) -> None:
"""
Add a bloom entry to the bloom filter (`bloom`).

Parameters
----------
bloom :
The bloom filter.
bloom_entry :
An entry which is to be added to bloom filter.
"""
# TODO: This functionality hasn't been tested rigorously yet.
hash = keccak256(bloom_entry)

for idx in (0, 2, 4):
# Obtain the least significant 11 bits from the pair of bytes
# (16 bits), and set this bit in bloom bytearray.
# The obtained bit is 0-indexed in the bloom filter from the least
# significant bit to the most significant bit.
bit_to_set = Uint.from_be_bytes(hash[idx : idx + 2]) & 0x07FF
# Below is the index of the bit in the bytearray (where 0-indexed
# byte is the most significant byte)
bit_index = 0x07FF - bit_to_set

byte_index = bit_index // 8
bit_value = 1 << (7 - (bit_index % 8))
bloom[byte_index] = bloom[byte_index] | bit_value


def logs_bloom(logs: Tuple[Log, ...]) -> Bloom:
"""
Obtain the logs bloom from a list of log entries.

Parameters
----------
logs :
List of logs for which the logs bloom is to be obtained.

Returns
-------
logs_bloom : `Bloom`
The logs bloom obtained which is 256 bytes with some bits set as per
the caller address and the log topics.
"""
# TODO: Logs bloom functionality hasn't been tested rigorously yet. The
# required test cases need `CALL` opcode to be implemented.
bloom: bytearray = bytearray(b"\x00" * 256)

for log in logs:
add_to_bloom(bloom, log.address)
for topic in log.topics:
add_to_bloom(bloom, topic)

return Bloom(bloom)
Loading