Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
Address,
Bytes,
CamelModel,
HexNumber,
RLPSerializable,
ZeroPaddedHexNumber,
)


Expand All @@ -23,11 +23,11 @@ class BalNonceChange(CamelModel, RLPSerializable):

model_config = CamelModel.model_config | {"extra": "forbid"}

block_access_index: HexNumber = Field(
HexNumber(1),
block_access_index: ZeroPaddedHexNumber = Field(
ZeroPaddedHexNumber(1),
description="Transaction index where the change occurred",
)
post_nonce: HexNumber = Field(
post_nonce: ZeroPaddedHexNumber = Field(
..., description="Nonce value after the transaction"
)

Expand All @@ -39,11 +39,11 @@ class BalBalanceChange(CamelModel, RLPSerializable):

model_config = CamelModel.model_config | {"extra": "forbid"}

block_access_index: HexNumber = Field(
HexNumber(1),
block_access_index: ZeroPaddedHexNumber = Field(
ZeroPaddedHexNumber(1),
description="Transaction index where the change occurred",
)
post_balance: HexNumber = Field(
post_balance: ZeroPaddedHexNumber = Field(
..., description="Balance after the transaction"
)

Expand All @@ -55,8 +55,8 @@ class BalCodeChange(CamelModel, RLPSerializable):

model_config = CamelModel.model_config | {"extra": "forbid"}

block_access_index: HexNumber = Field(
HexNumber(1),
block_access_index: ZeroPaddedHexNumber = Field(
ZeroPaddedHexNumber(1),
description="Transaction index where the change occurred",
)
new_code: Bytes = Field(..., description="New code bytes")
Expand All @@ -69,11 +69,11 @@ class BalStorageChange(CamelModel, RLPSerializable):

model_config = CamelModel.model_config | {"extra": "forbid"}

block_access_index: HexNumber = Field(
HexNumber(1),
block_access_index: ZeroPaddedHexNumber = Field(
ZeroPaddedHexNumber(1),
description="Transaction index where the change occurred",
)
post_value: HexNumber = Field(
post_value: ZeroPaddedHexNumber = Field(
..., description="Value after the transaction"
)

Expand All @@ -85,7 +85,7 @@ class BalStorageSlot(CamelModel, RLPSerializable):

model_config = CamelModel.model_config | {"extra": "forbid"}

slot: HexNumber = Field(..., description="Storage slot key")
slot: ZeroPaddedHexNumber = Field(..., description="Storage slot key")
slot_changes: List[BalStorageChange] = Field(
default_factory=list, description="List of changes to this slot"
)
Expand All @@ -111,7 +111,7 @@ class BalAccountChange(CamelModel, RLPSerializable):
storage_changes: List[BalStorageSlot] = Field(
default_factory=list, description="List of storage changes"
)
storage_reads: List[HexNumber] = Field(
storage_reads: List[ZeroPaddedHexNumber] = Field(
default_factory=list,
description="List of storage slots that were read",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

from typing import Any, Callable, List, Optional

from execution_testing.base_types import Address, HexNumber
from execution_testing.base_types import (
Address,
ZeroPaddedHexNumber,
)

from .. import BalCodeChange
from . import (
Expand Down Expand Up @@ -257,31 +260,43 @@ def transform(bal: BlockAccessList) -> BlockAccessList:
for nonce_change in new_account.nonce_changes:
if nonce_change.block_access_index == tx1:
nonce_indices[tx1] = True
nonce_change.block_access_index = HexNumber(tx2)
nonce_change.block_access_index = ZeroPaddedHexNumber(
tx2
)
elif nonce_change.block_access_index == tx2:
nonce_indices[tx2] = True
nonce_change.block_access_index = HexNumber(tx1)
nonce_change.block_access_index = ZeroPaddedHexNumber(
tx1
)

# Swap in balance changes
if new_account.balance_changes:
for balance_change in new_account.balance_changes:
if balance_change.block_access_index == tx1:
balance_indices[tx1] = True
balance_change.block_access_index = HexNumber(tx2)
balance_change.block_access_index = (
ZeroPaddedHexNumber(tx2)
)
elif balance_change.block_access_index == tx2:
balance_indices[tx2] = True
balance_change.block_access_index = HexNumber(tx1)
balance_change.block_access_index = (
ZeroPaddedHexNumber(tx1)
)

# Swap in storage changes (nested structure)
if new_account.storage_changes:
for storage_slot in new_account.storage_changes:
for storage_change in storage_slot.slot_changes:
if storage_change.block_access_index == tx1:
balance_indices[tx1] = True
storage_change.block_access_index = HexNumber(tx2)
storage_change.block_access_index = (
ZeroPaddedHexNumber(tx2)
)
elif storage_change.block_access_index == tx2:
balance_indices[tx2] = True
storage_change.block_access_index = HexNumber(tx1)
storage_change.block_access_index = (
ZeroPaddedHexNumber(tx1)
)

# Note: storage_reads is just a list of StorageKey, no block_access_index to
# swap
Expand All @@ -291,10 +306,14 @@ def transform(bal: BlockAccessList) -> BlockAccessList:
for code_change in new_account.code_changes:
if code_change.block_access_index == tx1:
code_indices[tx1] = True
code_change.block_access_index = HexNumber(tx2)
code_change.block_access_index = ZeroPaddedHexNumber(
tx2
)
elif code_change.block_access_index == tx2:
code_indices[tx2] = True
code_change.block_access_index = HexNumber(tx1)
code_change.block_access_index = ZeroPaddedHexNumber(
tx1
)

new_root.append(new_account)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ def test_absent_values_nonce_changes(has_change_should_raise: bool) -> None:

if has_change_should_raise:
with pytest.raises(
Exception, match="Unexpected nonce change found at tx 0x2"
Exception, match="Unexpected nonce change found at tx 0x02"
):
expectation.verify_against(actual_bal)
else:
Expand Down Expand Up @@ -614,7 +614,7 @@ def test_absent_values_balance_changes(has_change_should_raise: bool) -> None:
if has_change_should_raise:
with pytest.raises(
Exception,
match="Unexpected balance change found at tx 0x2",
match="Unexpected balance change found at tx 0x02",
):
expectation.verify_against(actual_bal)
else:
Expand Down Expand Up @@ -759,7 +759,7 @@ def test_absent_values_code_changes(has_change_should_raise: bool) -> None:

if has_change_should_raise:
with pytest.raises(
Exception, match="Unexpected code change found at tx 0x2"
Exception, match="Unexpected code change found at tx 0x02"
):
expectation.verify_against(actual_bal)
else:
Expand Down Expand Up @@ -898,7 +898,7 @@ def test_absent_values_with_multiple_tx_indices() -> None:
)

with pytest.raises(
Exception, match="Unexpected nonce change found at tx 0x1"
Exception, match="Unexpected nonce change found at tx 0x01"
):
expectation_fail.verify_against(actual_bal)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
Tests for BlockAccessList serialization format.

These tests verify that BAL models serialize to JSON with the correct
format, particularly zero-padded hex strings.
"""

from execution_testing.base_types import Address, Bytes
from execution_testing.test_types.block_access_list import (
BalAccountChange,
BalBalanceChange,
BalCodeChange,
BalNonceChange,
BalStorageChange,
BalStorageSlot,
BlockAccessList,
)


def test_bal_serialization_roundtrip_zero_padded_hex() -> None:
"""
Test that BAL serializes with zero-padded hex format and round-trips correctly.

This verifies that values like 12 serialize as "0x0c" (not "0xc"), which is
required for consistency with other test vector fields.
"""
addr = Address(0xA)

original = BlockAccessList(
[
BalAccountChange(
address=addr,
nonce_changes=[
BalNonceChange(block_access_index=1, post_nonce=12),
BalNonceChange(block_access_index=2, post_nonce=255),
],
balance_changes=[
BalBalanceChange(block_access_index=1, post_balance=15),
],
code_changes=[
BalCodeChange(
block_access_index=3, new_code=Bytes(b"\xde\xad")
),
],
storage_changes=[
BalStorageSlot(
slot=12,
slot_changes=[
BalStorageChange(
block_access_index=1, post_value=255
),
BalStorageChange(
block_access_index=2, post_value=4096
),
],
),
],
storage_reads=[1, 15, 256],
)
]
)

# Serialize to JSON
json_data = original.model_dump(mode="json")
account_data = json_data[0]

# Verify zero-padded hex format (0x0c not 0xc, 0x01 not 0x1)
assert account_data["nonce_changes"][0]["block_access_index"] == "0x01"
assert account_data["nonce_changes"][0]["post_nonce"] == "0x0c"
assert account_data["nonce_changes"][1]["post_nonce"] == "0xff"
assert account_data["balance_changes"][0]["post_balance"] == "0x0f"
assert account_data["code_changes"][0]["block_access_index"] == "0x03"
assert account_data["storage_changes"][0]["slot"] == "0x0c"
assert (
account_data["storage_changes"][0]["slot_changes"][0]["post_value"]
== "0xff"
)
assert (
account_data["storage_changes"][0]["slot_changes"][1]["post_value"]
== "0x1000"
)
assert account_data["storage_reads"] == ["0x01", "0x0f", "0x0100"]

# Round-trip: deserialize and verify equality
restored = BlockAccessList.model_validate(json_data)
assert restored == original
Loading
Loading