From 0068173367bb80cc4df54ad895a3996657c27ecc Mon Sep 17 00:00:00 2001 From: marioevz Date: Thu, 8 Jun 2023 01:42:35 +0000 Subject: [PATCH 01/21] tools: fix data gas used --- src/ethereum_test_tools/common/types.py | 24 ++++++++++++------- .../spec/blockchain_test.py | 1 + src/ethereum_test_tools/spec/state_test.py | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/ethereum_test_tools/common/types.py b/src/ethereum_test_tools/common/types.py index ccfa56ff52..826b2c85ad 100644 --- a/src/ethereum_test_tools/common/types.py +++ b/src/ethereum_test_tools/common/types.py @@ -557,8 +557,10 @@ class Environment: parent_gas_limit: Optional[int] = None parent_ommers_hash: Optional[str] = None withdrawals: Optional[List[Withdrawal]] = None - excess_data_gas: Optional[int] = None + parent_data_gas_used: Optional[int] = None parent_excess_data_gas: Optional[int] = None + excess_data_gas: Optional[int] = None + data_gas_used: Optional[int] = None @staticmethod def from_parent_header(parent: "FixtureHeader") -> "Environment": @@ -569,6 +571,7 @@ def from_parent_header(parent: "FixtureHeader") -> "Environment": parent_difficulty=parent.difficulty, parent_timestamp=parent.timestamp, parent_base_fee=parent.base_fee, + parent_data_gas_used=parent.data_gas_used, parent_excess_data_gas=parent.excess_data_gas, parent_gas_used=parent.gas_used, parent_gas_limit=parent.gas_limit, @@ -599,6 +602,7 @@ def apply_new_parent(self, new_parent: "FixtureHeader") -> "Environment": env.parent_difficulty = new_parent.difficulty env.parent_timestamp = new_parent.timestamp env.parent_base_fee = new_parent.base_fee + env.parent_data_gas_used = new_parent.data_gas_used env.parent_excess_data_gas = new_parent.excess_data_gas env.parent_gas_used = new_parent.gas_used env.parent_gas_limit = new_parent.gas_limit @@ -638,12 +642,6 @@ def set_fork_requirements(self, fork: Fork) -> "Environment": if fork.header_zero_difficulty_required(self.number, self.timestamp): res.difficulty = 0 - if ( - fork.header_excess_data_gas_required(self.number, self.timestamp) - and res.excess_data_gas is None - ): - res.excess_data_gas = 0 - return res @@ -806,6 +804,7 @@ class Header: nonce: Optional[str] = None base_fee: Optional[int | Removable] = None withdrawals_root: Optional[str | Removable] = None + data_gas_used: Optional[int | Removable] = None excess_data_gas: Optional[int | Removable] = None hash: Optional[str] = None @@ -838,6 +837,7 @@ class FixtureHeader: nonce: str base_fee: Optional[int] = None withdrawals_root: Optional[str] = None + data_gas_used: Optional[int] = None excess_data_gas: Optional[int] = None hash: Optional[str] = None @@ -867,6 +867,7 @@ def from_dict(source: Dict[str, Any]) -> "FixtureHeader": nonce=source["nonce"], base_fee=int_or_none(source.get("baseFeePerGas")), withdrawals_root=str_or_none(source.get("withdrawalsRoot")), + data_gas_used=int_or_none(source.get("dataGasUsed")), excess_data_gas=int_or_none(source.get("excessDataGas")), hash=source.get("hash"), ) @@ -896,6 +897,8 @@ def to_geth_dict(self) -> Mapping[str, Any]: header["baseFeePerGas"] = hex(self.base_fee) if self.withdrawals_root is not None: header["withdrawalsRoot"] = self.withdrawals_root + if self.data_gas_used is not None: + header["dataGasUsed"] = hex(self.data_gas_used) if self.excess_data_gas is not None: header["excessDataGas"] = hex(self.excess_data_gas) return header @@ -975,7 +978,8 @@ def set_environment(self, env: Environment) -> Environment: new_env.withdrawals = self.withdrawals if not isinstance(self.excess_data_gas, Removable): new_env.excess_data_gas = self.excess_data_gas - + if not isinstance(self.data_gas_used, Removable): + new_env.data_gas_used = self.data_gas_used """ These values are required, but they depend on the previous environment, so they can be calculated here. @@ -1156,8 +1160,10 @@ def default(self, obj): "withdrawals": to_json_or_none(obj.withdrawals), "parentUncleHash": obj.parent_ommers_hash, "currentBaseFee": str_or_none(obj.base_fee), + "parentDataGasUsed": str_or_none(obj.parent_data_gas_used), "parentExcessDataGas": str_or_none(obj.parent_excess_data_gas), "currentExcessDataGas": str_or_none(obj.excess_data_gas), + "currentDataGasUsed": str_or_none(obj.data_gas_used), } return {k: v for (k, v) in env.items() if v is not None} @@ -1185,6 +1191,8 @@ def default(self, obj): header["hash"] = obj.hash if obj.withdrawals_root is not None: header["withdrawalsRoot"] = obj.withdrawals_root + if obj.data_gas_used is not None: + header["dataGasUsed"] = hex(obj.data_gas_used) if obj.excess_data_gas is not None: header["excessDataGas"] = hex(obj.excess_data_gas) return even_padding( diff --git a/src/ethereum_test_tools/spec/blockchain_test.py b/src/ethereum_test_tools/spec/blockchain_test.py index 43c947afaf..0d102db63d 100644 --- a/src/ethereum_test_tools/spec/blockchain_test.py +++ b/src/ethereum_test_tools/spec/blockchain_test.py @@ -75,6 +75,7 @@ def make_genesis( mix_digest="0x0000000000000000000000000000000000000000000000000000000000000000", nonce="0x0000000000000000", base_fee=env.base_fee, + data_gas_used=env.data_gas_used, excess_data_gas=env.excess_data_gas, withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork) if env.withdrawals is not None diff --git a/src/ethereum_test_tools/spec/state_test.py b/src/ethereum_test_tools/spec/state_test.py index bf751dd98a..4e4f69fd3b 100644 --- a/src/ethereum_test_tools/spec/state_test.py +++ b/src/ethereum_test_tools/spec/state_test.py @@ -73,6 +73,7 @@ def make_genesis( mix_digest="0x0000000000000000000000000000000000000000000000000000000000000000", nonce="0x0000000000000000", base_fee=env.base_fee, + data_gas_used=env.data_gas_used, excess_data_gas=env.excess_data_gas, withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork) if env.withdrawals is not None From c05583813a0f430052b1e0d97f5c3fe397b71660 Mon Sep 17 00:00:00 2001 From: marioevz Date: Thu, 8 Jun 2023 01:42:56 +0000 Subject: [PATCH 02/21] fillers/4844: excess data gas: fix some tests --- tests/eips/eip4844/test_excess_data_gas.py | 112 ++++++++++++++++++--- 1 file changed, 99 insertions(+), 13 deletions(-) diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index 10324c615c..6f32c5cd52 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -107,16 +107,16 @@ def get_data_gasprice(excess_data_gas: int) -> int: ) -def calc_excess_data_gas(parent_excess_data_gas: int, new_blobs: int) -> int: +def calc_excess_data_gas(parent_excess_data_gas: int, parent_blobs: int) -> int: """ Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - consumed_data_gas = new_blobs * DATA_GAS_PER_BLOB - if parent_excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: + parent_consumed_data_gas = parent_blobs * DATA_GAS_PER_BLOB + if parent_excess_data_gas + parent_consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: return 0 else: - return parent_excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK + return parent_excess_data_gas + parent_consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK @pytest.fixture @@ -135,11 +135,11 @@ def parent_excess_data_gas(parent_excess_blobs: int) -> int: # noqa: D103 @pytest.fixture def correct_excess_data_gas( # noqa: D103 parent_excess_data_gas: int, - new_blobs: int, + parent_blobs: int, ) -> int: return calc_excess_data_gas( parent_excess_data_gas=parent_excess_data_gas, - new_blobs=new_blobs, + parent_blobs=parent_blobs, ) @@ -166,11 +166,16 @@ def header_excess_data_gas( # noqa: D103 return None +@pytest.fixture +def header_data_gas_used() -> Optional[int]: # noqa: D103 + return None + + @pytest.fixture def fee_per_data_gas( # noqa: D103 - parent_excess_data_gas: int, + correct_excess_data_gas: int, ) -> int: - return get_data_gasprice(excess_data_gas=parent_excess_data_gas) + return get_data_gasprice(excess_data_gas=correct_excess_data_gas) @pytest.fixture @@ -188,10 +193,12 @@ def block_base_fee() -> int: # noqa: D103 @pytest.fixture def env( # noqa: D103 parent_excess_data_gas: int, + parent_blobs: int, block_base_fee: int, ) -> Environment: return Environment( excess_data_gas=parent_excess_data_gas, + data_gas_used=parent_blobs * DATA_GAS_PER_BLOB, base_fee=block_base_fee, ) @@ -282,20 +289,34 @@ def tx( # noqa: D103 def blocks( # noqa: D103 tx: Transaction, header_excess_data_gas: Optional[int], + header_data_gas_used: Optional[int], ): if header_excess_data_gas is not None: return [ Block( txs=[tx], - rlp_modifier=Header(excess_data_gas=header_excess_data_gas), + rlp_modifier=Header( + excess_data_gas=header_excess_data_gas, + ), exception="invalid excess data gas", ) ] + if header_data_gas_used is not None: + return [ + Block( + txs=[tx], + rlp_modifier=Header( + data_gas_used=header_data_gas_used, + ), + exception="invalid data gas used", + ) + ] return [Block(txs=[tx])] -@pytest.mark.parametrize("new_blobs", range(0, MAX_BLOBS_PER_BLOCK + 1)) +@pytest.mark.parametrize("parent_blobs", range(0, MAX_BLOBS_PER_BLOCK + 1)) @pytest.mark.parametrize("parent_excess_blobs", range(0, TARGET_BLOBS_PER_BLOCK + 1)) +@pytest.mark.parametrize("new_blobs", [0]) def test_correct_excess_data_gas_calculation( blockchain_test: BlockchainTestFiller, env: Environment, @@ -334,7 +355,8 @@ def test_correct_excess_data_gas_calculation( 820, ], ) -@pytest.mark.parametrize("new_blobs", [TARGET_BLOBS_PER_BLOCK + 1]) +@pytest.mark.parametrize("parent_blobs", [TARGET_BLOBS_PER_BLOCK + 1]) +@pytest.mark.parametrize("new_blobs", [1]) def test_correct_increasing_data_gas_costs( blockchain_test: BlockchainTestFiller, env: Environment, @@ -371,7 +393,8 @@ def test_correct_increasing_data_gas_costs( 754, ], ) -@pytest.mark.parametrize("new_blobs", [TARGET_BLOBS_PER_BLOCK - 1]) +@pytest.mark.parametrize("parent_blobs", [TARGET_BLOBS_PER_BLOCK - 1]) +@pytest.mark.parametrize("new_blobs", [1]) def test_correct_decreasing_data_gas_costs( blockchain_test: BlockchainTestFiller, env: Environment, @@ -394,7 +417,8 @@ def test_correct_decreasing_data_gas_costs( @pytest.mark.parametrize("header_excess_data_gas", [0]) -@pytest.mark.parametrize("new_blobs", range(0, MAX_BLOBS_PER_BLOCK + 1)) +@pytest.mark.parametrize("new_blobs", [0, 1]) +@pytest.mark.parametrize("parent_blobs", range(0, MAX_BLOBS_PER_BLOCK + 1)) def test_invalid_zero_excess_data_gas_in_header( blockchain_test: BlockchainTestFiller, env: Environment, @@ -428,6 +452,68 @@ def test_invalid_zero_excess_data_gas_in_header( ) +@pytest.mark.parametrize("header_data_gas_used", [0]) +@pytest.mark.parametrize("new_blobs", range(1, MAX_BLOBS_PER_BLOCK + 1)) +@pytest.mark.parametrize("parent_blobs", [0]) +def test_invalid_zero_data_gas_used_in_header( + blockchain_test: BlockchainTestFiller, + env: Environment, + pre: Mapping[str, Account], + blocks: List[Block], + new_blobs: int, + header_data_gas_used: Optional[int], +): + """ + Test rejection of blocks where the data_gas_used in the header is zero in + a block with data blobs. + """ + if header_data_gas_used is None: + raise Exception("test case is badly formatted") + blockchain_test( + pre=pre, + post={}, + blocks=blocks, + genesis_environment=env, + tag="-".join( + [ + f"correct:{hex(new_blobs * DATA_GAS_PER_BLOB)}", + f"header:{hex(header_data_gas_used)}", + ] + ), + ) + + +@pytest.mark.parametrize("header_data_gas_used", [DATA_GAS_PER_BLOB]) +@pytest.mark.parametrize("new_blobs", [1]) +@pytest.mark.parametrize("parent_blobs", [0]) +def test_invalid_non_zero_data_gas_used_in_header( + blockchain_test: BlockchainTestFiller, + env: Environment, + pre: Mapping[str, Account], + blocks: List[Block], + new_blobs: int, + header_data_gas_used: Optional[int], +): + """ + Test rejection of blocks where the data_gas_used in the header is zero in + a block with data blobs. + """ + if header_data_gas_used is None: + raise Exception("test case is badly formatted") + blockchain_test( + pre=pre, + post={}, + blocks=blocks, + genesis_environment=env, + tag="-".join( + [ + f"correct:{hex(new_blobs * DATA_GAS_PER_BLOB)}", + f"header:{hex(header_data_gas_used)}", + ] + ), + ) + + @pytest.mark.parametrize( "header_excess_blobs_delta", [-(TARGET_BLOBS_PER_BLOCK + 1), (TARGET_BLOBS_PER_BLOCK + 1)], From 2810b5e0c2850b0d56897c9f16bff4d79bcef435 Mon Sep 17 00:00:00 2001 From: marioevz Date: Thu, 8 Jun 2023 20:07:57 +0000 Subject: [PATCH 03/21] fillers/4844: coalesce utilities into a single file --- tests/eips/eip4844/README.md | 13 ++- tests/eips/eip4844/test_blob_txs.py | 42 ++----- tests/eips/eip4844/test_blobhash_opcode.py | 2 +- .../eip4844/test_blobhash_opcode_contexts.py | 2 +- tests/eips/eip4844/test_excess_data_gas.py | 85 ++------------ .../test_excess_data_gas_fork_transition.py | 76 +----------- .../test_point_evaluation_precompile.py | 50 +++----- .../test_point_evaluation_precompile_gas.py | 30 ++--- .../eip4844/{util_blobhash.py => utils.py} | 108 +++++++++++++++++- 9 files changed, 156 insertions(+), 252 deletions(-) rename tests/eips/eip4844/{util_blobhash.py => utils.py} (76%) diff --git a/tests/eips/eip4844/README.md b/tests/eips/eip4844/README.md index 6201451757..9d4074aa7d 100644 --- a/tests/eips/eip4844/README.md +++ b/tests/eips/eip4844/README.md @@ -46,12 +46,17 @@ Predominantly verifies that `excess_data_gas` & `data_gasprice` are calculated c Tests that the `excess_data_gas` is calculated correctly within a single block for various contexts, where the `parent.excess_data_gas` and the proposed block `excess_data_gas` have a variety of values. The excess data gas is calculated using the following formula: ```python -def calc_excess_data_gas(parent: Header, new_blobs: int) -> int: - consumed_data_gas = new_blobs * DATA_GAS_PER_BLOB - if parent.excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: +def calc_excess_data_gas(parent_excess_data_gas: int, parent_blobs: int) -> int: + """ + Calculate the excess data gas for a block given the parent excess data gas + and the number of blobs in the block. + """ + parent_consumed_data_gas = parent_blobs * DATA_GAS_PER_BLOB + if parent_excess_data_gas + parent_consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: return 0 else: - return parent.excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK + return parent_excess_data_gas + parent_consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK + ``` For blocks to be valid in these contexts they must meet the following conditions of the EIP: diff --git a/tests/eips/eip4844/test_blob_txs.py b/tests/eips/eip4844/test_blob_txs.py index 702c91eee4..aaccdaea3a 100644 --- a/tests/eips/eip4844/test_blob_txs.py +++ b/tests/eips/eip4844/test_blob_txs.py @@ -19,6 +19,13 @@ to_hash_bytes, ) +from .utils import ( + BLOB_COMMITMENT_VERSION_KZG, + DATA_GAS_PER_BLOB, + MAX_BLOBS_PER_BLOCK, + get_data_gasprice, +) + # * Adding a new test * # Add a function that is named `test_` and takes the following # arguments: @@ -38,41 +45,6 @@ REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4844.md" REFERENCE_SPEC_VERSION = "b33e063530f0a114635dd4f89d3cca90f8cac28f" -BLOB_COMMITMENT_VERSION_KZG = 1 -BLOBHASH_GAS_COST = 3 -MIN_DATA_GASPRICE = 1 -DATA_GAS_PER_BLOB = 2**17 -MAX_DATA_GAS_PER_BLOCK = 2**19 -TARGET_DATA_GAS_PER_BLOCK = 2**18 -MAX_BLOBS_PER_BLOCK = MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB -TARGET_BLOBS_PER_BLOCK = TARGET_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB -DATA_GASPRICE_UPDATE_FRACTION = 2225652 - - -def fake_exponential(factor: int, numerator: int, denominator: int) -> int: - """ - Used to calculate the data gas cost. - """ - i = 1 - output = 0 - numerator_accumulator = factor * denominator - while numerator_accumulator > 0: - output += numerator_accumulator - numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i) - i += 1 - return output // denominator - - -def get_data_gasprice(excess_data_gas: int) -> int: - """ - Calculate the data gas price from the excess. - """ - return fake_exponential( - MIN_DATA_GASPRICE, - excess_data_gas, - DATA_GASPRICE_UPDATE_FRACTION, - ) - @pytest.fixture def destination_account() -> str: diff --git a/tests/eips/eip4844/test_blobhash_opcode.py b/tests/eips/eip4844/test_blobhash_opcode.py index 67a69164fe..ef9f5fc06c 100644 --- a/tests/eips/eip4844/test_blobhash_opcode.py +++ b/tests/eips/eip4844/test_blobhash_opcode.py @@ -17,7 +17,7 @@ ) from ethereum_test_tools.vm.opcode import Opcodes as Op -from .util_blobhash import ( +from .utils import ( BLOBHASH_GAS_COST, MAX_BLOB_PER_BLOCK, TARGET_BLOB_PER_BLOCK, diff --git a/tests/eips/eip4844/test_blobhash_opcode_contexts.py b/tests/eips/eip4844/test_blobhash_opcode_contexts.py index c5b054fa28..2c81a374f3 100644 --- a/tests/eips/eip4844/test_blobhash_opcode_contexts.py +++ b/tests/eips/eip4844/test_blobhash_opcode_contexts.py @@ -16,7 +16,7 @@ to_hash_bytes, ) -from .util_blobhash import BlobhashContext, simple_blob_hashes +from .utils import BlobhashContext, simple_blob_hashes pytestmark = pytest.mark.valid_from("Cancun") diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index 6f32c5cd52..fbe01cc11a 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -20,6 +20,15 @@ to_hash_bytes, ) +from .utils import ( + BLOB_COMMITMENT_VERSION_KZG, + DATA_GAS_PER_BLOB, + MAX_BLOBS_PER_BLOCK, + TARGET_BLOBS_PER_BLOCK, + calc_excess_data_gas, + get_data_gasprice, +) + # * Adding a new test * # Add a function that is named `test_` and takes the following # arguments: @@ -44,80 +53,6 @@ # All tests run from Cancun fork pytestmark = pytest.mark.valid_from("Cancun") -BLOB_COMMITMENT_VERSION_KZG = 1 -BLOBHASH_GAS_COST = 3 -MIN_DATA_GASPRICE = 1 -DATA_GAS_PER_BLOB = 2**17 -MAX_DATA_GAS_PER_BLOCK = 2**19 -TARGET_DATA_GAS_PER_BLOCK = 2**18 -MAX_BLOBS_PER_BLOCK = MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB -TARGET_BLOBS_PER_BLOCK = TARGET_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB -DATA_GASPRICE_UPDATE_FRACTION = 2225652 - - -def fake_exponential(factor: int, numerator: int, denominator: int) -> int: - """ - Used to calculate the data gas cost. - """ - i = 1 - output = 0 - numerator_accumulator = factor * denominator - while numerator_accumulator > 0: - output += numerator_accumulator - numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i) - i += 1 - return output // denominator - - -def calc_data_fee(tx: Transaction, excess_data_gas: int) -> int: - """ - Calculate the data fee for a transaction. - """ - return get_total_data_gas(tx) * get_data_gasprice(excess_data_gas) - - -def get_total_data_gas(tx: Transaction) -> int: - """ - Calculate the total data gas for a transaction. - """ - if tx.blob_versioned_hashes is None: - return 0 - return DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) - - -def get_data_gasprice_from_blobs(excess_blobs: int) -> int: - """ - Calculate the data gas price from the excess blob count. - """ - return fake_exponential( - MIN_DATA_GASPRICE, - excess_blobs * DATA_GAS_PER_BLOB, - DATA_GASPRICE_UPDATE_FRACTION, - ) - - -def get_data_gasprice(excess_data_gas: int) -> int: - """ - Calculate the data gas price from the excess. - """ - return fake_exponential( - MIN_DATA_GASPRICE, - excess_data_gas, - DATA_GASPRICE_UPDATE_FRACTION, - ) - - -def calc_excess_data_gas(parent_excess_data_gas: int, parent_blobs: int) -> int: - """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. - """ - parent_consumed_data_gas = parent_blobs * DATA_GAS_PER_BLOB - if parent_excess_data_gas + parent_consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: - return 0 - else: - return parent_excess_data_gas + parent_consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK - @pytest.fixture def parent_excess_blobs() -> int: # noqa: D103 @@ -316,7 +251,7 @@ def blocks( # noqa: D103 @pytest.mark.parametrize("parent_blobs", range(0, MAX_BLOBS_PER_BLOCK + 1)) @pytest.mark.parametrize("parent_excess_blobs", range(0, TARGET_BLOBS_PER_BLOCK + 1)) -@pytest.mark.parametrize("new_blobs", [0]) +@pytest.mark.parametrize("new_blobs", [1]) def test_correct_excess_data_gas_calculation( blockchain_test: BlockchainTestFiller, env: Environment, diff --git a/tests/eips/eip4844/test_excess_data_gas_fork_transition.py b/tests/eips/eip4844/test_excess_data_gas_fork_transition.py index 7e66e9aa1c..d26130556e 100644 --- a/tests/eips/eip4844/test_excess_data_gas_fork_transition.py +++ b/tests/eips/eip4844/test_excess_data_gas_fork_transition.py @@ -19,74 +19,14 @@ to_hash_bytes, ) +from .utils import BLOB_COMMITMENT_VERSION_KZG, MAX_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK + REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4844.md" REFERENCE_SPEC_VERSION = "ac003985b9be74ff48bd897770e6d5f2e4318715" # All tests run on the transition fork from Shanghai to Cancun pytestmark = pytest.mark.valid_at_transition_to("Cancun") -BLOB_COMMITMENT_VERSION_KZG = 1 -BLOBHASH_GAS_COST = 3 -MIN_DATA_GASPRICE = 1 -DATA_GAS_PER_BLOB = 2**17 -MAX_DATA_GAS_PER_BLOCK = 2**19 -TARGET_DATA_GAS_PER_BLOCK = 2**18 -MAX_BLOBS_PER_BLOCK = MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB -TARGET_BLOBS_PER_BLOCK = TARGET_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB -DATA_GASPRICE_UPDATE_FRACTION = 2225652 - - -def fake_exponential(factor: int, numerator: int, denominator: int) -> int: - """ - Used to calculate the data gas cost. - """ - i = 1 - output = 0 - numerator_accumulator = factor * denominator - while numerator_accumulator > 0: - output += numerator_accumulator - numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i) - i += 1 - return output // denominator - - -def calc_data_fee(tx: Transaction, excess_data_gas: int) -> int: - """ - Calculate the data fee for a transaction. - """ - return get_total_data_gas(tx) * get_data_gasprice(excess_data_gas) - - -def get_total_data_gas(tx: Transaction) -> int: - """ - Calculate the total data gas for a transaction. - """ - if tx.blob_versioned_hashes is None: - return 0 - return DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) - - -def get_data_gasprice_from_blobs(excess_blobs: int) -> int: - """ - Calculate the data gas price from the excess blob count. - """ - return fake_exponential( - MIN_DATA_GASPRICE, - excess_blobs * DATA_GAS_PER_BLOB, - DATA_GASPRICE_UPDATE_FRACTION, - ) - - -def get_data_gasprice(excess_data_gas: int) -> int: - """ - Calculate the data gas price from the excess. - """ - return fake_exponential( - MIN_DATA_GASPRICE, - excess_data_gas, - DATA_GASPRICE_UPDATE_FRACTION, - ) - # Timestamp of the fork FORK_TIMESTAMP = 15_000 @@ -94,18 +34,6 @@ def get_data_gasprice(excess_data_gas: int) -> int: BLOBS_TO_DATA_GAS_COST_INCREASE = 12 -def calc_excess_data_gas(parent_excess_data_gas: int, new_blobs: int) -> int: - """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. - """ - consumed_data_gas = new_blobs * DATA_GAS_PER_BLOB - if parent_excess_data_gas + consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: - return 0 - else: - return parent_excess_data_gas + consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK - - @pytest.fixture def env() -> Environment: # noqa: D103 return Environment() diff --git a/tests/eips/eip4844/test_point_evaluation_precompile.py b/tests/eips/eip4844/test_point_evaluation_precompile.py index 4a03bcd996..d6c9af8b3d 100644 --- a/tests/eips/eip4844/test_point_evaluation_precompile.py +++ b/tests/eips/eip4844/test_point_evaluation_precompile.py @@ -5,8 +5,7 @@ import glob import json import os -from hashlib import sha256 -from typing import Dict, Iterator, List, Literal +from typing import Dict, Iterator, List import pytest @@ -23,44 +22,21 @@ ) from ethereum_test_tools.vm.opcode import Opcodes as Op +from .utils import ( + BLS_MODULUS, + FIELD_ELEMENTS_PER_BLOB, + INF_POINT, + POINT_EVALUATION_PRECOMPILE_ADDRESS, + POINT_EVALUATION_PRECOMPILE_GAS, + Z_Y_VALID_ENDIANNESS, + Z, + auto, + kzg_to_versioned_hash, +) + REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4844.md" REFERENCE_SPEC_VERSION = "ac003985b9be74ff48bd897770e6d5f2e4318715" -POINT_EVALUATION_PRECOMPILE_ADDRESS = 20 -POINT_EVALUATION_PRECOMPILE_GAS = 50_000 -BLOB_COMMITMENT_VERSION_KZG = b"\x01" - -BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 -BLS_MODULUS_BYTES = BLS_MODULUS.to_bytes(32, "big") -FIELD_ELEMENTS_PER_BLOB = 4096 -FIELD_ELEMENTS_PER_BLOB_BYTES = FIELD_ELEMENTS_PER_BLOB.to_bytes(32, "big") - -Z_Y_VALID_ENDIANNESS: Literal["little", "big"] = "big" -Z_Y_INVALID_ENDIANNESS: Literal["little", "big"] = "little" - -Z = 0x623CE31CF9759A5C8DAF3A357992F9F3DD7F9339D8998BC8E68373E54F00B75E -INF_POINT = (0xC0 << 376).to_bytes(48, byteorder="big") - - -auto = Auto() - - -def kzg_to_versioned_hash( - kzg_commitment: bytes | int, # 48 bytes - blob_commitment_version_kzg: bytes | int = BLOB_COMMITMENT_VERSION_KZG, -) -> bytes: - """ - Calculates the versioned hash for a given KZG commitment. - """ - if isinstance(kzg_commitment, int): - kzg_commitment = kzg_commitment.to_bytes(48, "big") - if isinstance(blob_commitment_version_kzg, int): - blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, "big") - return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:] - - -StorageDictType = Dict[str | int | bytes, str | int | bytes] - @pytest.fixture def precompile_input( diff --git a/tests/eips/eip4844/test_point_evaluation_precompile_gas.py b/tests/eips/eip4844/test_point_evaluation_precompile_gas.py index 8931b393d3..21991656a4 100644 --- a/tests/eips/eip4844/test_point_evaluation_precompile_gas.py +++ b/tests/eips/eip4844/test_point_evaluation_precompile_gas.py @@ -2,7 +2,6 @@ Test EIP-4844: Shard Blob Transactions (Point Evaluation Precompile) EIP: https://eips.ethereum.org/EIPS/eip-4844 """ -from hashlib import sha256 from typing import Dict, Literal import pytest @@ -19,30 +18,17 @@ ) from ethereum_test_tools.vm.opcode import Opcodes as Op +from .utils import ( + INF_POINT, + POINT_EVALUATION_PRECOMPILE_ADDRESS, + POINT_EVALUATION_PRECOMPILE_GAS, + Z, + kzg_to_versioned_hash, +) + REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4844.md" REFERENCE_SPEC_VERSION = "ac003985b9be74ff48bd897770e6d5f2e4318715" -POINT_EVALUATION_PRECOMPILE_ADDRESS = 20 -POINT_EVALUATION_PRECOMPILE_GAS = 50_000 -BLOB_COMMITMENT_VERSION_KZG = b"\x01" - -Z = 0x623CE31CF9759A5C8DAF3A357992F9F3DD7F9339D8998BC8E68373E54F00B75E -INF_POINT = (0xC0 << 376).to_bytes(48, byteorder="big") - - -def kzg_to_versioned_hash( - kzg_commitment: bytes | int, # 48 bytes - blob_commitment_version_kzg: bytes | int = BLOB_COMMITMENT_VERSION_KZG, -) -> bytes: - """ - Calculates the versioned hash for a given KZG commitment. - """ - if isinstance(kzg_commitment, int): - kzg_commitment = kzg_commitment.to_bytes(48, "big") - if isinstance(blob_commitment_version_kzg, int): - blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, "big") - return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:] - @pytest.fixture def precompile_input(proof: Literal["correct", "incorrect"]) -> bytes: diff --git a/tests/eips/eip4844/util_blobhash.py b/tests/eips/eip4844/utils.py similarity index 76% rename from tests/eips/eip4844/util_blobhash.py rename to tests/eips/eip4844/utils.py index 69f13f90d1..ad4146e6dc 100644 --- a/tests/eips/eip4844/util_blobhash.py +++ b/tests/eips/eip4844/utils.py @@ -4,11 +4,14 @@ > test_blobhash_opcode_contexts.py > test_blobhash_opcode.py """ -from typing import Union +from hashlib import sha256 +from typing import Literal, Union from ethereum_test_tools import ( + Auto, TestAddress, YulCompiler, + Transaction, add_kzg_version, compute_create2_address, compute_create_address, @@ -16,10 +19,109 @@ ) from ethereum_test_tools.vm.opcode import Opcodes as Op +auto = Auto() + + +# Constants +BLOB_COMMITMENT_VERSION_KZG = 1 BLOBHASH_GAS_COST = 3 -TARGET_BLOB_PER_BLOCK = 2 +BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 +BLS_MODULUS_BYTES = BLS_MODULUS.to_bytes(32, "big") +DATA_GAS_PER_BLOB = 2**17 +DATA_GASPRICE_UPDATE_FRACTION = 2225652 +FIELD_ELEMENTS_PER_BLOB = 4096 +FIELD_ELEMENTS_PER_BLOB_BYTES = FIELD_ELEMENTS_PER_BLOB.to_bytes(32, "big") +INF_POINT = (0xC0 << 376).to_bytes(48, byteorder="big") MAX_BLOB_PER_BLOCK = 4 -BLOB_COMMITMENT_VERSION_KZG = 1 +MAX_DATA_GAS_PER_BLOCK = 2**19 +MAX_BLOBS_PER_BLOCK = MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB +MIN_DATA_GASPRICE = 1 +POINT_EVALUATION_PRECOMPILE_ADDRESS = 20 +POINT_EVALUATION_PRECOMPILE_GAS = 50_000 +TARGET_BLOB_PER_BLOCK = 2 +TARGET_DATA_GAS_PER_BLOCK = 2**18 +TARGET_BLOBS_PER_BLOCK = TARGET_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB +Z = 0x623CE31CF9759A5C8DAF3A357992F9F3DD7F9339D8998BC8E68373E54F00B75E +Z_Y_INVALID_ENDIANNESS: Literal["little", "big"] = "little" +Z_Y_VALID_ENDIANNESS: Literal["little", "big"] = "big" + + +def fake_exponential(factor: int, numerator: int, denominator: int) -> int: + """ + Used to calculate the data gas cost. + """ + i = 1 + output = 0 + numerator_accumulator = factor * denominator + while numerator_accumulator > 0: + output += numerator_accumulator + numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i) + i += 1 + return output // denominator + + +def calc_data_fee(tx: Transaction, excess_data_gas: int) -> int: + """ + Calculate the data fee for a transaction. + """ + return get_total_data_gas(tx) * get_data_gasprice(excess_data_gas) + + +def get_total_data_gas(tx: Transaction) -> int: + """ + Calculate the total data gas for a transaction. + """ + if tx.blob_versioned_hashes is None: + return 0 + return DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) + + +def get_data_gasprice_from_blobs(excess_blobs: int) -> int: + """ + Calculate the data gas price from the excess blob count. + """ + return fake_exponential( + MIN_DATA_GASPRICE, + excess_blobs * DATA_GAS_PER_BLOB, + DATA_GASPRICE_UPDATE_FRACTION, + ) + + +def get_data_gasprice(excess_data_gas: int) -> int: + """ + Calculate the data gas price from the excess. + """ + return fake_exponential( + MIN_DATA_GASPRICE, + excess_data_gas, + DATA_GASPRICE_UPDATE_FRACTION, + ) + + +def calc_excess_data_gas(parent_excess_data_gas: int, parent_blobs: int) -> int: + """ + Calculate the excess data gas for a block given the parent excess data gas + and the number of blobs in the block. + """ + parent_consumed_data_gas = parent_blobs * DATA_GAS_PER_BLOB + if parent_excess_data_gas + parent_consumed_data_gas < TARGET_DATA_GAS_PER_BLOCK: + return 0 + else: + return parent_excess_data_gas + parent_consumed_data_gas - TARGET_DATA_GAS_PER_BLOCK + + +def kzg_to_versioned_hash( + kzg_commitment: bytes | int, # 48 bytes + blob_commitment_version_kzg: bytes | int = BLOB_COMMITMENT_VERSION_KZG, +) -> bytes: + """ + Calculates the versioned hash for a given KZG commitment. + """ + if isinstance(kzg_commitment, int): + kzg_commitment = kzg_commitment.to_bytes(48, "big") + if isinstance(blob_commitment_version_kzg, int): + blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, "big") + return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:] # Simple list of blob versioned hashes ranging from bytes32(1 to 4) From 5f0182f69111aa8b967573a6e4381600b277586d Mon Sep 17 00:00:00 2001 From: marioevz Date: Thu, 8 Jun 2023 21:07:52 +0000 Subject: [PATCH 04/21] fillers/4844: fix typo --- tests/eips/eip4844/test_blobhash_opcode.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/eips/eip4844/test_blobhash_opcode.py b/tests/eips/eip4844/test_blobhash_opcode.py index ef9f5fc06c..11f01e6da8 100644 --- a/tests/eips/eip4844/test_blobhash_opcode.py +++ b/tests/eips/eip4844/test_blobhash_opcode.py @@ -19,8 +19,8 @@ from .utils import ( BLOBHASH_GAS_COST, - MAX_BLOB_PER_BLOCK, - TARGET_BLOB_PER_BLOCK, + MAX_BLOBS_PER_BLOCK, + TARGET_BLOBS_PER_BLOCK, BlobhashScenario, blobhash_index_values, random_blob_hashes, @@ -71,7 +71,7 @@ def _blob_tx(address, type, nonce): to=address, access_list=[], max_priority_fee_per_gas=10, - blob_versioned_hashes=random_blob_hashes[0:MAX_BLOB_PER_BLOCK], + blob_versioned_hashes=random_blob_hashes[0:MAX_BLOBS_PER_BLOCK], ) return _blob_tx @@ -114,7 +114,7 @@ def test_blobhash_gas_cost( gas_price=10 if tx_type < 2 else None, access_list=[] if tx_type >= 2 else None, max_priority_fee_per_gas=10 if tx_type >= 2 else None, - blob_versioned_hashes=random_blob_hashes[0:TARGET_BLOB_PER_BLOCK] + blob_versioned_hashes=random_blob_hashes[0:TARGET_BLOBS_PER_BLOCK] if tx_type >= 3 else None, ) @@ -174,7 +174,7 @@ def test_blobhash_scenarios( ) ) post[address] = Account( - storage={index: b_hashes_list[i][index] for index in range(MAX_BLOB_PER_BLOCK)} + storage={index: b_hashes_list[i][index] for index in range(MAX_BLOBS_PER_BLOCK)} ) blockchain_test( pre=pre, @@ -212,7 +212,7 @@ def test_blobhash_invalid_blob_index( for i in range(TOTAL_BLOCKS): address = to_address(0x100 + i * 0x100) pre[address] = Account(code=blobhash_calls) - blob_per_block = (i % MAX_BLOB_PER_BLOCK) + 1 + blob_per_block = (i % MAX_BLOBS_PER_BLOCK) + 1 blobs = [random_blob_hashes[blob] for blob in range(blob_per_block)] blocks.append( Block( @@ -233,7 +233,7 @@ def test_blobhash_invalid_blob_index( index: (0 if index < 0 or index >= blob_per_block else blobs[index]) for index in range( -TOTAL_BLOCKS, - blob_per_block + (TOTAL_BLOCKS - (i % MAX_BLOB_PER_BLOCK)), + blob_per_block + (TOTAL_BLOCKS - (i % MAX_BLOBS_PER_BLOCK)), ) } ) @@ -287,10 +287,10 @@ def test_blobhash_multiple_txs_in_block( ] post = { to_address(address): Account( - storage={i: random_blob_hashes[i] for i in range(MAX_BLOB_PER_BLOCK)} + storage={i: random_blob_hashes[i] for i in range(MAX_BLOBS_PER_BLOCK)} ) if address in (0x200, 0x400) - else Account(storage={i: 0 for i in range(MAX_BLOB_PER_BLOCK)}) + else Account(storage={i: 0 for i in range(MAX_BLOBS_PER_BLOCK)}) for address in range(0x100, 0x500, 0x100) } blockchain_test( From 77feaa711a58c8ced2d033943e1730416431fdb3 Mon Sep 17 00:00:00 2001 From: marioevz Date: Thu, 8 Jun 2023 21:13:15 +0000 Subject: [PATCH 05/21] fillers/4844: fix typo, utils --- tests/eips/eip4844/utils.py | 52 ++++++++++++------------------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/tests/eips/eip4844/utils.py b/tests/eips/eip4844/utils.py index ad4146e6dc..422a9d40db 100644 --- a/tests/eips/eip4844/utils.py +++ b/tests/eips/eip4844/utils.py @@ -32,13 +32,11 @@ FIELD_ELEMENTS_PER_BLOB = 4096 FIELD_ELEMENTS_PER_BLOB_BYTES = FIELD_ELEMENTS_PER_BLOB.to_bytes(32, "big") INF_POINT = (0xC0 << 376).to_bytes(48, byteorder="big") -MAX_BLOB_PER_BLOCK = 4 MAX_DATA_GAS_PER_BLOCK = 2**19 MAX_BLOBS_PER_BLOCK = MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB MIN_DATA_GASPRICE = 1 POINT_EVALUATION_PRECOMPILE_ADDRESS = 20 POINT_EVALUATION_PRECOMPILE_GAS = 50_000 -TARGET_BLOB_PER_BLOCK = 2 TARGET_DATA_GAS_PER_BLOCK = 2**18 TARGET_BLOBS_PER_BLOCK = TARGET_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB Z = 0x623CE31CF9759A5C8DAF3A357992F9F3DD7F9339D8998BC8E68373E54F00B75E @@ -60,13 +58,6 @@ def fake_exponential(factor: int, numerator: int, denominator: int) -> int: return output // denominator -def calc_data_fee(tx: Transaction, excess_data_gas: int) -> int: - """ - Calculate the data fee for a transaction. - """ - return get_total_data_gas(tx) * get_data_gasprice(excess_data_gas) - - def get_total_data_gas(tx: Transaction) -> int: """ Calculate the total data gas for a transaction. @@ -76,18 +67,7 @@ def get_total_data_gas(tx: Transaction) -> int: return DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) -def get_data_gasprice_from_blobs(excess_blobs: int) -> int: - """ - Calculate the data gas price from the excess blob count. - """ - return fake_exponential( - MIN_DATA_GASPRICE, - excess_blobs * DATA_GAS_PER_BLOB, - DATA_GASPRICE_UPDATE_FRACTION, - ) - - -def get_data_gasprice(excess_data_gas: int) -> int: +def get_data_gasprice(*, excess_data_gas: int) -> int: """ Calculate the data gas price from the excess. """ @@ -98,7 +78,7 @@ def get_data_gasprice(excess_data_gas: int) -> int: ) -def calc_excess_data_gas(parent_excess_data_gas: int, parent_blobs: int) -> int: +def calc_excess_data_gas(*, parent_excess_data_gas: int, parent_blobs: int) -> int: """ Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. @@ -126,7 +106,7 @@ def kzg_to_versioned_hash( # Simple list of blob versioned hashes ranging from bytes32(1 to 4) simple_blob_hashes: list[bytes] = add_kzg_version( - [(1 << x) for x in range(MAX_BLOB_PER_BLOCK)], + [(1 << x) for x in range(MAX_BLOBS_PER_BLOCK)], BLOB_COMMITMENT_VERSION_KZG, ) @@ -362,23 +342,23 @@ class BlobhashScenario: @staticmethod def create_blob_hashes_list(length: int) -> list[list[bytes]]: """ - Creates a list of MAX_BLOB_PER_BLOCK blob hashes + Creates a list of MAX_BLOBS_PER_BLOCK blob hashes using `random_blob_hashes`. Cycle over random_blob_hashes to get a large list of - length: MAX_BLOB_PER_BLOCK * length + length: MAX_BLOBS_PER_BLOCK * length -> [0x01, 0x02, 0x03, 0x04, ..., 0x0A, 0x0B, 0x0C, 0x0D] - Then split list into smaller chunks of MAX_BLOB_PER_BLOCK + Then split list into smaller chunks of MAX_BLOBS_PER_BLOCK -> [[0x01, 0x02, 0x03, 0x04], ..., [0x0a, 0x0b, 0x0c, 0x0d]] """ b_hashes = [ random_blob_hashes[i % len(random_blob_hashes)] - for i in range(MAX_BLOB_PER_BLOCK * length) + for i in range(MAX_BLOBS_PER_BLOCK * length) ] return [ - b_hashes[i : i + MAX_BLOB_PER_BLOCK] - for i in range(0, len(b_hashes), MAX_BLOB_PER_BLOCK) + b_hashes[i : i + MAX_BLOBS_PER_BLOCK] + for i in range(0, len(b_hashes), MAX_BLOBS_PER_BLOCK) ] @staticmethod @@ -391,7 +371,7 @@ def blobhash_sstore(index: int): the BLOBHASH sstore. """ invalidity_check = Op.SSTORE(index, 0x01) - if index < 0 or index >= MAX_BLOB_PER_BLOCK: + if index < 0 or index >= MAX_BLOBS_PER_BLOCK: return invalidity_check + Op.SSTORE(index, Op.BLOBHASH(index)) return Op.SSTORE(index, Op.BLOBHASH(index)) @@ -401,23 +381,23 @@ def generate_blobhash_bytecode(cls, scenario_name: str) -> bytes: Returns BLOBHASH bytecode for the given scenario. """ scenarios = { - "single_valid": b"".join(cls.blobhash_sstore(i) for i in range(MAX_BLOB_PER_BLOCK)), + "single_valid": b"".join(cls.blobhash_sstore(i) for i in range(MAX_BLOBS_PER_BLOCK)), "repeated_valid": b"".join( b"".join(cls.blobhash_sstore(i) for _ in range(10)) - for i in range(MAX_BLOB_PER_BLOCK) + for i in range(MAX_BLOBS_PER_BLOCK) ), "valid_invalid": b"".join( cls.blobhash_sstore(i) - + cls.blobhash_sstore(MAX_BLOB_PER_BLOCK) + + cls.blobhash_sstore(MAX_BLOBS_PER_BLOCK) + cls.blobhash_sstore(i) - for i in range(MAX_BLOB_PER_BLOCK) + for i in range(MAX_BLOBS_PER_BLOCK) ), "varied_valid": b"".join( cls.blobhash_sstore(i) + cls.blobhash_sstore(i + 1) + cls.blobhash_sstore(i) - for i in range(MAX_BLOB_PER_BLOCK - 1) + for i in range(MAX_BLOBS_PER_BLOCK - 1) ), "invalid_calls": b"".join( - cls.blobhash_sstore(i) for i in range(-5, MAX_BLOB_PER_BLOCK + 5) + cls.blobhash_sstore(i) for i in range(-5, MAX_BLOBS_PER_BLOCK + 5) ), } scenario = scenarios.get(scenario_name) From 2dc36935cd130662b30bf31bc754d568f590d320 Mon Sep 17 00:00:00 2001 From: marioevz Date: Thu, 8 Jun 2023 21:26:38 +0000 Subject: [PATCH 06/21] fillers/4844: fix blob tx utils usage --- tests/eips/eip4844/test_blob_txs.py | 36 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/tests/eips/eip4844/test_blob_txs.py b/tests/eips/eip4844/test_blob_txs.py index aaccdaea3a..bfd0221120 100644 --- a/tests/eips/eip4844/test_blob_txs.py +++ b/tests/eips/eip4844/test_blob_txs.py @@ -23,6 +23,8 @@ BLOB_COMMITMENT_VERSION_KZG, DATA_GAS_PER_BLOB, MAX_BLOBS_PER_BLOCK, + TARGET_BLOBS_PER_BLOCK, + calc_excess_data_gas, get_data_gasprice, ) @@ -85,6 +87,16 @@ def parent_excess_blobs() -> Optional[int]: return 10 # Defaults to a data gas price of 1. +@pytest.fixture(autouse=True) +def parent_blobs() -> Optional[int]: + """ + Default data blobs of the parent blob. + + Can be overloaded by a test case to provide a custom parent blob count. + """ + return 0 + + @pytest.fixture def parent_excess_data_gas( parent_excess_blobs: Optional[int], @@ -100,13 +112,20 @@ def parent_excess_data_gas( @pytest.fixture def data_gasprice( parent_excess_data_gas: Optional[int], + parent_blobs: Optional[int], ) -> Optional[int]: """ Data gas price for the block of the test. """ - if parent_excess_data_gas is None: + if parent_excess_data_gas is None or parent_blobs is None: return None - return get_data_gasprice(excess_data_gas=parent_excess_data_gas) + + return get_data_gasprice( + excess_data_gas=calc_excess_data_gas( + parent_excess_data_gas=parent_excess_data_gas, + parent_blobs=parent_blobs, + ), + ) @pytest.fixture @@ -279,11 +298,16 @@ def pre( # noqa: D103 @pytest.fixture def env( parent_excess_data_gas: Optional[int], + parent_blobs: Optional[int], ) -> Environment: """ Prepare the environment for all test cases. """ - return Environment(excess_data_gas=parent_excess_data_gas) + if parent_blobs is None: + parent_blobs = 0 + return Environment( + excess_data_gas=parent_excess_data_gas, data_gas_used=parent_blobs * DATA_GAS_PER_BLOB + ) @pytest.fixture @@ -370,17 +394,19 @@ def test_valid_blob_tx_combinations( @pytest.mark.parametrize( - "parent_excess_blobs,tx_max_fee_per_data_gas,tx_error", + "parent_excess_blobs,parent_blobs,tx_max_fee_per_data_gas,tx_error", [ # tx max_data_gas_cost of the transaction is not enough ( - 12, # data gas price is 2 + 11, # data gas price is 2 + TARGET_BLOBS_PER_BLOCK + 1, # data gas cost increases to 2 1, # tx max_data_gas_cost is 1 "insufficient max fee per data gas", ), # tx max_data_gas_cost of the transaction is zero, which is invalid ( 0, # data gas price is 1 + 0, # data gas cost stays put at 1 0, # tx max_data_gas_cost is 0 "invalid max fee per data gas", ), From d14a48195f30c534ec4e06ab8fe69575dbd576a9 Mon Sep 17 00:00:00 2001 From: marioevz Date: Fri, 9 Jun 2023 16:47:56 +0000 Subject: [PATCH 07/21] fillers/eip4844: Remove initcode ctx test --- .../eips/eip4844/test_blobhash_opcode_contexts.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/eips/eip4844/test_blobhash_opcode_contexts.py b/tests/eips/eip4844/test_blobhash_opcode_contexts.py index 2c81a374f3..f89654f3cd 100644 --- a/tests/eips/eip4844/test_blobhash_opcode_contexts.py +++ b/tests/eips/eip4844/test_blobhash_opcode_contexts.py @@ -191,21 +191,6 @@ def opcode_context(yul: YulCompiler, request): ), }, ) - elif test_case == "on_INITCODE": - return create_opcode_context( - {}, - tx_type_3.with_fields( - data=BlobhashContext.code("initcode"), - to=None, - ), - { - BlobhashContext.created_contract("tx_created_contract"): Account( - storage={ - k: v for (k, v) in zip(range(len(simple_blob_hashes)), simple_blob_hashes) - } - ), - }, - ) elif test_case == "on_CREATE": return create_opcode_context( { From 0c282e32011046e58517dabd62e48232b55b8357 Mon Sep 17 00:00:00 2001 From: marioevz Date: Fri, 9 Jun 2023 17:14:34 +0000 Subject: [PATCH 08/21] tests/4844: Add opcode tests to blob txs info --- tests/eips/eip4844/test_blob_txs.py | 265 ++++++++++++++++++++++++++-- whitelist.txt | 1 + 2 files changed, 254 insertions(+), 12 deletions(-) diff --git a/tests/eips/eip4844/test_blob_txs.py b/tests/eips/eip4844/test_blob_txs.py index bfd0221120..9cf232fd1d 100644 --- a/tests/eips/eip4844/test_blob_txs.py +++ b/tests/eips/eip4844/test_blob_txs.py @@ -7,14 +7,14 @@ import pytest +from ethereum_test_tools import Account, Block, BlockchainTestFiller, Environment +from ethereum_test_tools import Opcodes as Op from ethereum_test_tools import ( - Account, - Block, - BlockchainTestFiller, - Environment, + Storage, TestAddress, Transaction, add_kzg_version, + eip_2028_transaction_data_cost, to_address, to_hash_bytes, ) @@ -70,6 +70,12 @@ def tx_gas() -> int: return 21000 +@pytest.fixture +def tx_calldata() -> bytes: + """Default calldata in transactions sent during test.""" + return b"" + + @pytest.fixture def block_fee_per_gas() -> int: """Default max fee per gas for transactions sent during test.""" @@ -174,7 +180,8 @@ def blob_hashes_per_tx(blobs_per_tx: List[int]) -> List[List[bytes]]: def total_account_minimum_balance( # noqa: D103 tx_gas: int, tx_value: int, - block_fee_per_gas: int, + tx_calldata: bytes, + tx_max_fee_per_gas: int, tx_max_priority_fee_per_gas: int, data_gasprice: Optional[int], blob_hashes_per_tx: List[List[bytes]], @@ -190,7 +197,10 @@ def total_account_minimum_balance( # noqa: D103 for tx_blob_count in [len(x) for x in blob_hashes_per_tx]: data_cost = data_gasprice * DATA_GAS_PER_BLOB * tx_blob_count total_cost += ( - (tx_gas * (block_fee_per_gas + tx_max_priority_fee_per_gas)) + tx_value + data_cost + (tx_gas * (tx_max_fee_per_gas + tx_max_priority_fee_per_gas)) + + tx_value + + eip_2028_transaction_data_cost(tx_calldata) + + data_cost ) return total_cost @@ -226,26 +236,27 @@ def tx_max_fee_per_data_gas( # noqa: D103 @pytest.fixture -def tx_error() -> str: +def tx_error() -> Optional[str]: """ Default expected error produced by the block transactions (no error). Can be overloaded on test cases where the transactions are expected to fail. """ - return "" + return None @pytest.fixture(autouse=True) def txs( # noqa: D103 - destination_account: str, + destination_account: Optional[str], tx_gas: int, tx_value: int, + tx_calldata: bytes, tx_max_fee_per_gas: int, tx_max_fee_per_data_gas: int, tx_max_priority_fee_per_gas: int, blob_hashes_per_tx: List[List[bytes]], - tx_error: str, + tx_error: Optional[str], ) -> List[Transaction]: """ Prepare the list of transactions that are sent during the test. @@ -257,6 +268,7 @@ def txs( # noqa: D103 to=destination_account, value=tx_value, gas_limit=tx_gas, + data=tx_calldata, max_fee_per_gas=tx_max_fee_per_gas, max_priority_fee_per_gas=tx_max_priority_fee_per_gas, max_fee_per_data_gas=tx_max_fee_per_data_gas, @@ -311,9 +323,9 @@ def env( @pytest.fixture -def blocks( # noqa: D103 +def blocks( txs: List[Transaction], - tx_error: str, + tx_error: Optional[str], ) -> List[Block]: """ Prepare the list of blocks for all test cases. @@ -489,6 +501,11 @@ def test_invalid_block_blob_count( @pytest.mark.parametrize("tx_max_priority_fee_per_gas", [0, 8]) @pytest.mark.parametrize("tx_value", [0, 1]) +@pytest.mark.parametrize( + "tx_calldata", + [b"", b"\x00", b"\x01"], + ids=["no_calldata", "single_zero_calldata", "single_one_calldata"], +) @pytest.mark.parametrize("account_balance_modifier", [-1], ids=["exact_balance_minus_1"]) @pytest.mark.parametrize("tx_error", ["insufficient_account_balance"], ids=[""]) @pytest.mark.valid_from("Cancun") @@ -621,6 +638,230 @@ def test_invalid_blob_hash_versioning( ) +@pytest.mark.parametrize( + "destination_account,tx_error", [(None, "no_contract_creating_blob_txs")], ids=[""] +) +@pytest.mark.valid_from("Cancun") +def test_invalid_blob_tx_contract_creation( + blockchain_test: BlockchainTestFiller, + pre: Dict, + env: Environment, + blocks: List[Block], +): + """ + Reject blocks that include blob transactions that have nil to value (contract creating). + """ + blockchain_test( + pre=pre, + post={}, + blocks=blocks, + genesis_environment=env, + ) + + +# ---------------------------------------- +# Opcode Tests in Blob Transaction Context +# ---------------------------------------- + + +@pytest.fixture +def opcode( + request, + tx_calldata: bytes, + block_fee_per_gas: int, + tx_max_fee_per_gas: int, + tx_max_priority_fee_per_gas: int, + tx_value: int, +) -> Tuple[bytes, Storage.StorageDictType]: + """ + Build bytecode and post to test each opcode that accesses transaction information. + """ + if request.param == Op.ORIGIN: + return ( + Op.SSTORE(0, Op.ORIGIN), + {0: TestAddress}, + ) + elif request.param == Op.CALLER: + return ( + Op.SSTORE(0, Op.CALLER), + {0: TestAddress}, + ) + elif request.param == Op.CALLVALUE: + return ( + Op.SSTORE(0, Op.CALLVALUE), + {0: tx_value}, + ) + elif request.param == Op.CALLDATALOAD: + return ( + Op.SSTORE(0, Op.CALLDATALOAD(0)), + {0: tx_calldata.ljust(32, b"\x00")}, + ) + elif request.param == Op.CALLDATASIZE: + return ( + Op.SSTORE(0, Op.CALLDATASIZE), + {0: len(tx_calldata)}, + ) + elif request.param == Op.CALLDATACOPY: + return ( + Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + Op.SSTORE(0, Op.MLOAD(0)), + {0: tx_calldata.ljust(32, b"\x00")}, + ) + elif request.param == Op.GASPRICE: + assert tx_max_fee_per_gas >= block_fee_per_gas + return ( + Op.SSTORE(0, Op.GASPRICE), + { + 0: min(tx_max_priority_fee_per_gas, tx_max_fee_per_gas - block_fee_per_gas) + + block_fee_per_gas + }, + ) + raise Exception("Unknown opcode") + + +@pytest.mark.parametrize( + "opcode", + [Op.ORIGIN, Op.CALLER], + indirect=["opcode"], +) +@pytest.mark.parametrize("tx_gas", [500_000]) +@pytest.mark.valid_from("Cancun") +def test_blob_tx_attribute_opcodes( + blockchain_test: BlockchainTestFiller, + pre: Dict, + opcode: Tuple[bytes, Storage.StorageDictType], + env: Environment, + blocks: List[Block], + destination_account: str, +): + """ + Test opcodes that read transaction attributes work properly for blob txs. + """ + code, storage = opcode + pre[destination_account] = Account(code=code) + post = { + destination_account: Account( + storage=storage, + ) + } + blockchain_test( + pre=pre, + post=post, + blocks=blocks, + genesis_environment=env, + ) + + +@pytest.mark.parametrize("opcode", [Op.CALLVALUE], indirect=["opcode"]) +@pytest.mark.parametrize("tx_value", [0, 1, int(1e18)]) +@pytest.mark.parametrize("tx_gas", [500_000]) +@pytest.mark.valid_from("Cancun") +def test_blob_tx_attribute_value_opcode( + blockchain_test: BlockchainTestFiller, + pre: Dict, + opcode: Tuple[bytes, Storage.StorageDictType], + env: Environment, + blocks: List[Block], + tx_value: int, + destination_account: str, +): + """ + Test the VALUE opcode with different blob tx value amounts. + """ + code, storage = opcode + pre[destination_account] = Account(code=code) + post = { + destination_account: Account( + storage=storage, + balance=tx_value, + ) + } + blockchain_test( + pre=pre, + post=post, + blocks=blocks, + genesis_environment=env, + ) + + +@pytest.mark.parametrize( + "opcode", + [ + Op.CALLDATALOAD, + Op.CALLDATASIZE, + Op.CALLDATACOPY, + ], + indirect=True, +) +@pytest.mark.parametrize( + "tx_calldata", + [ + b"", + b"\x01", + b"\x00\x01" * 16, + ], + ids=["empty", "single_byte", "word"], +) +@pytest.mark.parametrize("tx_gas", [500_000]) +@pytest.mark.valid_from("Cancun") +def test_blob_tx_attribute_calldata_opcodes( + blockchain_test: BlockchainTestFiller, + pre: Dict, + opcode: Tuple[bytes, Storage.StorageDictType], + env: Environment, + blocks: List[Block], + destination_account: str, +): + """ + Test calldata related opcodes to verify their behavior is not affected by blobs. + """ + code, storage = opcode + pre[destination_account] = Account(code=code) + post = { + destination_account: Account( + storage=storage, + ) + } + blockchain_test( + pre=pre, + post=post, + blocks=blocks, + genesis_environment=env, + ) + + +@pytest.mark.parametrize("tx_max_priority_fee_per_gas", [0, 2]) # always below data fee +@pytest.mark.parametrize("tx_max_fee_per_data_gas", [1, 3]) # normal and above priority fee +@pytest.mark.parametrize("tx_max_fee_per_gas", [100]) # always above priority fee +@pytest.mark.parametrize("opcode", [Op.GASPRICE], indirect=True) +@pytest.mark.parametrize("tx_gas", [500_000]) +@pytest.mark.valid_from("Cancun") +def test_blob_tx_attribute_gasprice_opcode( + blockchain_test: BlockchainTestFiller, + pre: Dict, + opcode: Tuple[bytes, Storage.StorageDictType], + env: Environment, + blocks: List[Block], + destination_account: str, +): + """ + Test GASPRICE opcode to sanity check that the data fee per gas does not affect + its calculation. + """ + code, storage = opcode + pre[destination_account] = Account(code=code) + post = { + destination_account: Account( + storage=storage, + ) + } + blockchain_test( + pre=pre, + post=post, + blocks=blocks, + genesis_environment=env, + ) + + @pytest.mark.parametrize( [ "blobs_per_tx", diff --git a/whitelist.txt b/whitelist.txt index 23fcc354ce..efe7292979 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -103,6 +103,7 @@ shl shr sar rjust +ljust keccak256 From cd534b00c96a57fc848ffe243e85ab22da286ae5 Mon Sep 17 00:00:00 2001 From: marioevz Date: Fri, 9 Jun 2023 19:39:38 +0000 Subject: [PATCH 09/21] tests/4844: Fix all excess data gas tests due to calc spec change --- tests/eips/eip4844/test_excess_data_gas.py | 119 +++++++++------------ 1 file changed, 50 insertions(+), 69 deletions(-) diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index fbe01cc11a..4b1e033c3b 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -3,7 +3,7 @@ EIP: https://eips.ethereum.org/EIPS/eip-4844 """ import itertools -from typing import List, Mapping, Optional +from typing import Iterator, List, Mapping, Optional, Tuple import pytest @@ -90,19 +90,14 @@ def header_excess_data_gas_delta() -> Optional[int]: # noqa: D103 @pytest.fixture def header_excess_data_gas( # noqa: D103 - parent_excess_data_gas: int, + correct_excess_data_gas: int, header_excess_blobs_delta: Optional[int], header_excess_data_gas_delta: Optional[int], ) -> Optional[int]: if header_excess_blobs_delta is not None: - return parent_excess_data_gas + (header_excess_blobs_delta * DATA_GAS_PER_BLOB) + return correct_excess_data_gas + (header_excess_blobs_delta * DATA_GAS_PER_BLOB) if header_excess_data_gas_delta is not None: - return parent_excess_data_gas + header_excess_data_gas_delta - return None - - -@pytest.fixture -def header_data_gas_used() -> Optional[int]: # noqa: D103 + return correct_excess_data_gas + header_excess_data_gas_delta return None @@ -220,6 +215,11 @@ def tx( # noqa: D103 ) +@pytest.fixture +def header_data_gas_used() -> Optional[int]: # noqa: D103 + return None + + @pytest.fixture def blocks( # noqa: D103 tx: Transaction, @@ -387,41 +387,22 @@ def test_invalid_zero_excess_data_gas_in_header( ) -@pytest.mark.parametrize("header_data_gas_used", [0]) -@pytest.mark.parametrize("new_blobs", range(1, MAX_BLOBS_PER_BLOCK + 1)) -@pytest.mark.parametrize("parent_blobs", [0]) -def test_invalid_zero_data_gas_used_in_header( - blockchain_test: BlockchainTestFiller, - env: Environment, - pre: Mapping[str, Account], - blocks: List[Block], - new_blobs: int, - header_data_gas_used: Optional[int], -): +def all_invalid_data_gas_used_combinations() -> Iterator[Tuple[int, int]]: """ - Test rejection of blocks where the data_gas_used in the header is zero in - a block with data blobs. + Returns all invalid data gas used combinations. """ - if header_data_gas_used is None: - raise Exception("test case is badly formatted") - blockchain_test( - pre=pre, - post={}, - blocks=blocks, - genesis_environment=env, - tag="-".join( - [ - f"correct:{hex(new_blobs * DATA_GAS_PER_BLOB)}", - f"header:{hex(header_data_gas_used)}", - ] - ), - ) + for new_blobs in range(0, MAX_BLOBS_PER_BLOCK + 1): + for header_data_gas_used in range(0, MAX_BLOBS_PER_BLOCK + 1): + if new_blobs != header_data_gas_used: + yield (new_blobs, header_data_gas_used * DATA_GAS_PER_BLOB) -@pytest.mark.parametrize("header_data_gas_used", [DATA_GAS_PER_BLOB]) -@pytest.mark.parametrize("new_blobs", [1]) +@pytest.mark.parametrize( + "new_blobs,header_data_gas_used", + all_invalid_data_gas_used_combinations(), +) @pytest.mark.parametrize("parent_blobs", [0]) -def test_invalid_non_zero_data_gas_used_in_header( +def test_invalid_data_gas_used_in_header( blockchain_test: BlockchainTestFiller, env: Environment, pre: Mapping[str, Account], @@ -450,10 +431,11 @@ def test_invalid_non_zero_data_gas_used_in_header( @pytest.mark.parametrize( - "header_excess_blobs_delta", - [-(TARGET_BLOBS_PER_BLOCK + 1), (TARGET_BLOBS_PER_BLOCK + 1)], + "header_excess_blobs_delta,parent_blobs", + [(-1, 0), (1, MAX_BLOBS_PER_BLOCK)], + ids=["zero_blobs_decrease_more_than_expected", "max_blobs_increase_more_than_expected"], ) -@pytest.mark.parametrize("new_blobs", range(0, MAX_BLOBS_PER_BLOCK + 1)) +@pytest.mark.parametrize("new_blobs", [1]) def test_invalid_excess_data_gas_above_target_change( blockchain_test: BlockchainTestFiller, env: Environment, @@ -486,29 +468,25 @@ def test_invalid_excess_data_gas_above_target_change( ) -@pytest.mark.parametrize("header_excess_blobs_delta", [0]) @pytest.mark.parametrize( - "new_blobs", + "parent_blobs", [b for b in range(0, MAX_BLOBS_PER_BLOCK + 1) if b != TARGET_BLOBS_PER_BLOCK], ) +@pytest.mark.parametrize("parent_excess_blobs", [1, TARGET_BLOBS_PER_BLOCK]) +@pytest.mark.parametrize("new_blobs", [1]) def test_invalid_static_excess_data_gas( blockchain_test: BlockchainTestFiller, env: Environment, pre: Mapping[str, Account], blocks: List[Block], correct_excess_data_gas: int, - header_excess_data_gas: Optional[int], + parent_excess_data_gas: int, ): """ Test rejection of blocks where the excess_data_gas remains unchanged - but the blobs included are not TARGET_BLOBS_PER_BLOCK. + but the parent blobs included are not TARGET_BLOBS_PER_BLOCK. """ - if header_excess_data_gas is None: - raise Exception("test case is badly formatted") - - if header_excess_data_gas == correct_excess_data_gas: - raise Exception("invalid test case") - + blocks[0].rlp_modifier = Header(excess_data_gas=parent_excess_data_gas) blockchain_test( pre=pre, post={}, @@ -517,15 +495,16 @@ def test_invalid_static_excess_data_gas( tag="-".join( [ f"correct:{hex(correct_excess_data_gas)}", - f"header:{hex(header_excess_data_gas)}", + f"header:{hex(parent_excess_data_gas)}", ] ), ) @pytest.mark.parametrize("header_excess_blobs_delta", range(1, MAX_BLOBS_PER_BLOCK)) -@pytest.mark.parametrize("new_blobs", range(0, TARGET_BLOBS_PER_BLOCK + 1)) +@pytest.mark.parametrize("parent_blobs", range(0, TARGET_BLOBS_PER_BLOCK + 1)) @pytest.mark.parametrize("parent_excess_blobs", [0]) # Start at 0 +@pytest.mark.parametrize("new_blobs", [1]) def test_invalid_excess_data_gas_target_blobs_increase_from_zero( blockchain_test: BlockchainTestFiller, env: Environment, @@ -558,9 +537,12 @@ def test_invalid_excess_data_gas_target_blobs_increase_from_zero( ) -@pytest.mark.parametrize("header_excess_blobs_delta", [0]) -@pytest.mark.parametrize("new_blobs", range(TARGET_BLOBS_PER_BLOCK + 1, MAX_BLOBS_PER_BLOCK + 1)) +@pytest.mark.parametrize("header_excess_data_gas", [0]) +@pytest.mark.parametrize( + "parent_blobs", range(TARGET_BLOBS_PER_BLOCK + 1, MAX_BLOBS_PER_BLOCK + 1) +) @pytest.mark.parametrize("parent_excess_blobs", [0]) # Start at 0 +@pytest.mark.parametrize("new_blobs", [1]) def test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target( blockchain_test: BlockchainTestFiller, env: Environment, @@ -594,18 +576,15 @@ def test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target( @pytest.mark.parametrize( - "new_blobs,header_excess_blobs_delta", - [ - c - for c in itertools.product( - # new_blobs - range(0, MAX_BLOBS_PER_BLOCK + 1), - # header_excess_blobs_delta - range(-TARGET_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK + 1), - ) - if c[1] != c[0] - TARGET_BLOBS_PER_BLOCK # Only get incorrect combinations - ], + "parent_blobs,header_excess_blobs_delta", + itertools.product( + # parent_blobs + range(0, MAX_BLOBS_PER_BLOCK + 1), + # header_excess_blobs_delta (from correct value) + [x for x in range(-TARGET_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK + 1) if x != 0], + ), ) +@pytest.mark.parametrize("new_blobs", [1]) def test_invalid_excess_data_gas_change( blockchain_test: BlockchainTestFiller, env: Environment, @@ -642,7 +621,8 @@ def test_invalid_excess_data_gas_change( "header_excess_data_gas", [(2**64 + (x * DATA_GAS_PER_BLOB)) for x in range(-TARGET_BLOBS_PER_BLOCK, 0)], ) -@pytest.mark.parametrize("new_blobs", range(TARGET_BLOBS_PER_BLOCK)) +@pytest.mark.parametrize("parent_blobs", range(TARGET_BLOBS_PER_BLOCK)) +@pytest.mark.parametrize("new_blobs", [1]) @pytest.mark.parametrize("parent_excess_blobs", range(TARGET_BLOBS_PER_BLOCK)) def test_invalid_negative_excess_data_gas( blockchain_test: BlockchainTestFiller, @@ -677,7 +657,7 @@ def test_invalid_negative_excess_data_gas( @pytest.mark.parametrize( - "new_blobs,header_excess_data_gas_delta", + "parent_blobs,header_excess_data_gas_delta", [ (TARGET_BLOBS_PER_BLOCK + 1, 1), (TARGET_BLOBS_PER_BLOCK + 1, DATA_GAS_PER_BLOB - 1), @@ -685,6 +665,7 @@ def test_invalid_negative_excess_data_gas( (TARGET_BLOBS_PER_BLOCK - 1, -(DATA_GAS_PER_BLOB - 1)), ], ) +@pytest.mark.parametrize("new_blobs", [1]) @pytest.mark.parametrize("parent_excess_blobs", [TARGET_BLOBS_PER_BLOCK + 1]) def test_invalid_non_multiple_excess_data_gas( blockchain_test: BlockchainTestFiller, From 677a20df01b2d476e9406b526d35da2fccad9899 Mon Sep 17 00:00:00 2001 From: marioevz Date: Fri, 9 Jun 2023 19:54:09 +0000 Subject: [PATCH 10/21] tests/4844: Test max value for data gas used --- tests/eips/eip4844/test_excess_data_gas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index 4b1e033c3b..aa2d9d6a43 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -395,6 +395,7 @@ def all_invalid_data_gas_used_combinations() -> Iterator[Tuple[int, int]]: for header_data_gas_used in range(0, MAX_BLOBS_PER_BLOCK + 1): if new_blobs != header_data_gas_used: yield (new_blobs, header_data_gas_used * DATA_GAS_PER_BLOB) + yield (new_blobs, 2**64 - 1) @pytest.mark.parametrize( From a4c99a13532a337947402b2c39c5b69fe236599c Mon Sep 17 00:00:00 2001 From: marioevz Date: Fri, 9 Jun 2023 19:54:28 +0000 Subject: [PATCH 11/21] tests/4844: Ensure blob tx tests contain the correct data gas used --- tests/eips/eip4844/test_blob_txs.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/eips/eip4844/test_blob_txs.py b/tests/eips/eip4844/test_blob_txs.py index 9cf232fd1d..2c40916a21 100644 --- a/tests/eips/eip4844/test_blob_txs.py +++ b/tests/eips/eip4844/test_blob_txs.py @@ -7,7 +7,7 @@ import pytest -from ethereum_test_tools import Account, Block, BlockchainTestFiller, Environment +from ethereum_test_tools import Account, Block, BlockchainTestFiller, Environment, Header from ethereum_test_tools import Opcodes as Op from ethereum_test_tools import ( Storage, @@ -330,11 +330,20 @@ def blocks( """ Prepare the list of blocks for all test cases. """ - return [ - Block( - txs=txs, - exception=tx_error, + header_data_gas_used = 0 + if len(txs) > 0: + header_data_gas_used = ( + sum( + [ + len(tx.blob_versioned_hashes) + for tx in txs + if tx.blob_versioned_hashes is not None + ] + ) + * DATA_GAS_PER_BLOB ) + return [ + Block(txs=txs, exception=tx_error, rlp_modifier=Header(data_gas_used=header_data_gas_used)) ] From 41b3e36bf839615785a1da5b854fdf5157bc4b00 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Mon, 12 Jun 2023 20:25:45 +0000 Subject: [PATCH 12/21] tests/eip4844: all spec changes from #7154 --- tests/eips/eip4844/test_blob_txs.py | 3 +- tests/eips/eip4844/test_excess_data_gas.py | 51 +++++++++---------- .../test_excess_data_gas_fork_transition.py | 17 +++++-- tests/eips/eip4844/utils.py | 25 +++++++-- 4 files changed, 60 insertions(+), 36 deletions(-) diff --git a/tests/eips/eip4844/test_blob_txs.py b/tests/eips/eip4844/test_blob_txs.py index 2c40916a21..f2dec9d339 100644 --- a/tests/eips/eip4844/test_blob_txs.py +++ b/tests/eips/eip4844/test_blob_txs.py @@ -26,6 +26,7 @@ TARGET_BLOBS_PER_BLOCK, calc_excess_data_gas, get_data_gasprice, + get_min_excess_data_blobs_for_data_gas_price, ) # * Adding a new test * @@ -419,7 +420,7 @@ def test_valid_blob_tx_combinations( [ # tx max_data_gas_cost of the transaction is not enough ( - 11, # data gas price is 2 + get_min_excess_data_blobs_for_data_gas_price(2) - 1, # data gas price is 1 TARGET_BLOBS_PER_BLOCK + 1, # data gas cost increases to 2 1, # tx max_data_gas_cost is 1 "insufficient max fee per data gas", diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index aa2d9d6a43..11d724b7d6 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -27,6 +27,7 @@ TARGET_BLOBS_PER_BLOCK, calc_excess_data_gas, get_data_gasprice, + get_min_excess_data_blobs_for_data_gas_price, ) # * Adding a new test * @@ -95,7 +96,12 @@ def header_excess_data_gas( # noqa: D103 header_excess_data_gas_delta: Optional[int], ) -> Optional[int]: if header_excess_blobs_delta is not None: - return correct_excess_data_gas + (header_excess_blobs_delta * DATA_GAS_PER_BLOB) + modified_excess_data_gas = correct_excess_data_gas + ( + header_excess_blobs_delta * DATA_GAS_PER_BLOB + ) + if modified_excess_data_gas < 0: + modified_excess_data_gas = 2**64 + (modified_excess_data_gas) + return modified_excess_data_gas if header_excess_data_gas_delta is not None: return correct_excess_data_gas + header_excess_data_gas_delta return None @@ -273,22 +279,24 @@ def test_correct_excess_data_gas_calculation( ) +DATA_GAS_COST_INCREASES = [ + get_min_excess_data_blobs_for_data_gas_price(i) + for i in [ + 2, # First data gas cost increase + 2**32 // DATA_GAS_PER_BLOB, # Data tx wei cost 2^32 + 2**32, # Data gas cost 2^32 + 2**64 // DATA_GAS_PER_BLOB, # Data tx wei cost 2^64 + 2**64, # Data gas cost 2^64 + ( + 120_000_000 * (10**18) // DATA_GAS_PER_BLOB + ), # Data tx wei is current total Ether supply + ] +] + + @pytest.mark.parametrize( "parent_excess_blobs", - [ - # Data gas cost increase to 2 - 11, - # Data tx wei cost increase to 2^32 - 176, - # Data gas cost increase to 2^32 - 376, - # Data tx wei cost increase to 2^64 - 553, - # Data gas cost increase to 2^64 - 753, - # Data tx wei cost increase to main net current total Ether supply - 820, - ], + [g - 1 for g in DATA_GAS_COST_INCREASES], ) @pytest.mark.parametrize("parent_blobs", [TARGET_BLOBS_PER_BLOCK + 1]) @pytest.mark.parametrize("new_blobs", [1]) @@ -315,18 +323,7 @@ def test_correct_increasing_data_gas_costs( @pytest.mark.parametrize( "parent_excess_blobs", - [ - # Data gas cost decrease to 1 - 12, - # Data tx wei cost decrease from 2^32 - 177, - # Data gas cost decrease from 2^32 - 377, - # Data tx wei cost decrease from 2^64 - 554, - # Data gas cost decrease from 2^64 - 754, - ], + [g for g in DATA_GAS_COST_INCREASES], ) @pytest.mark.parametrize("parent_blobs", [TARGET_BLOBS_PER_BLOCK - 1]) @pytest.mark.parametrize("new_blobs", [1]) diff --git a/tests/eips/eip4844/test_excess_data_gas_fork_transition.py b/tests/eips/eip4844/test_excess_data_gas_fork_transition.py index d26130556e..d4d35d4e2f 100644 --- a/tests/eips/eip4844/test_excess_data_gas_fork_transition.py +++ b/tests/eips/eip4844/test_excess_data_gas_fork_transition.py @@ -19,7 +19,12 @@ to_hash_bytes, ) -from .utils import BLOB_COMMITMENT_VERSION_KZG, MAX_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK +from .utils import ( + BLOB_COMMITMENT_VERSION_KZG, + MAX_BLOBS_PER_BLOCK, + TARGET_BLOBS_PER_BLOCK, + get_min_excess_data_blobs_for_data_gas_price, +) REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4844.md" REFERENCE_SPEC_VERSION = "ac003985b9be74ff48bd897770e6d5f2e4318715" @@ -30,8 +35,6 @@ # Timestamp of the fork FORK_TIMESTAMP = 15_000 -# Data gas cost increases from 1 to 2 at this amount of excess blobs -BLOBS_TO_DATA_GAS_COST_INCREASE = 12 @pytest.fixture @@ -59,7 +62,9 @@ def post_fork_block_count() -> int: """ Amount of blocks to produce with the post-fork rules. """ - return 12 + return get_min_excess_data_blobs_for_data_gas_price(2) // ( + MAX_BLOBS_PER_BLOCK - TARGET_BLOBS_PER_BLOCK + ) @pytest.fixture @@ -187,7 +192,9 @@ def test_invalid_post_fork_block_without_excess_data_gas( "post_fork_block_count,blob_count_per_block", [ ( - BLOBS_TO_DATA_GAS_COST_INCREASE // (MAX_BLOBS_PER_BLOCK - TARGET_BLOBS_PER_BLOCK) + 2, + get_min_excess_data_blobs_for_data_gas_price(2) + // (MAX_BLOBS_PER_BLOCK - TARGET_BLOBS_PER_BLOCK) + + 2, MAX_BLOBS_PER_BLOCK, ), (10, 0), diff --git a/tests/eips/eip4844/utils.py b/tests/eips/eip4844/utils.py index 422a9d40db..5ea03ff48c 100644 --- a/tests/eips/eip4844/utils.py +++ b/tests/eips/eip4844/utils.py @@ -28,16 +28,16 @@ BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 BLS_MODULUS_BYTES = BLS_MODULUS.to_bytes(32, "big") DATA_GAS_PER_BLOB = 2**17 -DATA_GASPRICE_UPDATE_FRACTION = 2225652 +DATA_GASPRICE_UPDATE_FRACTION = 3338477 FIELD_ELEMENTS_PER_BLOB = 4096 FIELD_ELEMENTS_PER_BLOB_BYTES = FIELD_ELEMENTS_PER_BLOB.to_bytes(32, "big") INF_POINT = (0xC0 << 376).to_bytes(48, byteorder="big") -MAX_DATA_GAS_PER_BLOCK = 2**19 +MAX_DATA_GAS_PER_BLOCK = 786432 MAX_BLOBS_PER_BLOCK = MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB MIN_DATA_GASPRICE = 1 POINT_EVALUATION_PRECOMPILE_ADDRESS = 20 POINT_EVALUATION_PRECOMPILE_GAS = 50_000 -TARGET_DATA_GAS_PER_BLOCK = 2**18 +TARGET_DATA_GAS_PER_BLOCK = 393216 TARGET_BLOBS_PER_BLOCK = TARGET_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB Z = 0x623CE31CF9759A5C8DAF3A357992F9F3DD7F9339D8998BC8E68373E54F00B75E Z_Y_INVALID_ENDIANNESS: Literal["little", "big"] = "little" @@ -78,6 +78,25 @@ def get_data_gasprice(*, excess_data_gas: int) -> int: ) +def get_min_excess_data_gas_for_data_gas_price(data_gas_price: int) -> int: + """ + Gets the minimum required excess data gas value to get a given data gas cost in a block + """ + current_excess_data_gas = 0 + current_data_gas_price = 1 + while current_data_gas_price < data_gas_price: + current_excess_data_gas += DATA_GAS_PER_BLOB + current_data_gas_price = get_data_gasprice(excess_data_gas=current_excess_data_gas) + return current_excess_data_gas + + +def get_min_excess_data_blobs_for_data_gas_price(data_gas_price: int) -> int: + """ + Gets the minimum required excess data blobs to get a given data gas cost in a block + """ + return get_min_excess_data_gas_for_data_gas_price(data_gas_price) // DATA_GAS_PER_BLOB + + def calc_excess_data_gas(*, parent_excess_data_gas: int, parent_blobs: int) -> int: """ Calculate the excess data gas for a block given the parent excess data gas From d9646f091ef87357f817ef254988397a26aa84df Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 13 Jun 2023 03:20:56 +0000 Subject: [PATCH 13/21] tests/eip4844: fix blobhash tests --- tests/eips/eip4844/test_blobhash_opcode_contexts.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/eips/eip4844/test_blobhash_opcode_contexts.py b/tests/eips/eip4844/test_blobhash_opcode_contexts.py index f89654f3cd..d20b772c61 100644 --- a/tests/eips/eip4844/test_blobhash_opcode_contexts.py +++ b/tests/eips/eip4844/test_blobhash_opcode_contexts.py @@ -16,7 +16,7 @@ to_hash_bytes, ) -from .utils import BlobhashContext, simple_blob_hashes +from .utils import BlobhashContext, MAX_BLOBS_PER_BLOCK, simple_blob_hashes pytestmark = pytest.mark.valid_from("Cancun") @@ -136,7 +136,7 @@ def opcode_context(yul: YulCompiler, request): ), }, tx_type_3.with_fields( - data=to_hash_bytes(0) + to_hash_bytes(3), + data=to_hash_bytes(0) + to_hash_bytes(MAX_BLOBS_PER_BLOCK - 1), to=BlobhashContext.address("delegatecall"), ), { @@ -158,7 +158,7 @@ def opcode_context(yul: YulCompiler, request): ), }, tx_type_3.with_fields( - data=to_hash_bytes(0) + to_hash_bytes(3), + data=to_hash_bytes(0) + to_hash_bytes(MAX_BLOBS_PER_BLOCK - 1), to=BlobhashContext.address("staticcall"), ), { @@ -180,7 +180,7 @@ def opcode_context(yul: YulCompiler, request): ), }, tx_type_3.with_fields( - data=to_hash_bytes(0) + to_hash_bytes(3), + data=to_hash_bytes(0) + to_hash_bytes(MAX_BLOBS_PER_BLOCK - 1), to=BlobhashContext.address("callcode"), ), { From c7277e487c732d5f3ba1925b92dae57c4937ce16 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 13 Jun 2023 18:08:25 +0000 Subject: [PATCH 14/21] forks: add dataGasUsed requirement check --- src/ethereum_test_forks/base_fork.py | 10 +++++++++- src/ethereum_test_forks/forks/forks.py | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/ethereum_test_forks/base_fork.py b/src/ethereum_test_forks/base_fork.py index 9bd870ac97..22225cb66a 100644 --- a/src/ethereum_test_forks/base_fork.py +++ b/src/ethereum_test_forks/base_fork.py @@ -14,7 +14,7 @@ def name(cls) -> str: """ To be implemented by the fork base class. """ - pass + return "" def __repr__(cls) -> str: """ @@ -70,6 +70,14 @@ def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> b """ pass + @classmethod + @abstractmethod + def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool: + """ + Returns true if the header must contain data gas used + """ + pass + @classmethod @abstractmethod def get_reward(cls, block_number: int, timestamp: int) -> int: diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index 09bc2b311c..0c48c3a7cd 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -45,6 +45,13 @@ def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> b """ return False + @classmethod + def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool: + """ + At genesis, header must not contain data gas used + """ + return False + @classmethod def get_reward(cls, block_number: int, timestamp: int) -> int: """ @@ -212,3 +219,10 @@ def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> b Excess data gas is required starting from Cancun. """ return True + + @classmethod + def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool: + """ + Data gas used is required starting from Cancun. + """ + return True From 13145e79f932e5185c89b6e94027911ea635c749 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 13 Jun 2023 18:08:54 +0000 Subject: [PATCH 15/21] tools/types: fix data fields requirements check --- src/ethereum_test_tools/common/types.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ethereum_test_tools/common/types.py b/src/ethereum_test_tools/common/types.py index 826b2c85ad..b7c9cf4224 100644 --- a/src/ethereum_test_tools/common/types.py +++ b/src/ethereum_test_tools/common/types.py @@ -642,6 +642,20 @@ def set_fork_requirements(self, fork: Fork) -> "Environment": if fork.header_zero_difficulty_required(self.number, self.timestamp): res.difficulty = 0 + if ( + fork.header_excess_data_gas_required(self.number, self.timestamp) + and res.excess_data_gas is None + and res.parent_excess_data_gas is None + ): + res.excess_data_gas = 0 + + if ( + fork.header_data_gas_used_required(self.number, self.timestamp) + and res.data_gas_used is None + and res.parent_data_gas_used is None + ): + res.data_gas_used = 0 + return res From 06fdbf0dd95d31d43c1310e60024275975523248 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 13 Jun 2023 18:09:35 +0000 Subject: [PATCH 16/21] tests/4844: fix blob tx genesis header --- tests/eips/eip4844/test_blob_txs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/eips/eip4844/test_blob_txs.py b/tests/eips/eip4844/test_blob_txs.py index f2dec9d339..69ca8e1d7e 100644 --- a/tests/eips/eip4844/test_blob_txs.py +++ b/tests/eips/eip4844/test_blob_txs.py @@ -889,7 +889,6 @@ def test_blob_tx_attribute_gasprice_opcode( def test_blob_type_tx_pre_fork( blockchain_test: BlockchainTestFiller, pre: Dict, - env: Environment, blocks: List[Block], ): """ @@ -899,5 +898,5 @@ def test_blob_type_tx_pre_fork( pre=pre, post={}, blocks=blocks, - genesis_environment=env, + genesis_environment=Environment(), # `env` fixture has blob fields ) From d50c692208de1541e11491043363c9a624df8718 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 13 Jun 2023 18:19:40 +0000 Subject: [PATCH 17/21] tests/4844: add missing expected exception --- tests/eips/eip4844/test_excess_data_gas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index 11d724b7d6..f47d8bdc04 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -485,6 +485,7 @@ def test_invalid_static_excess_data_gas( but the parent blobs included are not TARGET_BLOBS_PER_BLOCK. """ blocks[0].rlp_modifier = Header(excess_data_gas=parent_excess_data_gas) + blocks[0].exception = "invalid excessDataGas" blockchain_test( pre=pre, post={}, From 65bd00898ffa163937010275ae5e6461c64eb54f Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 13 Jun 2023 19:16:18 +0000 Subject: [PATCH 18/21] tests/4844: tox fix --- tests/eips/eip4844/test_blobhash_opcode_contexts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/eips/eip4844/test_blobhash_opcode_contexts.py b/tests/eips/eip4844/test_blobhash_opcode_contexts.py index d20b772c61..81e5d13c66 100644 --- a/tests/eips/eip4844/test_blobhash_opcode_contexts.py +++ b/tests/eips/eip4844/test_blobhash_opcode_contexts.py @@ -16,7 +16,7 @@ to_hash_bytes, ) -from .utils import BlobhashContext, MAX_BLOBS_PER_BLOCK, simple_blob_hashes +from .utils import MAX_BLOBS_PER_BLOCK, BlobhashContext, simple_blob_hashes pytestmark = pytest.mark.valid_from("Cancun") From 9b189a4c91b6e8b407a899cafd10a400beeeb69b Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Wed, 14 Jun 2023 16:30:59 +0000 Subject: [PATCH 19/21] tests/4844: fix account balances calculation --- tests/eips/eip4844/test_blob_txs.py | 13 +++++++------ tests/eips/eip4844/test_excess_data_gas.py | 15 +++++++++++---- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/eips/eip4844/test_blob_txs.py b/tests/eips/eip4844/test_blob_txs.py index 69ca8e1d7e..36ae0398b1 100644 --- a/tests/eips/eip4844/test_blob_txs.py +++ b/tests/eips/eip4844/test_blob_txs.py @@ -184,19 +184,16 @@ def total_account_minimum_balance( # noqa: D103 tx_calldata: bytes, tx_max_fee_per_gas: int, tx_max_priority_fee_per_gas: int, - data_gasprice: Optional[int], + tx_max_fee_per_data_gas: int, blob_hashes_per_tx: List[List[bytes]], ) -> int: """ Calculates the minimum balance required for the account to be able to send the transactions in the block of the test. """ - if data_gasprice is None: - # When fork transitioning, the default data gas price is 1. - data_gasprice = 1 total_cost = 0 for tx_blob_count in [len(x) for x in blob_hashes_per_tx]: - data_cost = data_gasprice * DATA_GAS_PER_BLOB * tx_blob_count + data_cost = tx_max_fee_per_data_gas * DATA_GAS_PER_BLOB * tx_blob_count total_cost += ( (tx_gas * (tx_max_fee_per_gas + tx_max_priority_fee_per_gas)) + tx_value @@ -223,7 +220,7 @@ def tx_max_fee_per_gas( @pytest.fixture def tx_max_fee_per_data_gas( # noqa: D103 - data_gasprice: int, + data_gasprice: Optional[int], ) -> int: """ Default max fee per data gas for transactions sent during test. @@ -233,6 +230,9 @@ def tx_max_fee_per_data_gas( # noqa: D103 Can be overloaded by a test case to test rejection of transactions where the max fee per data gas is insufficient. """ + if data_gasprice is None: + # When fork transitioning, the default data gas price is 1. + return 1 return data_gasprice @@ -516,6 +516,7 @@ def test_invalid_block_blob_count( [b"", b"\x00", b"\x01"], ids=["no_calldata", "single_zero_calldata", "single_one_calldata"], ) +@pytest.mark.parametrize("tx_max_fee_per_data_gas", [1, 100, 10000]) @pytest.mark.parametrize("account_balance_modifier", [-1], ids=["exact_balance_minus_1"]) @pytest.mark.parametrize("tx_error", ["insufficient_account_balance"], ids=[""]) @pytest.mark.valid_from("Cancun") diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index f47d8bdc04..7a45f259e6 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -147,11 +147,18 @@ def tx_max_fee( # noqa: D103 @pytest.fixture -def tx_data_cost( # noqa: D103 +def tx_max_fee_per_data( # noqa: D103 fee_per_data_gas: int, +) -> int: + return fee_per_data_gas + + +@pytest.fixture +def tx_data_cost( # noqa: D103 + tx_max_fee_per_data: int, new_blobs: int, ) -> int: - return fee_per_data_gas * DATA_GAS_PER_BLOB * new_blobs + return tx_max_fee_per_data * DATA_GAS_PER_BLOB * new_blobs @pytest.fixture @@ -188,7 +195,7 @@ def post(destination_account: str, tx_value: int) -> Mapping[str, Account]: # n def tx( # noqa: D103 new_blobs: int, tx_max_fee: int, - tx_data_cost: int, + tx_max_fee_per_data: int, destination_account: str, ): if new_blobs == 0: @@ -212,7 +219,7 @@ def tx( # noqa: D103 gas_limit=21000, max_fee_per_gas=tx_max_fee, max_priority_fee_per_gas=0, - max_fee_per_data_gas=tx_data_cost, + max_fee_per_data_gas=tx_max_fee_per_data, access_list=[], blob_versioned_hashes=add_kzg_version( [to_hash_bytes(x) for x in range(new_blobs)], From 12f9b97c429673ce1cffe55329ff04a9bf9d12ef Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Wed, 14 Jun 2023 22:15:29 +0000 Subject: [PATCH 20/21] tests/4844: utils tox fix --- tests/eips/eip4844/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/eips/eip4844/utils.py b/tests/eips/eip4844/utils.py index 5ea03ff48c..05f75f9827 100644 --- a/tests/eips/eip4844/utils.py +++ b/tests/eips/eip4844/utils.py @@ -10,8 +10,8 @@ from ethereum_test_tools import ( Auto, TestAddress, - YulCompiler, Transaction, + YulCompiler, add_kzg_version, compute_create2_address, compute_create_address, From 18b555a27a880c30b112db46b3f1a3c7e0bc493c Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Wed, 14 Jun 2023 23:18:16 +0000 Subject: [PATCH 21/21] tests/4844: excess data gas fixture naming fixes --- tests/eips/eip4844/test_excess_data_gas.py | 35 +++++++++------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/tests/eips/eip4844/test_excess_data_gas.py b/tests/eips/eip4844/test_excess_data_gas.py index 7a45f259e6..9d0bdc81d8 100644 --- a/tests/eips/eip4844/test_excess_data_gas.py +++ b/tests/eips/eip4844/test_excess_data_gas.py @@ -108,19 +108,12 @@ def header_excess_data_gas( # noqa: D103 @pytest.fixture -def fee_per_data_gas( # noqa: D103 +def block_fee_per_data_gas( # noqa: D103 correct_excess_data_gas: int, ) -> int: return get_data_gasprice(excess_data_gas=correct_excess_data_gas) -@pytest.fixture -def tx_max_fee_per_data_gas( # noqa: D103 - fee_per_data_gas: int, -) -> int: - return fee_per_data_gas - - @pytest.fixture def block_base_fee() -> int: # noqa: D103 return 7 @@ -140,25 +133,25 @@ def env( # noqa: D103 @pytest.fixture -def tx_max_fee( # noqa: D103 +def tx_max_fee_per_gas( # noqa: D103 block_base_fee: int, ) -> int: return block_base_fee @pytest.fixture -def tx_max_fee_per_data( # noqa: D103 - fee_per_data_gas: int, +def tx_max_fee_per_data_gas( # noqa: D103 + block_fee_per_data_gas: int, ) -> int: - return fee_per_data_gas + return block_fee_per_data_gas @pytest.fixture def tx_data_cost( # noqa: D103 - tx_max_fee_per_data: int, + tx_max_fee_per_data_gas: int, new_blobs: int, ) -> int: - return tx_max_fee_per_data * DATA_GAS_PER_BLOB * new_blobs + return tx_max_fee_per_data_gas * DATA_GAS_PER_BLOB * new_blobs @pytest.fixture @@ -167,9 +160,9 @@ def tx_value() -> int: # noqa: D103 @pytest.fixture -def tx_exact_cost(tx_value: int, tx_max_fee: int, tx_data_cost: int) -> int: # noqa: D103 +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) + tx_value + tx_data_cost + return (tx_gas * tx_max_fee_per_gas) + tx_value + tx_data_cost @pytest.fixture @@ -194,8 +187,8 @@ def post(destination_account: str, tx_value: int) -> Mapping[str, Account]: # n @pytest.fixture def tx( # noqa: D103 new_blobs: int, - tx_max_fee: int, - tx_max_fee_per_data: int, + tx_max_fee_per_gas: int, + tx_max_fee_per_data_gas: int, destination_account: str, ): if new_blobs == 0: @@ -206,7 +199,7 @@ def tx( # noqa: D103 to=destination_account, value=1, gas_limit=21000, - max_fee_per_gas=tx_max_fee, + max_fee_per_gas=tx_max_fee_per_gas, max_priority_fee_per_gas=0, access_list=[], ) @@ -217,9 +210,9 @@ def tx( # noqa: D103 to=destination_account, value=1, gas_limit=21000, - max_fee_per_gas=tx_max_fee, + max_fee_per_gas=tx_max_fee_per_gas, max_priority_fee_per_gas=0, - max_fee_per_data_gas=tx_max_fee_per_data, + max_fee_per_data_gas=tx_max_fee_per_data_gas, access_list=[], blob_versioned_hashes=add_kzg_version( [to_hash_bytes(x) for x in range(new_blobs)],