82 lines
2.4 KiB
Python
82 lines
2.4 KiB
Python
|
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))}
|