Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for ethereum/execution-specs (eels) #445

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
Empty file added runners/eels/README.md
Empty file.
10 changes: 10 additions & 0 deletions runners/eels/cpython/entry
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euf -o pipefail

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

cd $SCRIPT_DIR
poetry env use python3 >&2
poetry install >&2
poetry update >&2
exec poetry run python -O ../runner.py $@
5 changes: 5 additions & 0 deletions runners/eels/cpython/runner.evm-bench.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "../../schema.json",
"name": "eels.cpython",
"entry": "entry"
}
893 changes: 893 additions & 0 deletions runners/eels/poetry.lock

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions runners/eels/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[tool.poetry]
name = "eels"
version = "0.1.0"
description = "Runner for the Ethereum execution specs"
authors = ["Sam Wilson <sam@binarycake.ca>"]
readme = "README.md"
package-mode = false

[tool.poetry.dependencies]
python = "^3.10"
coincurve = "^20.0.0"
ethereum = {git = "https://github.com/ethereum/execution-specs.git"}


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
10 changes: 10 additions & 0 deletions runners/eels/pypy/entry
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euf -o pipefail

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

cd $SCRIPT_DIR
poetry env use pypy3 >&2
poetry install >&2
poetry update >&2
exec poetry run python -O ../runner.py $@
5 changes: 5 additions & 0 deletions runners/eels/pypy/runner.evm-bench.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "../../schema.json",
"name": "eels.pypy",
"entry": "entry"
}
109 changes: 109 additions & 0 deletions runners/eels/runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import argparse
import pathlib
import timeit
from typing import Final

from coincurve import PrivateKey
from ethereum.base_types import U64, U256, Bytes0, Bytes32, Uint
from ethereum.cancun.fork import process_transaction
from ethereum.cancun.fork_types import Address
from ethereum.cancun.state import State, TransientStorage
from ethereum.cancun.transactions import LegacyTransaction
from ethereum.cancun.utils.address import compute_contract_address
from ethereum.cancun.vm import Environment
from ethereum.crypto.hash import keccak256

ZERO: Final[Address] = Address(b"\0" * 20)
GAS_LIMIT: Final[Uint] = Uint(1_000_000_000_000_000_000)
SENDER_SECRET: Final[bytes] = bytes.fromhex(
"45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
)
SENDER_PRIVATE_KEY: Final[PrivateKey] = PrivateKey(SENDER_SECRET)
SENDER: Final[Address] = Address(
keccak256(SENDER_PRIVATE_KEY.public_key.format(compressed=False)[1:])[12:32]
)


def _load_contract_data(data_file_path: pathlib.Path) -> bytes:
with open(data_file_path, mode="r") as file:
return bytes.fromhex(file.read())


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--contract-code-path", type=pathlib.Path)
parser.add_argument("--calldata", type=str)
parser.add_argument("--num-runs", type=int)
return parser.parse_args()


def main() -> None:
args = parse_args()

contract_data = _load_contract_data(args.contract_code_path)
calldata = bytes.fromhex(args.calldata)

state = State()

env = Environment(
caller=SENDER,
origin=SENDER,
block_hashes=[],
coinbase=ZERO,
number=Uint(0),
gas_limit=GAS_LIMIT,
base_fee_per_gas=Uint(0),
gas_price=Uint(0),
time=U256(0),
state=state,
chain_id=U64(1),
traces=[],
prev_randao=Bytes32([0] * 32),
excess_blob_gas=U64(0),
blob_versioned_hashes=(),
transient_storage=TransientStorage(),
)

tx = LegacyTransaction(
nonce=U256(0),
gas_price=Uint(0),
gas=GAS_LIMIT,
to=Bytes0(),
value=U256(0),
data=contract_data,
v=U256(0),
r=U256(0),
s=U256(0),
)

gas_used, logs, error = process_transaction(env, tx)
if error is not None:
raise error

contract = compute_contract_address(SENDER, Uint(tx.nonce))

tx = LegacyTransaction(
nonce=U256(0),
gas_price=Uint(0),
gas=GAS_LIMIT,
to=contract,
value=U256(0),
data=calldata,
v=U256(0),
r=U256(0),
s=U256(0),
)

def bench():
gas_used, logs, error = process_transaction(env, tx)
if error is not None:
raise error

results = timeit.repeat(bench, number=1, repeat=args.num_runs)

for result in results:
print(result * 1000)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion runners/py-evm/cpython/entry.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ cd $SCRIPT_DIR
poetry env use python3 >&2
poetry install >&2
poetry update >&2
poetry run python ../runner.py $@
poetry run python -O ../runner.py $@
711 changes: 394 additions & 317 deletions runners/py-evm/poetry.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion runners/py-evm/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ authors = ["Ziyad Edher <ziyad.edher@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.9"
py-evm = "^0.6.0-alpha.1"
py-evm = "^0.10.1-beta.1"
setuptools = "^70.1.1"

[tool.poetry.dev-dependencies]
mypy = "^1.0.0"
Expand Down
2 changes: 1 addition & 1 deletion runners/py-evm/pypy/entry.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ cd $SCRIPT_DIR
poetry env use pypy3 >&2
poetry install >&2
poetry update >&2
poetry run python ../runner.py $@
poetry run python -O ../runner.py $@
27 changes: 17 additions & 10 deletions runners/py-evm/runner.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import cast, Final

import timeit
import argparse
import pathlib
import time

import eth.abc
import eth.consensus.pow
Expand All @@ -16,6 +16,7 @@
import eth_utils


GAS_PRICE: Final[int] = 875_000_000
GAS_LIMIT: Final[int] = 1_000_000_000
ZERO_ADDRESS: Final[eth_typing.Address] = eth.constants.ZERO_ADDRESS

Expand All @@ -38,15 +39,23 @@ def _construct_chain() -> eth.chains.base.MiningChain:
chain_class = eth.chains.base.MiningChain.configure(
__name__="TestChain",
vm_configuration=(
(eth.constants.GENESIS_BLOCK_NUMBER, eth.vm.forks.berlin.BerlinVM),
(eth.constants.GENESIS_BLOCK_NUMBER, eth.vm.forks.cancun.CancunVM),
),
)
chain = chain_class.from_genesis(
eth.db.atomic.AtomicDB(),
genesis_params={
"difficulty": 1,
"difficulty": 0,
"gas_limit": 2 * GAS_LIMIT,
},
genesis_state={
CALLER_ADDRESS: {
"balance": 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
"nonce": 0,
"code": b"",
"storage": {},
}
},
)

return cast(eth.chains.base.MiningChain, chain)
Expand All @@ -64,7 +73,7 @@ def _benchmark(
nonce = evm.state.get_nonce(caller_address)
tx = evm.create_unsigned_transaction(
nonce=nonce,
gas_price=0,
gas_price=GAS_PRICE,
gas=GAS_LIMIT,
to=eth.constants.CREATE_CONTRACT_ADDRESS,
value=0,
Expand All @@ -78,7 +87,7 @@ def _benchmark(
nonce = evm.state.get_nonce(caller_address)
tx = evm.create_unsigned_transaction(
nonce=nonce,
gas_price=0,
gas_price=GAS_PRICE,
gas=GAS_LIMIT,
to=contract_address,
value=0,
Expand All @@ -90,11 +99,9 @@ def _benchmark(
def bench() -> None:
evm.state.get_transaction_executor().build_computation(evm_message, signed_tx)

for _ in range(num_runs):
start = time.perf_counter_ns()
bench()
end = time.perf_counter_ns()
print((end - start) / 1e6)
results = timeit.repeat(bench, number=1, repeat=num_runs)
for result in results:
print(result * 1000)


def parse_args() -> argparse.Namespace:
Expand Down