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
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
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
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
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 fifth 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)
155 changes: 155 additions & 0 deletions src/ethereum/spurious_dragon/eth_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
"""
Ethereum Types
^^^^^^^^^^^^^^

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

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

Types re-used throughout the specification, which are specific to Ethereum.
"""

from dataclasses import dataclass
from typing import Tuple, Union

from .. import rlp
from ..base_types import (
U256,
Bytes,
Bytes0,
Bytes8,
Bytes20,
Bytes32,
Bytes256,
Uint,
slotted_freezable,
)
from ..crypto import Hash32, keccak256

Address = Bytes20
Root = Hash32

Bloom = Bytes256

TX_BASE_COST = 21000
TX_DATA_COST_PER_NON_ZERO = 68
TX_DATA_COST_PER_ZERO = 4
TX_CREATE_COST = 32000


@slotted_freezable
@dataclass
class Transaction:
"""
Atomic operation performed on the block chain.
"""

nonce: U256
gas_price: U256
gas: U256
to: Union[Bytes0, Address]
value: U256
data: Bytes
v: U256
r: U256
s: U256


@slotted_freezable
@dataclass
class Account:
"""
State associated with an address.
"""

nonce: Uint
balance: U256
code: bytes


EMPTY_ACCOUNT = Account(
nonce=Uint(0),
balance=U256(0),
code=bytearray(),
)


def encode_account(raw_account_data: Account, storage_root: Bytes) -> Bytes:
"""
Encode `Account` dataclass.

Storage is not stored in the `Account` dataclass, so `Accounts` cannot be
encoded with providing a storage root.
"""
return rlp.encode(
(
raw_account_data.nonce,
raw_account_data.balance,
storage_root,
keccak256(raw_account_data.code),
)
)


@slotted_freezable
@dataclass
class Header:
"""
Header portion of a block on the chain.
"""

parent_hash: Hash32
ommers_hash: Hash32
coinbase: Address
state_root: Root
transactions_root: Root
receipt_root: Root
bloom: Bloom
difficulty: Uint
number: Uint
gas_limit: Uint
gas_used: Uint
timestamp: U256
extra_data: Bytes
mix_digest: Bytes32
nonce: Bytes8


@slotted_freezable
@dataclass
class Block:
"""
A complete block.
"""

header: Header
transactions: Tuple[Transaction, ...]
ommers: Tuple[Header, ...]


@slotted_freezable
@dataclass
class Log:
"""
Data record produced during the execution of a transaction.
"""

address: Address
topics: Tuple[Hash32, ...]
data: bytes


@slotted_freezable
@dataclass
class Receipt:
"""
Result of a transaction.
"""

post_state: Root
cumulative_gas_used: Uint
bloom: Bloom
logs: Tuple[Log, ...]
Loading