diff --git a/fillers/eips/eip4844/datahash_opcode.py b/fillers/eips/eip4844/datahash_opcode.py index a0f2d5faa13..6969c48e8c8 100644 --- a/fillers/eips/eip4844/datahash_opcode.py +++ b/fillers/eips/eip4844/datahash_opcode.py @@ -17,6 +17,7 @@ TestAddress, Transaction, Yul, + add_kzg_version, compute_create2_address, compute_create_address, test_from, @@ -28,6 +29,7 @@ REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4844.md" REFERENCE_SPEC_VERSION = "ac003985b9be74ff48bd897770e6d5f2e4318715" +BLOB_COMMITMENT_VERSION_KZG = 1 DATAHASH_GAS_COST = 3 MAX_BLOB_PER_BLOCK = 4 BLOB_HASHES = [ @@ -199,9 +201,10 @@ def test_datahash_opcode_contexts(_: Fork): initcode_datahash_sstore_bytecode.assemble(), ) - b_hashes: Sequence[bytes] = [ - to_hash_bytes(1 << x) for x in range(MAX_BLOB_PER_BLOCK) - ] + b_hashes: Sequence[bytes] = add_kzg_version( + [(1 << x) for x in range(MAX_BLOB_PER_BLOCK)], + BLOB_COMMITMENT_VERSION_KZG, + ) tags = [ "at_top_level_call_stack", @@ -485,7 +488,7 @@ def test_datahash_gas_cost(_: Fork): to=address, nonce=i, max_priority_fee_per_gas=10, - blob_versioned_hashes=[BLOB_HASHES[i % MAX_BLOB_PER_BLOCK]], + access_list=[], ) ) txs_type_3.append( @@ -494,7 +497,10 @@ def test_datahash_gas_cost(_: Fork): to=address, nonce=i, max_priority_fee_per_gas=10, - blob_versioned_hashes=[BLOB_HASHES[i % MAX_BLOB_PER_BLOCK]], + blob_versioned_hashes=add_kzg_version( + [BLOB_HASHES[i % MAX_BLOB_PER_BLOCK]], + BLOB_COMMITMENT_VERSION_KZG, + ), ) ) post[address] = Account(storage={0: DATAHASH_GAS_COST}) @@ -537,11 +543,14 @@ def test_datahash_blob_versioned_hash(_: Fork): # Create an arbitrary repeated list of blob hashes # with length MAX_BLOB_PER_BLOCK * TOTAL_BLOCKS - b_hashes = list( - itertools.islice( - itertools.cycle(BLOB_HASHES), - MAX_BLOB_PER_BLOCK * TOTAL_BLOCKS, - ) + b_hashes = add_kzg_version( + list( + itertools.islice( + itertools.cycle(BLOB_HASHES), + MAX_BLOB_PER_BLOCK * TOTAL_BLOCKS, + ) + ), + BLOB_COMMITMENT_VERSION_KZG, ) # `DATAHASH` sstore template helper @@ -678,7 +687,10 @@ def test_datahash_invalid_blob_index(_: Fork): address = to_address(0x100 + i * 0x100) pre[address] = Account(code=datahash_invalid_calls) blob_per_block = (i % MAX_BLOB_PER_BLOCK) + 1 - blob_hashes = [BLOB_HASHES[blob] for blob in range(blob_per_block)] + blob_hashes = add_kzg_version( + [BLOB_HASHES[blob] for blob in range(blob_per_block)], + BLOB_COMMITMENT_VERSION_KZG, + ) blocks.append( Block( txs=[ @@ -735,6 +747,10 @@ def test_datahash_multiple_txs_in_block(_: Fork): } pre[TestAddress] = Account(balance=10000000000000000000000) + b_hashes = add_kzg_version( + BLOB_HASHES[0:MAX_BLOB_PER_BLOCK], BLOB_COMMITMENT_VERSION_KZG + ) + tx = Transaction( data=to_hash_bytes(0), gas_limit=3000000, @@ -742,7 +758,7 @@ def test_datahash_multiple_txs_in_block(_: Fork): max_priority_fee_per_gas=10, max_fee_per_data_gas=10, access_list=[], - blob_versioned_hashes=BLOB_HASHES[0:MAX_BLOB_PER_BLOCK], + blob_versioned_hashes=b_hashes, ) blocks = [ @@ -768,7 +784,7 @@ def test_datahash_multiple_txs_in_block(_: Fork): post = { to_address(address): Account( - storage={i: BLOB_HASHES[i] for i in range(MAX_BLOB_PER_BLOCK)} + storage={i: b_hashes[i] for i in range(MAX_BLOB_PER_BLOCK)} ) if address in (0x200, 0x400) else Account(storage={i: 0 for i in range(MAX_BLOB_PER_BLOCK)}) diff --git a/fillers/eips/eip4844/excess_data_gas.py b/fillers/eips/eip4844/excess_data_gas.py index c7e2138ce1d..a7bb450021c 100644 --- a/fillers/eips/eip4844/excess_data_gas.py +++ b/fillers/eips/eip4844/excess_data_gas.py @@ -20,6 +20,7 @@ Header, TestAddress, Transaction, + add_kzg_version, test_from, test_only, to_address, @@ -29,6 +30,7 @@ REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4844.md" REFERENCE_SPEC_VERSION = "ac003985b9be74ff48bd897770e6d5f2e4318715" +BLOB_COMMITMENT_VERSION_KZG = 1 DATAHASH_GAS_COST = 3 MIN_DATA_GASPRICE = 1 DATA_GAS_PER_BLOB = 2**17 @@ -155,9 +157,10 @@ def generate(self) -> BlockchainTest: max_priority_fee_per_gas=0, max_fee_per_data_gas=data_gasprice, access_list=[], - blob_versioned_hashes=[ - to_hash_bytes(x) for x in range(self.blobs) - ], + blob_versioned_hashes=add_kzg_version( + [to_hash_bytes(x) for x in range(self.blobs)], + BLOB_COMMITMENT_VERSION_KZG, + ), ) else: tx = Transaction( @@ -374,9 +377,10 @@ def generate(self) -> BlockchainTest: excess_data_gas=parent_excess_data_gas ), access_list=[], - blob_versioned_hashes=[ - to_hash_bytes(x) for x in range(self.new_blobs) - ], + blob_versioned_hashes=add_kzg_version( + [to_hash_bytes(x) for x in range(self.new_blobs)], + BLOB_COMMITMENT_VERSION_KZG, + ), ) return BlockchainTest( @@ -603,10 +607,13 @@ def test_fork_transition_excess_data_gas_in_header(_: Fork): excess_data_gas=parent_excess_data_gas ), access_list=[], - blob_versioned_hashes=[ - to_hash_bytes(x) - for x in range(MAX_BLOBS_PER_BLOCK) - ], + blob_versioned_hashes=add_kzg_version( + [ + to_hash_bytes(x) + for x in range(MAX_BLOBS_PER_BLOCK) + ], + BLOB_COMMITMENT_VERSION_KZG, + ), ) ], ) @@ -647,6 +654,7 @@ class InvalidBlobTransactionTestCase: tx_count: int = 1 parent_excess_blobs: Optional[int] = None tx_max_data_gas_cost: Optional[int] = None + total_kzg_versioning: int = MAX_BLOBS_PER_BLOCK account_balance_modifier: int = 0 block_base_fee: int = 7 @@ -681,6 +689,13 @@ def generate(self) -> BlockchainTest: else data_gasprice ) + b_hashes = [to_hash_bytes(x) for x in range(self.blobs_per_tx)] + if self.total_kzg_versioning > 0: + b_hashes[0 : self.total_kzg_versioning] = add_kzg_version( + b_hashes[0 : self.total_kzg_versioning], + BLOB_COMMITMENT_VERSION_KZG, + ) + txs: List[Transaction] = [] for tx_i in range(self.tx_count): tx = Transaction( @@ -693,9 +708,7 @@ def generate(self) -> BlockchainTest: max_priority_fee_per_gas=0, max_fee_per_data_gas=max_fee_per_data_gas, access_list=[], - blob_versioned_hashes=[ - to_hash_bytes(x) for x in range(self.blobs_per_tx) - ], + blob_versioned_hashes=b_hashes, error=self.tx_error if tx_i == (self.tx_count - 1) else None, ) txs.append(tx) @@ -778,6 +791,18 @@ def test_invalid_blob_txs(fork: Fork): tx_error="too_few_blobs", blobs_per_tx=0, ), + InvalidBlobTransactionTestCase( + tag="no_kzg_versioning", + tx_error="all_blob_hashes_unversioned", + blobs_per_tx=MAX_BLOBS_PER_BLOCK, + total_kzg_versioning=0, + ), + InvalidBlobTransactionTestCase( + tag="partial_kzg_versioning", + tx_error="some_blob_hashes_unversioned", + blobs_per_tx=MAX_BLOBS_PER_BLOCK, + total_kzg_versioning=2, + ), ] else: # Pre-Cancun, blocks with type 3 txs must be rejected diff --git a/src/ethereum_test_tools/__init__.py b/src/ethereum_test_tools/__init__.py index 4975a9b1d00..2fea9132faf 100644 --- a/src/ethereum_test_tools/__init__.py +++ b/src/ethereum_test_tools/__init__.py @@ -15,6 +15,7 @@ TestAddress, Transaction, Withdrawal, + add_kzg_version, ceiling_division, compute_create2_address, compute_create_address, @@ -50,6 +51,7 @@ "Transaction", "Withdrawal", "Yul", + "add_kzg_version", "ceiling_division", "compute_create_address", "compute_create2_address", diff --git a/src/ethereum_test_tools/common/__init__.py b/src/ethereum_test_tools/common/__init__.py index 74d952de3e9..bf9f86765de 100644 --- a/src/ethereum_test_tools/common/__init__.py +++ b/src/ethereum_test_tools/common/__init__.py @@ -9,6 +9,7 @@ TestPrivateKey, ) from .helpers import ( + add_kzg_version, ceiling_division, compute_create2_address, compute_create_address, @@ -57,6 +58,7 @@ "TestPrivateKey", "Transaction", "Withdrawal", + "add_kzg_version", "alloc_to_accounts", "even_padding", "ceiling_division", diff --git a/src/ethereum_test_tools/common/helpers.py b/src/ethereum_test_tools/common/helpers.py index 1a639e6679e..ff9e96313c4 100644 --- a/src/ethereum_test_tools/common/helpers.py +++ b/src/ethereum_test_tools/common/helpers.py @@ -104,3 +104,24 @@ def to_hash(input: int | str) -> str: Converts an int or str into proper 32-byte hash hex string. """ return "0x" + to_hash_bytes(input).hex() + + +def add_kzg_version(b_hashes, kzg_version): + """ + Adds the Kzg Version to each blob hash. + """ + kzg_version_hex = bytes([kzg_version]) + kzg_versioned_hashes = [] + + for hash in b_hashes: + if isinstance(hash, int) or isinstance(hash, str): + kzg_versioned_hashes.append( + kzg_version_hex + to_hash_bytes(hash)[1:] + ) + elif isinstance(hash, bytes): + kzg_versioned_hashes.append(kzg_version_hex + hash[1:]) + else: + raise TypeError( + "Blob hash must be either an integer, string or bytes" + ) + return kzg_versioned_hashes