def decode(data, typ): if is_uint_type(typ): return data elif is_bool_type(typ): assert data in (True, False) return data elif is_list_type(typ): elem_typ = read_list_elem_type(typ) return [decode(element, elem_typ) for element in data] elif is_vector_type(typ): elem_typ = read_vector_elem_type(typ) return Vector(decode(element, elem_typ) for element in data) elif is_bytes_type(typ): return bytes.fromhex(data[2:]) elif is_bytesn_type(typ): return BytesN(bytes.fromhex(data[2:])) elif is_container_type(typ): temp = {} for field, subtype in typ.get_fields(): temp[field] = decode(data[field], subtype) if field + "_hash_tree_root" in data: assert (data[field + "_hash_tree_root"][2:] == hash_tree_root( temp[field], subtype).hex()) ret = typ(**temp) if "hash_tree_root" in data: assert (data["hash_tree_root"][2:] == hash_tree_root(ret, typ).hex()) return ret else: raise Exception(f"Type not recognized: data={data}, typ={typ}")
def signing_root(obj, typ): assert is_container_type(typ) # ignore last field leaves = [ hash_tree_root(field_value, typ=field_typ) for field_value, field_typ in obj.get_typed_values()[:-1] ] return merkleize_chunks(chunkify(b''.join(leaves)))
def get_typed_values(obj, typ=None): if is_container_type(typ): return obj.get_typed_values() elif is_list_kind(typ) or is_vector_kind(typ): elem_type = read_elem_type(typ) return list(zip(obj, [elem_type] * len(obj))) else: raise Exception("Invalid type")
def serialize(obj, typ=None): if is_basic_type(typ): return serialize_basic(obj, typ) elif is_list_kind(typ) or is_vector_kind(typ): return encode_series(obj, [read_elem_type(typ)] * len(obj)) elif is_container_type(typ): return encode_series(obj.get_field_values(), typ.get_field_types()) else: raise Exception("Type not supported: {}".format(typ))
def is_fixed_size(typ): if is_basic_type(typ): return True elif is_list_kind(typ): return False elif is_vector_kind(typ): return is_fixed_size(read_vector_elem_type(typ)) elif is_container_type(typ): return all(is_fixed_size(t) for t in typ.get_field_types()) else: raise Exception("Type not supported: {}".format(typ))
def translate_value(value, typ): """ Translate a value output from Py-SSZ deserialization into the given spec type. :param value: The PySSZ value :param typ: The type from the spec to translate into :return: the translated value """ if spec_ssz.is_uint_type(typ): size = spec_ssz.uint_byte_size(typ) if size == 1: return spec_ssz.uint8(value) elif size == 2: return spec_ssz.uint16(value) elif size == 4: return spec_ssz.uint32(value) elif size == 8: # uint64 is default (TODO this is changing soon) return value elif size == 16: return spec_ssz.uint128(value) elif size == 32: return spec_ssz.uint256(value) else: raise TypeError("invalid uint size") elif spec_ssz.is_list_type(typ): elem_typ = spec_ssz.read_elem_type(typ) return [translate_value(elem, elem_typ) for elem in value] elif spec_ssz.is_bool_type(typ): return value elif spec_ssz.is_vector_type(typ): elem_typ = spec_ssz.read_elem_type(typ) return typ(*(translate_value(elem, elem_typ) for elem in value)) elif spec_ssz.is_bytesn_type(typ): return typ(value) elif spec_ssz.is_bytes_type(typ): return value elif spec_ssz.is_container_type(typ): return typ( **{ f_name: translate_value(f_val, f_typ) for (f_name, f_val, f_typ) in zip(typ.get_field_names(), value, typ.get_field_types()) }) else: raise TypeError("Type not supported: {}".format(typ))
def translate_typ(typ) -> ssz.BaseSedes: """ Translates a spec type to a Py-SSZ type description (sedes). :param typ: The spec type, a class. :return: The Py-SSZ equivalent. """ if spec_ssz.is_container_type(typ): return ssz.Container([ translate_typ(field_typ) for (field_name, field_typ) in typ.get_fields() ]) elif spec_ssz.is_bytesn_type(typ): return ssz.ByteVector(typ.length) elif spec_ssz.is_bytes_type(typ): return ssz.ByteList() elif spec_ssz.is_vector_type(typ): return ssz.Vector(translate_typ(spec_ssz.read_vector_elem_type(typ)), typ.length) elif spec_ssz.is_list_type(typ): return ssz.List(translate_typ(spec_ssz.read_list_elem_type(typ))) elif spec_ssz.is_bool_type(typ): return ssz.boolean elif spec_ssz.is_uint_type(typ): size = spec_ssz.uint_byte_size(typ) if size == 1: return ssz.uint8 elif size == 2: return ssz.uint16 elif size == 4: return ssz.uint32 elif size == 8: return ssz.uint64 elif size == 16: return ssz.uint128 elif size == 32: return ssz.uint256 else: raise TypeError("invalid uint size") else: raise TypeError("Type not supported: {}".format(typ))
def get_random_ssz_object(rng: Random, typ: Any, max_bytes_length: int, max_list_length: int, mode: RandomizationMode, chaos: bool) -> Any: """ Create an object for a given type, filled with random data. :param rng: The random number generator to use. :param typ: The type to instantiate :param max_bytes_length: the max. length for a random bytes array :param max_list_length: the max. length for a random list :param mode: how to randomize :param chaos: if true, the randomization-mode will be randomly changed :return: the random object instance, of the given type. """ if chaos: mode = rng.choice(list(RandomizationMode)) if is_bytes_type(typ): # Bytes array if mode == RandomizationMode.mode_nil_count: return b'' elif mode == RandomizationMode.mode_max_count: return get_random_bytes_list(rng, max_bytes_length) elif mode == RandomizationMode.mode_one_count: return get_random_bytes_list(rng, 1) elif mode == RandomizationMode.mode_zero: return b'\x00' elif mode == RandomizationMode.mode_max: return b'\xff' else: return get_random_bytes_list(rng, rng.randint(0, max_bytes_length)) elif is_bytesn_type(typ): # BytesN length = typ.length # Sanity, don't generate absurdly big random values # If a client is aiming to performance-test, they should create a benchmark suite. assert length <= max_bytes_length if mode == RandomizationMode.mode_zero: return b'\x00' * length elif mode == RandomizationMode.mode_max: return b'\xff' * length else: return get_random_bytes_list(rng, length) elif is_basic_type(typ): # Basic types if mode == RandomizationMode.mode_zero: return get_min_basic_value(typ) elif mode == RandomizationMode.mode_max: return get_max_basic_value(typ) else: return get_random_basic_value(rng, typ) elif is_vector_type(typ): # Vector elem_typ = read_vector_elem_type(typ) return [ get_random_ssz_object(rng, elem_typ, max_bytes_length, max_list_length, mode, chaos) for _ in range(typ.length) ] elif is_list_type(typ): # List elem_typ = read_list_elem_type(typ) length = rng.randint(0, max_list_length) if mode == RandomizationMode.mode_one_count: length = 1 elif mode == RandomizationMode.mode_max_count: length = max_list_length return [ get_random_ssz_object(rng, elem_typ, max_bytes_length, max_list_length, mode, chaos) for _ in range(length) ] elif is_container_type(typ): # Container return typ(**{ field: get_random_ssz_object(rng, subtype, max_bytes_length, max_list_length, mode, chaos) for field, subtype in typ.get_fields() }) else: raise Exception(f"Type not recognized: typ={typ}")