Skip to content

Commit

Permalink
PR Feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
pipermerriam committed Apr 24, 2019
1 parent 3a871a4 commit 9cafc75
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 29 deletions.
3 changes: 0 additions & 3 deletions ssz/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
CHUNK_SIZE = 32 # named BYTES_PER_CHUNK in the spec
EMPTY_CHUNK = Hash32(b"\x00" * CHUNK_SIZE)

SIZE_PREFIX_SIZE = 4 # named BYTES_PER_LENGTH_PREFIX in the spec
MAX_CONTENT_SIZE = 2 ** (SIZE_PREFIX_SIZE * 8) - 1

SIGNATURE_FIELD_NAME = "signature"

# number of bytes for a serialized offset
Expand Down
15 changes: 0 additions & 15 deletions ssz/sedes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
abstractmethod,
)
import io
import itertools
import operator
from typing import (
IO,
Expand Down Expand Up @@ -176,17 +175,3 @@ def deserialize(self, data: bytes) -> TDeserialized:
@abstractmethod
def _deserialize_stream(self, stream: IO[bytes]) -> TDeserialized:
pass


TSerializableElement = TypeVar("TSerializableElement")
TDeserializedElement = TypeVar("TDeserializedElement")


class HomogenousSequence(CompositeSedes[Sequence[Any], Tuple[Any]]):
element_sedes: TSedes

#
# Serialization
#
def _get_item_sedes_pairs(self, value: Sequence[Any]) -> Tuple[Tuple[Any, TSedes], ...]:
return tuple(zip(value, itertools.repeat(self.element_sedes)))
2 changes: 0 additions & 2 deletions ssz/sedes/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ class Container(CompositeSedes[Sequence[Any], Tuple[Any, ...]]):
def __init__(self, field_sedes: Sequence[TSedes]) -> None:
if len(field_sedes) == 0:
raise ValidationError("Cannot define container without any fields")
from ssz.sedes.base import BaseSedes
assert all(isinstance(sedes, BaseSedes) for sedes in field_sedes)
self.field_sedes = tuple(field_sedes)

#
Expand Down
23 changes: 16 additions & 7 deletions ssz/sedes/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
TSerializable = TypeVar("TSerializable")
TDeserialized = TypeVar("TDeserialized")

EMPTY_LIST_HASH_TRIES_ROOT = mix_in_length(merkleize(pack([])), 0)
EMPTY_LIST_HASH_TREE_ROOT = mix_in_length(merkleize(pack([])), 0)


class EmptyList(BaseCompositeSedes[Sequence[TSerializable], Tuple[TSerializable, ...]]):
Expand All @@ -61,8 +61,8 @@ def deserialize(self, data: bytes) -> Tuple[TDeserialized, ...]:

def hash_tree_root(self, value: Sequence[TSerializable]) -> bytes:
if len(value):
raise ValueError("Cannot compute trie hash for non-empty value using `EmptyList` sedes")
return EMPTY_LIST_HASH_TRIES_ROOT
raise ValueError("Cannot compute tree hash for non-empty value using `EmptyList` sedes")
return EMPTY_LIST_HASH_TREE_ROOT


empty_list = EmptyList()
Expand Down Expand Up @@ -98,15 +98,24 @@ def _deserialize_stream(self, stream: IO[bytes]) -> Iterable[TDeserialized]:
element_size = self.element_sedes.get_fixed_size()
data = stream.read()
if len(data) % element_size != 0:
raise DeserializationError("TODO: INVALID LENGTH")
raise DeserializationError(
f"Invalid length. List is comprised of a fixed size sedes "
f"but total serialized data is not an even multiple of the "
f"element size. data length: {len(data)} element size: "
f"{element_size}"
)
for segment in partition(element_size, data):
yield self.element_sedes.deserialize(segment)
else:
stream_zero_loc = stream.tell()
try:
first_offset = s_decode_offset(stream)
except DeserializationError:
# Empty list
return
if stream.tell() == stream_zero_loc:
# Empty list
return
else:
raise

num_remaining_offset_bytes = first_offset - stream.tell()
if num_remaining_offset_bytes % OFFSET_SIZE != 0:
Expand Down Expand Up @@ -134,7 +143,7 @@ def _deserialize_stream(self, stream: IO[bytes]) -> Iterable[TDeserialized]:
#
def hash_tree_root(self, value: Iterable[TSerializable]) -> bytes:
if len(value) == 0:
return EMPTY_LIST_HASH_TRIES_ROOT
return EMPTY_LIST_HASH_TREE_ROOT
elif isinstance(self.element_sedes, BasicSedes):
serialized_items = tuple(
self.element_sedes.serialize(element)
Expand Down
2 changes: 1 addition & 1 deletion ssz/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def decode_offset(data: bytes) -> int:


def s_decode_offset(stream: IO[bytes]) -> int:
data = read_exact(4, stream)
data = read_exact(OFFSET_SIZE, stream)
return decode_offset(data)


Expand Down
15 changes: 14 additions & 1 deletion tests/sedes/test_composite_sedes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import pytest

import ssz
from ssz.exceptions import (
DeserializationError,
)
from ssz.sedes import (
Container,
List,
Expand All @@ -31,6 +34,16 @@ def test_list(value, serialized):
assert ssz.decode(decode_hex(serialized), sedes) == value


def test_invalid_serialized_list():
# ensure that an improperly read offset (not enough bytes) does not
# incorrectly register as an empty list due to mis-interpreting the failed
# stream read as the stream having been empty.
data = decode_hex("0x0001")
sedes = List(List(uint8))
with pytest.raises(DeserializationError):
ssz.decode(data, sedes=sedes)


@pytest.mark.parametrize(
("value", "serialized"),
(
Expand Down Expand Up @@ -58,7 +71,7 @@ def test_tuple_of_static_sized_entries(value, serialized):
),
)
)
def test_tuple_of_dynamic_sized_entries(value, serialized):
def test_list_of_dynamic_sized_entries(value, serialized):
sedes = Vector(List(uint8), len(value))
assert encode_hex(ssz.encode(value, sedes)) == serialized
assert ssz.decode(decode_hex(serialized), sedes) == value
Expand Down

0 comments on commit 9cafc75

Please sign in to comment.