Skip to content

Commit

Permalink
fix: always serialize block size to int (#2324)
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Oct 17, 2024
1 parent 742ed66 commit 3f2f301
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 12 deletions.
19 changes: 11 additions & 8 deletions src/ape/api/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from eth_pydantic_types import HexBytes
from ethpm_types.abi import EventABI
from pydantic import Field, computed_field, model_validator
from pydantic import Field, computed_field, field_serializer, model_validator

from ape.api.config import PluginConfig
from ape.api.networks import NetworkAPI
Expand All @@ -40,6 +40,7 @@
_create_raises_not_implemented_error,
log_instead_of_fail,
raises_not_implemented,
to_int,
)
from ape.utils.rpc import RPCHeaders

Expand Down Expand Up @@ -74,7 +75,7 @@ class BlockAPI(BaseInterfaceModel):
default=EMPTY_BYTES32, alias="parentHash"
) # NOTE: genesis block has no parent hash
"""
The preceeding block's hash.
The preceding block's hash.
"""

timestamp: HexInt
Expand All @@ -83,7 +84,7 @@ class BlockAPI(BaseInterfaceModel):
NOTE: The pending block uses the current timestamp.
"""

_size: Optional[int] = None
_size: Optional[HexInt] = None

@log_instead_of_fail(default="<BlockAPI>")
def __repr__(self) -> str:
Expand Down Expand Up @@ -111,7 +112,6 @@ def validate_size(cls, values, handler):
Saves it to a private member on this class and
gets returned in computed field "size".
"""

if isinstance(values, BlockAPI):
size = values.size

Expand All @@ -125,10 +125,14 @@ def validate_size(cls, values, handler):

model = handler(values)
if size is not None:
model._size = size
model._size = to_int(size)

return model

@field_serializer("size")
def serialize_size(self, value):
return to_int(value)

@computed_field() # type: ignore[misc]
@cached_property
def transactions(self) -> list[TransactionAPI]:
Expand All @@ -145,15 +149,14 @@ def transactions(self) -> list[TransactionAPI]:

@computed_field() # type: ignore[misc]
@cached_property
def size(self) -> int:
def size(self) -> HexInt:
"""
The size of the block in gas. Most of the time,
this field is passed to the model at validation time,
but occassionally it is missing (like in `eth_subscribe:newHeads`),
but occasionally it is missing (like in `eth_subscribe:newHeads`),
in which case it gets calculated if and only if the user
requests it (or during serialization of this model to disk).
"""

if self._size is not None:
# The size was provided with the rest of the model
# (normal).
Expand Down
31 changes: 27 additions & 4 deletions tests/functional/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ def test_block(eth_tester_provider, vyper_contract_instance):
assert actual.number == data["number"]


def test_block_dict(block):
actual = block.model_dump()
@pytest.mark.parametrize("mode", ("json", "python"))
def test_model_dump(block, mode):
actual = block.model_dump(mode=mode)
expected = {
"baseFeePerGas": 1000000000,
"difficulty": 0,
Expand All @@ -38,19 +39,41 @@ def test_block_dict(block):
assert actual == expected


def test_block_json(block):
def test_model_dump_json(block):
actual = block.model_dump_json()
expected = (
'{"baseFeePerGas":1000000000,"difficulty":0,"gasLimit":30029122,"gasUsed":0,'
f'"hash":"{to_hex(block.hash)}",'
'"num_transactions":0,"number":0,'
f'"parentHash":"{to_hex(block.parent_hash)}",'
f'"size":{block.size},"timestamp":{block.timestamp},'
f'"totalDifficulty":0,"transactions":[],"uncles":[]}}'
'"totalDifficulty":0,"transactions":[],"uncles":[]}'
)
assert actual == expected


@pytest.mark.parametrize("size", (123, HexBytes(123), to_hex(123)))
def test_size(block, size):
block._size = size
dictionary_python = block.model_dump(mode="python")
dictionary_json = block.model_dump(mode="json")
jons_str = block.model_dump_json()
assert dictionary_python["size"] == 123
assert dictionary_json["size"] == 123
assert '"size":123' in jons_str

# Show the same when validated with size in the model.
data = block.model_dump()
data["size"] = size
new_block = Block.model_validate(data)
dictionary_python = new_block.model_dump(mode="python")
dictionary_json = new_block.model_dump(mode="json")
jons_str = new_block.model_dump_json()
assert dictionary_python["size"] == 123
assert dictionary_json["size"] == 123
assert '"size":123' in jons_str


def test_block_calculate_size(block):
original = block.model_dump(by_alias=True)
size = original.pop("size")
Expand Down

0 comments on commit 3f2f301

Please sign in to comment.