Skip to content

Commit

Permalink
Add checks when coercing between containers that have different profiles
Browse files Browse the repository at this point in the history
  • Loading branch information
etan-status committed Oct 1, 2024
1 parent 65fb72f commit 74fadc0
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 6 deletions.
15 changes: 11 additions & 4 deletions remerkleable/complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from collections.abc import Sequence as ColSequence
from itertools import chain
import io
from remerkleable.core import View, BasicView, OFFSET_BYTE_LENGTH, ViewHook, ObjType, ObjParseException
from remerkleable.core import View, BackedView, BasicView, OFFSET_BYTE_LENGTH,\
ViewHook, ObjType, ObjParseException
from remerkleable.basic import uint256, uint8, uint32
from remerkleable.tree import Node, subtree_fill_to_length, subtree_fill_to_contents,\
zero_node, Gindex, PairNode, to_gindex, NavigationError, get_depth, RIGHT_GINDEX
Expand Down Expand Up @@ -283,7 +284,9 @@ def __new__(cls, *args, backing: Optional[Node] = None, hook: Optional[ViewHook]
raise Exception(f"too many list inputs: {len(vals)}, limit is: {limit}")
input_views = []
for el in vals:
if isinstance(el, View):
if isinstance(el, BackedView):
input_views.append(elem_cls(backing=el.get_backing()))
elif isinstance(el, View):
input_views.append(el)
else:
input_views.append(elem_cls.coerce_view(el))
Expand Down Expand Up @@ -527,7 +530,9 @@ def __new__(cls, *args, backing: Optional[Node] = None, hook: Optional[ViewHook]
raise Exception(f"invalid inputs length: {len(vals)}, vector length is: {vector_length}")
input_views = []
for el in vals:
if isinstance(el, View):
if isinstance(el, BackedView):
input_views.append(elem_cls(backing=el.get_backing()))
elif isinstance(el, View):
input_views.append(el)
else:
input_views.append(elem_cls.coerce_view(el))
Expand Down Expand Up @@ -731,7 +736,9 @@ def __new__(cls, *args, backing: Optional[Node] = None, hook: Optional[ViewHook]
fnode: Node
if fkey in kwargs:
finput = kwargs.pop(fkey)
if isinstance(finput, View):
if isinstance(finput, BackedView):
fnode = ftyp(backing=finput.get_backing()).get_backing()
elif isinstance(finput, View):
fnode = finput.get_backing()
else:
fnode = ftyp.coerce_view(finput).get_backing()
Expand Down
15 changes: 13 additions & 2 deletions remerkleable/stable_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from remerkleable.byte_arrays import ByteList, ByteVector
from remerkleable.complex import ComplexView, Container, FieldOffset, List, Vector, \
decode_offset, encode_offset
from remerkleable.core import View, ViewHook, ViewMeta, OFFSET_BYTE_LENGTH
from remerkleable.core import BackedView, View, ViewHook, ViewMeta, OFFSET_BYTE_LENGTH
from remerkleable.tree import Gindex, NavigationError, Node, PairNode, \
get_depth, subtree_fill_to_contents, zero_node, \
RIGHT_GINDEX
Expand Down Expand Up @@ -84,7 +84,9 @@ def __new__(cls, backing: Optional[Node] = None, hook: Optional[ViewHook] = None
fnode = zero_node(0)
active_fields.set(findex, False)
else:
if isinstance(finput, View):
if isinstance(finput, BackedView):
fnode = ftyp(backing=finput.get_backing()).get_backing()
elif isinstance(finput, View):
fnode = finput.get_backing()
else:
fnode = ftyp.coerce_view(finput).get_backing()
Expand Down Expand Up @@ -330,6 +332,15 @@ def __new__(cls, backing: Optional[Node] = None, hook: Optional[ViewHook] = None
if backing is not None:
if len(kwargs) != 0:
raise Exception('Cannot have both a backing and elements to init fields')
active_fields = Bitvector[cls.B.N].view_from_backing(backing.get_right())
for fkey, (findex, _) in cls.B._field_indices.items():
if fkey not in cls._field_indices:
if active_fields.get(findex):
raise ValueError(f'Cannot convert to `{cls.__name__}`: {fkey} unsupported')
else:
(_, _, fopt) = cls._field_indices[fkey]
if not fopt and not active_fields.get(findex):
raise ValueError(f'Cannot convert to `{cls.__name__}`: {fkey} is required')
return super().__new__(cls, backing=backing, hook=hook, **kwargs)

extra_kw = kwargs.copy()
Expand Down
32 changes: 32 additions & 0 deletions remerkleable/test_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,10 @@ class ShapePairRepr(Container):
square = Square(radius=0x42, color=1)
with pytest.raises(Exception):
circle = Circle(side=0x42, color=1)
with pytest.raises(Exception):
square = Square.coerce_view(Shape(radius=0x42, color=1))
with pytest.raises(Exception):
square = Square(backing=Circle(radius=0x42, color=1).get_backing())

# Surrounding container tests
class ShapeContainer(Container):
Expand Down Expand Up @@ -741,6 +745,34 @@ class ShapeContainerRepr(Container):
),
).hash_tree_root()

# Unsupported surrounding container tests
with pytest.raises(Exception):
shapes = List[Square, 5].coerce_view(
List[Circle, 5](Circle(radius=0x42, color=1)))
with pytest.raises(Exception):
shapes = Vector[Square, 1].coerce_view(
Vector[Circle, 1](Circle(radius=0x42, color=1)))

class SquareContainer(Container):
shape: Square

class CircleContainer(Container):
shape: Circle

with pytest.raises(Exception):
shape = SquareContainer.coerce_view(
CircleContainer(shape=Circle(radius=0x42, color=1)))

class SquareStableContainer(StableContainer[1]):
shape: Optional[Square]

class CircleStableContainer(StableContainer[1]):
shape: Optional[Circle]

with pytest.raises(Exception):
shape = SquareStableContainer.coerce_view(
CircleStableContainer(shape=Circle(radius=0x42, color=1)))

# basic container
class Shape1(StableContainer[4]):
side: Optional[uint16]
Expand Down

0 comments on commit 74fadc0

Please sign in to comment.