Skip to content

Commit

Permalink
tests/4844: Add EIP-7516, BLOBBASEFEE, verification to excess blob ga…
Browse files Browse the repository at this point in the history
…s tests (#294)

* vm/opcode: add BLOBBASEFEE

* tests/4844: check BLOBBASEFEE on excess blob gas tests

* tests/cancun: More EIP-7516 coverage

* tests: tox fixes
  • Loading branch information
marioevz authored Sep 19, 2023
1 parent e7a0603 commit 789de47
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/ethereum_test_tools/vm/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ class Opcodes(Opcode, Enum):
SELFBALANCE = Opcode(0x47, pushed_stack_items=1)
BASEFEE = Opcode(0x48, pushed_stack_items=1)
BLOBHASH = Opcode(0x49, popped_stack_items=1, pushed_stack_items=1)
BLOBBASEFEE = Opcode(0x4A, popped_stack_items=0, pushed_stack_items=1)

POP = Opcode(0x50, popped_stack_items=1)
MLOAD = Opcode(0x51, popped_stack_items=1, pushed_stack_items=1)
Expand Down
52 changes: 35 additions & 17 deletions tests/cancun/eip4844_blobs/test_excess_blob_gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,9 @@

import pytest

from ethereum_test_tools import Account, Block, BlockchainTestFiller, Environment, Header
from ethereum_test_tools import Opcodes as Op
from ethereum_test_tools import (
Account,
Block,
BlockchainTestFiller,
Environment,
Header,
TestAddress,
TestAddress2,
Transaction,
Expand Down Expand Up @@ -156,17 +153,21 @@ def tx_value() -> int: # noqa: D103


@pytest.fixture
def tx_exact_cost(tx_value: int, tx_max_fee_per_gas: int, tx_data_cost: int) -> int: # noqa: D103
tx_gas = 21000
return (tx_gas * tx_max_fee_per_gas) + tx_value + tx_data_cost
def tx_gas_limit() -> int: # noqa: D103
return 45000


@pytest.fixture
def pre(tx_exact_cost: int) -> Mapping[str, Account]: # noqa: D103
return {
TestAddress: Account(balance=tx_exact_cost),
TestAddress2: Account(balance=10**40),
}
def tx_exact_cost( # noqa: D103
tx_value: int, tx_max_fee_per_gas: int, tx_data_cost: int, tx_gas_limit: int
) -> int:
return (tx_gas_limit * tx_max_fee_per_gas) + tx_value + tx_data_cost


@pytest.fixture
def destination_account_bytecode() -> bytes: # noqa: D103
# Verify that the BLOBBASEFEE opcode reflects the current blob gas cost
return Op.SSTORE(0, Op.BLOBBASEFEE)


@pytest.fixture
Expand All @@ -175,9 +176,25 @@ def destination_account() -> str: # noqa: D103


@pytest.fixture
def post(destination_account: str, tx_value: int) -> Mapping[str, Account]: # noqa: D103
def pre( # noqa: D103
destination_account: str, destination_account_bytecode: bytes, tx_exact_cost: int
) -> Mapping[str, Account]:
return {
destination_account: Account(balance=tx_value),
TestAddress: Account(balance=tx_exact_cost),
TestAddress2: Account(balance=10**40),
destination_account: Account(balance=0, code=destination_account_bytecode),
}


@pytest.fixture
def post( # noqa: D103
destination_account: str, tx_value: int, block_fee_per_blob_gas: int
) -> Mapping[str, Account]:
return {
destination_account: Account(
storage={0: block_fee_per_blob_gas},
balance=tx_value,
),
}


Expand All @@ -186,6 +203,7 @@ def tx( # noqa: D103
new_blobs: int,
tx_max_fee_per_gas: int,
tx_max_fee_per_blob_gas: int,
tx_gas_limit: int,
destination_account: str,
):
if new_blobs == 0:
Expand All @@ -195,7 +213,7 @@ def tx( # noqa: D103
nonce=0,
to=destination_account,
value=1,
gas_limit=21000,
gas_limit=tx_gas_limit,
max_fee_per_gas=tx_max_fee_per_gas,
max_priority_fee_per_gas=0,
access_list=[],
Expand All @@ -206,7 +224,7 @@ def tx( # noqa: D103
nonce=0,
to=destination_account,
value=1,
gas_limit=21000,
gas_limit=tx_gas_limit,
max_fee_per_gas=tx_max_fee_per_gas,
max_priority_fee_per_gas=0,
max_fee_per_blob_gas=tx_max_fee_per_blob_gas,
Expand Down
3 changes: 3 additions & 0 deletions tests/cancun/eip7516_blobgasfee/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Tests for EIP-7516: BLOBBASEFEE opcode
"""
194 changes: 194 additions & 0 deletions tests/cancun/eip7516_blobgasfee/test_blobgasfee_opcode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
"""
abstract: Tests [EIP-7516: BLOBBASEFEE opcode](https://eips.ethereum.org/EIPS/eip-7516)
Test BLOBGASFEE opcode [EIP-7516: BLOBBASEFEE opcode](https://eips.ethereum.org/EIPS/eip-7516)
""" # noqa: E501
from itertools import count
from typing import Dict

import pytest

from ethereum_test_tools import Account, Block, BlockchainTestFiller, Environment
from ethereum_test_tools import Opcodes as Op
from ethereum_test_tools import StateTestFiller, Storage, TestAddress, Transaction

REFERENCE_SPEC_GIT_PATH = "EIPS/eip-7516.md"
REFERENCE_SPEC_VERSION = "2ade0452efe8124378f35284676ddfd16dd56ecd"

# Code address used to call the test bytecode on every test case.
code_caller_address = 0x100
code_callee_address = 0x200

BLOBBASEFEE_GAS = 2


@pytest.fixture
def call_gas() -> int:
"""
Amount of gas to use when calling the callee code.
"""
return 0xFFFF


@pytest.fixture
def caller_code(
call_gas: int,
) -> bytes:
"""
Bytecode used to call the bytecode containing the BLOBBASEFEE opcode.
"""
return Op.SSTORE(Op.NUMBER, Op.CALL(call_gas, Op.PUSH20(code_callee_address), 0, 0, 0, 0, 0))


@pytest.fixture
def callee_code() -> bytes:
"""
Bytecode under test, by default, only call the BLOBBASEFEE opcode.
"""
return bytes(Op.BLOBBASEFEE + Op.STOP)


@pytest.fixture
def pre(
caller_code: bytes,
callee_code: bytes,
) -> Dict:
"""
Prepares the pre state of all test cases, by setting the balance of the
source account of all test transactions, and the required code.
"""
return {
TestAddress: Account(balance=10**40),
code_caller_address: Account(
balance=0,
code=caller_code,
),
code_callee_address: Account(
balance=0,
code=callee_code,
),
}


@pytest.fixture
def tx() -> Transaction:
"""
Prepares the test transaction, by setting the destination account, the
transaction value, the transaction gas limit, and the transaction data.
"""
return Transaction(
gas_price=1_000_000_000,
gas_limit=1_000_000,
to=code_caller_address,
value=0,
data=b"",
)


@pytest.mark.parametrize(
"callee_code,call_fails",
[
pytest.param(Op.BLOBBASEFEE * 1024, False, id="no_stack_overflow"),
pytest.param(Op.BLOBBASEFEE * 1025, True, id="stack_overflow"),
],
)
@pytest.mark.valid_from("Cancun")
def test_blobbasefee_stack_overflow(
state_test: StateTestFiller,
pre: Dict,
tx: Transaction,
call_fails: bool,
):
"""
Tests that the BLOBBASEFEE opcode produces an stack overflow by using it repatedly.
"""
post = {
code_caller_address: Account(
storage={1: 0 if call_fails else 1},
),
code_callee_address: Account(
balance=0,
),
}
state_test(
env=Environment(),
pre=pre,
txs=[tx],
post=post,
)


@pytest.mark.parametrize(
"call_gas,call_fails",
[
pytest.param(BLOBBASEFEE_GAS, False, id="enough_gas"),
pytest.param(BLOBBASEFEE_GAS - 1, True, id="out_of_gas"),
],
)
@pytest.mark.valid_from("Cancun")
def test_blobbasefee_out_of_gas(
state_test: StateTestFiller,
pre: Dict,
tx: Transaction,
call_fails: bool,
):
"""
Tests that the BLOBBASEFEE opcode produces an stack overflow by using it repatedly.
"""
post = {
code_caller_address: Account(
storage={1: 0 if call_fails else 1},
),
code_callee_address: Account(
balance=0,
),
}
state_test(
env=Environment(),
pre=pre,
txs=[tx],
post=post,
)


@pytest.mark.valid_at_transition_to("Cancun")
def test_blobbasefee_before_fork(
blockchain_test: BlockchainTestFiller,
pre: Dict,
tx: Transaction,
):
"""
Tests that the BLOBBASEFEE opcode results on exception when called before the fork.
"""
code_caller_storage = Storage()

nonce = count(0)

timestamps = [7_500, 14_999, 15_000]

blocks = []

for number, timestamp in enumerate(timestamps):
blocks.append(
Block(
txs=[tx.with_nonce(next(nonce))],
timestamp=timestamp,
),
)
code_caller_storage[number + 1] = 0 if timestamp < 15_000 else 1

post = {
code_caller_address: Account(
storage=code_caller_storage,
),
code_callee_address: Account(
balance=0,
),
}
blockchain_test(
genesis_environment=Environment(),
pre=pre,
blocks=blocks,
post=post,
)
1 change: 1 addition & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ selfdestruct
selfdestructing
sendall
blobhash
blobbasefee
mcopy
precompile
precompiles
Expand Down

0 comments on commit 789de47

Please sign in to comment.