eth2.0-specs/test_libs/pyspec/eth2spec/utils/ssz/ssz_partials.py

82 lines
2.4 KiB
Python
Raw Normal View History

2019-05-28 13:30:35 +00:00
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))}