Starting work on partials
This commit is contained in:
parent
132d3c976a
commit
19601df572
|
@ -1 +1,2 @@
|
||||||
from .ssz_impl import *
|
from .ssz_impl import *
|
||||||
|
from .ssz_partials import *
|
||||||
|
|
|
@ -35,7 +35,7 @@ def is_fixed_size(typ):
|
||||||
|
|
||||||
|
|
||||||
@infer_input_type
|
@infer_input_type
|
||||||
def serialize(obj, typ):
|
def serialize(obj, typ=None):
|
||||||
if is_basic_type(typ):
|
if is_basic_type(typ):
|
||||||
return serialize_basic(obj, typ)
|
return serialize_basic(obj, typ)
|
||||||
elif is_list_type(typ) or is_vector_type(typ):
|
elif is_list_type(typ) or is_vector_type(typ):
|
||||||
|
@ -100,7 +100,7 @@ def mix_in_length(root, length):
|
||||||
|
|
||||||
|
|
||||||
@infer_input_type
|
@infer_input_type
|
||||||
def hash_tree_root(obj, typ):
|
def hash_tree_root(obj, typ=None):
|
||||||
if is_basic_type(typ):
|
if is_basic_type(typ):
|
||||||
return merkleize_chunks(chunkify(serialize_basic(obj, typ)))
|
return merkleize_chunks(chunkify(serialize_basic(obj, typ)))
|
||||||
elif is_list_type(typ) or is_vector_type(typ):
|
elif is_list_type(typ) or is_vector_type(typ):
|
||||||
|
@ -119,7 +119,7 @@ def hash_tree_root(obj, typ):
|
||||||
|
|
||||||
|
|
||||||
@infer_input_type
|
@infer_input_type
|
||||||
def signing_root(obj, typ):
|
def signing_root(obj, typ=None):
|
||||||
assert is_container_typ(typ)
|
assert is_container_typ(typ)
|
||||||
leaves = [hash_tree_root(elem, subtyp) for elem, subtyp in obj.get_fields()[:-1]]
|
leaves = [hash_tree_root(elem, subtyp) for elem, subtyp in obj.get_fields()[:-1]]
|
||||||
return merkleize_chunks(chunkify(b''.join(leaves)))
|
return merkleize_chunks(chunkify(b''.join(leaves)))
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
from ..merkle_minimal import hash, next_power_of_two
|
||||||
|
from .ssz_typing import *
|
||||||
|
from .ssz_impl import *
|
||||||
|
|
||||||
|
ZERO_CHUNK = b'\x00' * 32
|
||||||
|
|
||||||
|
def last_power_of_two(x):
|
||||||
|
return next_power_of_two(x+1) // 2
|
||||||
|
|
||||||
|
def concat_generalized_indices(x, y):
|
||||||
|
return x * last_power_of_two(y) + y - last_power_of_two(y)
|
||||||
|
|
||||||
|
def rebase(objs, new_root):
|
||||||
|
return {concat_generalized_indices(new_root, k): v for k,v in objs.items()}
|
||||||
|
|
||||||
|
def constrict_generalized_index(x, q):
|
||||||
|
depth = last_power_of_two(x // q)
|
||||||
|
o = depth + x - q * depth
|
||||||
|
if concat_generalized_indices(q, o) != x:
|
||||||
|
return None
|
||||||
|
return o
|
||||||
|
|
||||||
|
def unrebase(objs, q):
|
||||||
|
o = {}
|
||||||
|
for k,v in objs.items():
|
||||||
|
new_k = constrict_generalized_index(k, q)
|
||||||
|
if new_k is not None:
|
||||||
|
o[new_k] = v
|
||||||
|
return o
|
||||||
|
|
||||||
|
def filler(starting_position, chunk_count):
|
||||||
|
at, skip, end = chunk_count, 1, next_power_of_two(chunk_count)
|
||||||
|
value = ZERO_CHUNK
|
||||||
|
o = {}
|
||||||
|
while at < end:
|
||||||
|
while at % (skip*2) == 0:
|
||||||
|
skip *= 2
|
||||||
|
value = hash(value + value)
|
||||||
|
o[starting_position + at] = value
|
||||||
|
at += skip
|
||||||
|
return o
|
||||||
|
|
||||||
|
def merkle_tree_of_chunks(chunks, root):
|
||||||
|
starting_index = root * next_power_of_two(len(chunks))
|
||||||
|
o = {starting_index+i: chunk for i,chunk in enumerate(chunks)}
|
||||||
|
o = {**o, **filler(starting_index, len(chunks))}
|
||||||
|
return o
|
||||||
|
|
||||||
|
def is_bottom_layer_type(typ):
|
||||||
|
return (
|
||||||
|
is_basic_type(typ) or
|
||||||
|
(is_list_type(typ) or is_vector_type(typ)) and is_basic_type(read_elem_typ(typ))
|
||||||
|
)
|
||||||
|
|
||||||
|
@infer_input_type
|
||||||
|
def get_fields(obj, typ=None):
|
||||||
|
if is_container_typ(typ):
|
||||||
|
return obj.get_fields()
|
||||||
|
elif is_list_type(typ) or is_vector_type(typ):
|
||||||
|
subtype = read_elem_typ(typ)
|
||||||
|
return zip([subtype] * len(obj), obj)
|
||||||
|
else:
|
||||||
|
raise Exception("Invalid type")
|
||||||
|
|
||||||
|
@infer_input_type
|
||||||
|
def ssz_all(obj, typ=None, root=1):
|
||||||
|
if is_list_type(typ):
|
||||||
|
o = {root * 2 + 1: len(obj).to_bytes(32, 'little')}
|
||||||
|
base = root * 2
|
||||||
|
else:
|
||||||
|
o = {}
|
||||||
|
base = root
|
||||||
|
if is_bottom_layer_type(typ):
|
||||||
|
data = serialize_basic(obj, typ) if is_basic_type(typ) else pack(obj, read_elem_typ(typ))
|
||||||
|
return {**o, **merkle_tree_of_chunks(chunkify(data), base)}
|
||||||
|
else:
|
||||||
|
fields = get_fields(obj, typ=typ)
|
||||||
|
sub_base = base * next_power_of_two(len(fields))
|
||||||
|
for i, (elem, subtype) in enumerate(fields):
|
||||||
|
o = {**o, **ssz_all(elem, typ=subtype, root=sub_base+i)}
|
||||||
|
return {**o, **filter(sub_base, len(fields))}
|
|
@ -1,7 +1,10 @@
|
||||||
from typing import List, Iterable, Type, NewType
|
from typing import List, Iterable, Type, NewType, TypeVar
|
||||||
from typing import Union
|
from typing import Union
|
||||||
from inspect import isclass
|
from inspect import isclass
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
L = TypeVar('L')
|
||||||
|
|
||||||
|
|
||||||
# SSZ integers
|
# SSZ integers
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
|
@ -64,13 +67,13 @@ class uint256(uint):
|
||||||
def is_uint(typ):
|
def is_uint(typ):
|
||||||
# All integers are uint in the scope of the spec here.
|
# All integers are uint in the scope of the spec here.
|
||||||
# Since we default to uint64. Bounds can be checked elsewhere.
|
# Since we default to uint64. Bounds can be checked elsewhere.
|
||||||
return issubclass(typ, int)
|
return (isinstance(typ, int.__class__) and issubclass(typ, int)) or typ == uint64
|
||||||
|
|
||||||
|
|
||||||
def uint_byte_size(typ):
|
def uint_byte_size(typ):
|
||||||
if issubclass(typ, uint):
|
if isinstance(typ, int.__class__) and issubclass(typ, uint):
|
||||||
return typ.byte_len
|
return typ.byte_len
|
||||||
elif issubclass(typ, int):
|
elif typ in (int, uint64):
|
||||||
# Default to uint64
|
# Default to uint64
|
||||||
return 8
|
return 8
|
||||||
else:
|
else:
|
||||||
|
@ -109,7 +112,7 @@ class Container(object):
|
||||||
return [getattr(self, field) for field in cls.get_field_names()]
|
return [getattr(self, field) for field in cls.get_field_names()]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return {field: getattr(self, field) for field in self.get_field_names()}
|
return repr({field: getattr(self, field) for field in self.get_field_names()})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fields_dict(cls):
|
def get_fields_dict(cls):
|
||||||
|
@ -221,7 +224,7 @@ class Vector(metaclass=VectorMeta):
|
||||||
return hash_tree_root(self, self.__class__)
|
return hash_tree_root(self, self.__class__)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return {'length': self.__class__.length, 'items': self.items}
|
return repr({'length': self.__class__.length, 'items': self.items})
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.items[key]
|
return self.items[key]
|
||||||
|
@ -370,10 +373,10 @@ def infer_input_type(fn):
|
||||||
"""
|
"""
|
||||||
Decorator to run infer_type on the obj if typ argument is None
|
Decorator to run infer_type on the obj if typ argument is None
|
||||||
"""
|
"""
|
||||||
def infer_helper(obj, typ=None):
|
def infer_helper(obj, *args, typ=None, **kwargs):
|
||||||
if typ is None:
|
if typ is None:
|
||||||
typ = infer_type(obj)
|
typ = infer_type(obj)
|
||||||
return fn(obj, typ)
|
return fn(obj, *args, typ=typ, **kwargs)
|
||||||
return infer_helper
|
return infer_helper
|
||||||
|
|
||||||
|
|
||||||
|
@ -381,10 +384,10 @@ def is_list_type(typ):
|
||||||
return (hasattr(typ, '_name') and typ._name == 'List') or typ == bytes
|
return (hasattr(typ, '_name') and typ._name == 'List') or typ == bytes
|
||||||
|
|
||||||
def is_vector_type(typ):
|
def is_vector_type(typ):
|
||||||
return issubclass(typ, Vector)
|
return isinstance(typ, int.__class__) and issubclass(typ, Vector)
|
||||||
|
|
||||||
def is_container_typ(typ):
|
def is_container_typ(typ):
|
||||||
return issubclass(typ, Container)
|
return isinstance(typ, int.__class__) and issubclass(typ, Container)
|
||||||
|
|
||||||
def read_list_elem_typ(list_typ: Type[List[T]]) -> T:
|
def read_list_elem_typ(list_typ: Type[List[T]]) -> T:
|
||||||
if list_typ.__args__ is None or len(list_typ.__args__) != 1:
|
if list_typ.__args__ is None or len(list_typ.__args__) != 1:
|
||||||
|
|
Loading…
Reference in New Issue