Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Release tarball changes:
- 🔀 Update EIP-7251 according to [spec updates](https://github.com/ethereum/EIPs/pull/9127) ([#1024](https://github.com/ethereum/execution-spec-tests/pull/1024)).
- 🔀 Update EIP-7002 according to [spec updates](https://github.com/ethereum/EIPs/pull/9119) ([#1024](https://github.com/ethereum/execution-spec-tests/pull/1024)).
- 🔀 Update EIP-2935 according to [spec updates](https://github.com/ethereum/EIPs/pull/9144) ([#1046](https://github.com/ethereum/execution-spec-tests/pull/1046))
- ✨ [EIP-7691](https://eips.ethereum.org/EIPS/eip-7691) Blob throughput increase tests by parametrization of existing EIP-4844 tests ([#1023](https://github.com/ethereum/execution-spec-tests/pull/1023))
- ✨ [EIP-7691](https://eips.ethereum.org/EIPS/eip-7691) Blob throughput increase tests by parametrization of existing EIP-4844 tests ([#1023](https://github.com/ethereum/execution-spec-tests/pull/1023), [#1082](https://github.com/ethereum/execution-spec-tests/pull/1082))

### 🛠️ Framework

Expand Down
214 changes: 151 additions & 63 deletions tests/cancun/eip4844_blobs/test_excess_blob_gas_fork_transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,29 @@

import pytest

from ethereum_test_forks import Cancun, Fork
from ethereum_test_forks import Fork
from ethereum_test_tools import (
EOA,
Account,
Address,
Alloc,
Block,
BlockchainTestFiller,
BlockException,
EngineAPIError,
Environment,
Hash,
Header,
TestAddress,
Transaction,
add_kzg_version,
)
from ethereum_test_tools import Opcodes as Op

from .spec import Spec, SpecHelpers, ref_spec_4844

REFERENCE_SPEC_GIT_PATH = ref_spec_4844.git_path
REFERENCE_SPEC_VERSION = ref_spec_4844.version

# All tests run on the transition fork from Shanghai to Cancun
pytestmark = pytest.mark.valid_at_transition_to("Cancun")


# Timestamp of the fork
FORK_TIMESTAMP = 15_000

Expand All @@ -43,89 +41,177 @@ def env() -> Environment: # noqa: D103


@pytest.fixture
def pre() -> Mapping[Address, Account]: # noqa: D103
return {
TestAddress: Account(balance=10**40),
}


@pytest.fixture
def pre_fork_blocks():
"""Generate blocks to reach the fork."""
return [Block(timestamp=t) for t in range(999, FORK_TIMESTAMP, 1_000)]


@pytest.fixture
def post_fork_block_count(fork: Fork) -> int:
"""Amount of blocks to produce with the post-fork rules."""
return SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=fork, blob_gas_price=2) // (
fork.max_blobs_per_block() - fork.target_blobs_per_block()
)


@pytest.fixture
def blob_count_per_block() -> int:
"""Amount of blocks to produce with the post-fork rules."""
return 4
def pre_fork_blobs_per_block(fork: Fork) -> int:
"""Amount of blobs to produce with the pre-fork rules."""
if fork.supports_blobs(timestamp=0):
return fork.max_blobs_per_block(timestamp=0)
return 0


@pytest.fixture
def destination_account() -> Address: # noqa: D103
return Address(0x100)
def sender(pre: Alloc) -> EOA:
"""Sender account."""
return pre.fund_eoa()


@pytest.fixture
def post_fork_blocks(
def pre_fork_blocks(
pre_fork_blobs_per_block: int,
destination_account: Address,
post_fork_block_count: int,
blob_count_per_block: int,
):
"""Generate blocks past the fork."""
sender: EOA,
) -> List[Block]:
"""Generate blocks to reach the fork."""
return [
Block(
txs=[
Transaction(
ty=Spec.BLOB_TX_TYPE,
nonce=b,
to=destination_account,
value=1,
gas_limit=3000000,
max_fee_per_gas=1000000,
gas_limit=3_000_000,
max_fee_per_gas=1_000_000,
max_priority_fee_per_gas=10,
max_fee_per_blob_gas=100,
access_list=[],
blob_versioned_hashes=add_kzg_version(
[Hash(x) for x in range(blob_count_per_block)],
[Hash(x) for x in range(pre_fork_blobs_per_block)],
Spec.BLOB_COMMITMENT_VERSION_KZG,
),
sender=sender,
)
if blob_count_per_block > 0
if pre_fork_blobs_per_block > 0
else Transaction(
ty=2,
nonce=b,
to=destination_account,
value=1,
gas_limit=3000000,
max_fee_per_gas=1000000,
gas_limit=3_000_000,
max_fee_per_gas=1_000_000,
max_priority_fee_per_gas=10,
access_list=[],
sender=sender,
)
],
timestamp=t,
)
for b in range(post_fork_block_count)
for t in range(999, FORK_TIMESTAMP, 1_000)
]


@pytest.fixture
def pre_fork_excess_blobs(
fork: Fork,
pre_fork_blobs_per_block: int,
pre_fork_blocks: List[Block],
) -> int:
"""
Return the cummulative excess blobs up until the fork given the pre_fork_blobs_per_block
and the target blobs in the fork prior.
"""
if not fork.supports_blobs(timestamp=0):
return 0
target_blobs = fork.target_blobs_per_block(timestamp=0)
if pre_fork_blobs_per_block > target_blobs:
return (pre_fork_blobs_per_block - target_blobs) * (len(pre_fork_blocks) - 1)
return 0


@pytest.fixture
def post_fork_block_count(fork: Fork) -> int:
"""Amount of blocks to produce with the post-fork rules."""
return SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=fork, blob_gas_price=2) // (
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP)
- fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP)
)


@pytest.fixture
def post_fork_blobs_per_block(fork: Fork) -> int:
"""Amount of blocks to produce with the post-fork rules."""
return fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP) + 1


@pytest.fixture
def destination_account(pre: Alloc) -> Address: # noqa: D103
return pre.deploy_contract(Op.STOP)


@pytest.fixture
def fork_block_excess_blob_gas(
fork: Fork,
pre_fork_excess_blobs: int,
pre_fork_blobs_per_block: int,
) -> int:
"""Calculate the expected excess blob gas for the fork block."""
if pre_fork_blobs_per_block == 0:
return 0
calc_excess_blob_gas_post_fork = fork.excess_blob_gas_calculator(timestamp=FORK_TIMESTAMP)
return calc_excess_blob_gas_post_fork(
parent_excess_blobs=pre_fork_excess_blobs,
parent_blob_count=pre_fork_blobs_per_block,
)


@pytest.fixture
def post_fork_blocks(
destination_account: Address,
post_fork_block_count: int,
post_fork_blobs_per_block: int,
fork_block_excess_blob_gas: int,
sender: EOA,
):
"""Generate blocks past the fork."""
blocks = []
for i in range(post_fork_block_count):
txs = [
Transaction(
ty=Spec.BLOB_TX_TYPE,
to=destination_account,
value=1,
gas_limit=3_000_000,
max_fee_per_gas=1_000_000,
max_priority_fee_per_gas=10,
max_fee_per_blob_gas=100,
blob_versioned_hashes=add_kzg_version(
[Hash(x) for x in range(post_fork_blobs_per_block)],
Spec.BLOB_COMMITMENT_VERSION_KZG,
),
sender=sender,
)
if post_fork_blobs_per_block > 0
else Transaction(
ty=2,
to=destination_account,
value=1,
gas_limit=3_000_000,
max_fee_per_gas=1_000_000,
max_priority_fee_per_gas=10,
sender=sender,
)
]
if i == 0:
blocks.append(
Block(
txs=txs,
excess_blob_gas=fork_block_excess_blob_gas,
)
)
else:
blocks.append(Block(txs=txs))
return blocks


@pytest.fixture
def post( # noqa: D103
pre_fork_blocks: List[Block],
post_fork_block_count: int,
destination_account: Address,
) -> Mapping[Address, Account]:
return {
destination_account: Account(balance=post_fork_block_count),
destination_account: Account(balance=post_fork_block_count + len(pre_fork_blocks)),
}


@pytest.mark.valid_at_transition_to("Cancun")
@pytest.mark.parametrize(
"excess_blob_gas_present,blob_gas_used_present",
[
Expand All @@ -137,7 +223,7 @@ def post( # noqa: D103
def test_invalid_pre_fork_block_with_blob_fields(
blockchain_test: BlockchainTestFiller,
env: Environment,
pre: Mapping[Address, Account],
pre: Alloc,
pre_fork_blocks: List[Block],
excess_blob_gas_present: bool,
blob_gas_used_present: bool,
Expand Down Expand Up @@ -166,10 +252,10 @@ def test_invalid_pre_fork_block_with_blob_fields(
)
],
genesis_environment=env,
tag="invalid_pre_fork_blob_fields",
)


@pytest.mark.valid_at_transition_to("Cancun")
@pytest.mark.parametrize(
"excess_blob_gas_missing,blob_gas_used_missing",
[
Expand All @@ -181,7 +267,7 @@ def test_invalid_pre_fork_block_with_blob_fields(
def test_invalid_post_fork_block_without_blob_fields(
blockchain_test: BlockchainTestFiller,
env: Environment,
pre: Mapping[Address, Account],
pre: Alloc,
pre_fork_blocks: List[Block],
excess_blob_gas_missing: bool,
blob_gas_used_missing: bool,
Expand Down Expand Up @@ -211,28 +297,31 @@ def test_invalid_post_fork_block_without_blob_fields(
)
],
genesis_environment=env,
tag="blob_fields_missing_post_fork",
)


@pytest.mark.parametrize(
"post_fork_block_count,blob_count_per_block",
[
(
SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=Cancun, blob_gas_price=2)
// (Cancun.max_blobs_per_block() - Cancun.target_blobs_per_block())
@pytest.mark.valid_at_transition_to("Cancun", subsequent_forks=True)
@pytest.mark.parametrize_by_fork(
"post_fork_block_count,post_fork_blobs_per_block",
lambda fork: [
pytest.param(
SpecHelpers.get_min_excess_blobs_for_blob_gas_price(fork=fork, blob_gas_price=2)
// (
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP)
- fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP)
)
+ 2,
Cancun.max_blobs_per_block(),
fork.max_blobs_per_block(timestamp=FORK_TIMESTAMP),
id="max_blobs",
),
(10, 0),
(10, Cancun.target_blobs_per_block()),
pytest.param(10, 0, id="no_blobs"),
pytest.param(10, fork.target_blobs_per_block(timestamp=FORK_TIMESTAMP), id="target_blobs"),
],
ids=["max_blobs", "no_blobs", "target_blobs"],
)
def test_fork_transition_excess_blob_gas(
blockchain_test: BlockchainTestFiller,
env: Environment,
pre: Mapping[Address, Account],
pre: Alloc,
pre_fork_blocks: List[Block],
post_fork_blocks: List[Block],
post: Mapping[Address, Account],
Expand All @@ -248,5 +337,4 @@ def test_fork_transition_excess_blob_gas(
post=post,
blocks=pre_fork_blocks + post_fork_blocks,
genesis_environment=env,
tag="correct_initial_blob_gas_calc",
)
Loading