From 0f79ed709bd4846299fb4379ed22d1de47f94e02 Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 27 May 2019 22:19:18 +0200 Subject: [PATCH] update yaml encoder/decoder and obj randomizer for typed ssz usage --- test_libs/pyspec/eth2spec/debug/decode.py | 16 +-- test_libs/pyspec/eth2spec/debug/encode.py | 11 +- .../pyspec/eth2spec/debug/random_value.py | 112 +++++++++--------- 3 files changed, 68 insertions(+), 71 deletions(-) diff --git a/test_libs/pyspec/eth2spec/debug/decode.py b/test_libs/pyspec/eth2spec/debug/decode.py index 261692bed..c9657dc28 100644 --- a/test_libs/pyspec/eth2spec/debug/decode.py +++ b/test_libs/pyspec/eth2spec/debug/decode.py @@ -3,22 +3,22 @@ from eth2spec.utils.ssz.ssz_typing import * def decode(data, typ): - if is_uint(typ): + if is_uint_type(typ): return data elif is_bool_type(typ): assert data in (True, False) return data - elif issubclass(typ, list): - elem_typ = read_list_elem_typ(typ) + elif is_list_type(typ): + elem_typ = read_list_elem_type(typ) return [decode(element, elem_typ) for element in data] - elif issubclass(typ, Vector): - elem_typ = read_vector_elem_typ(typ) + elif is_vector_type(typ): + elem_typ = read_vector_elem_type(typ) return Vector(decode(element, elem_typ) for element in data) - elif issubclass(typ, bytes): + elif is_bytes_type(typ): return bytes.fromhex(data[2:]) - elif issubclass(typ, BytesN): + elif is_bytesn_type(typ): return BytesN(bytes.fromhex(data[2:])) - elif is_container_typ(typ): + elif is_container_type(typ): temp = {} for field, subtype in typ.get_fields(): temp[field] = decode(data[field], subtype) diff --git a/test_libs/pyspec/eth2spec/debug/encode.py b/test_libs/pyspec/eth2spec/debug/encode.py index 3c0658c8f..832203e35 100644 --- a/test_libs/pyspec/eth2spec/debug/encode.py +++ b/test_libs/pyspec/eth2spec/debug/encode.py @@ -3,19 +3,20 @@ from eth2spec.utils.ssz.ssz_typing import * def encode(value, typ, include_hash_tree_roots=False): - if is_uint(typ): + if is_uint_type(typ): + # Larger uints are boxed and the class declares their byte length if issubclass(typ, uint) and typ.byte_len > 8: return str(value) return value elif is_bool_type(typ): assert value in (True, False) return value - elif issubclass(typ, list) or issubclass(typ, Vector): - elem_typ = read_elem_typ(typ) + elif is_list_type(typ) or is_vector_type(typ): + elem_typ = read_elem_type(typ) return [encode(element, elem_typ, include_hash_tree_roots) for element in value] - elif issubclass(typ, bytes): + elif issubclass(typ, bytes): # both bytes and BytesN return '0x' + value.hex() - elif is_container_typ(typ): + elif is_container_type(typ): ret = {} for field, subtype in typ.get_fields(): field_value = getattr(value, field) diff --git a/test_libs/pyspec/eth2spec/debug/random_value.py b/test_libs/pyspec/eth2spec/debug/random_value.py index f28181943..5abd73086 100644 --- a/test_libs/pyspec/eth2spec/debug/random_value.py +++ b/test_libs/pyspec/eth2spec/debug/random_value.py @@ -2,10 +2,11 @@ from random import Random from typing import Any from enum import Enum +from eth2spec.utils.ssz.ssz_typing import * +from eth2spec.utils.ssz.ssz_impl import is_basic_type -UINT_SIZES = [8, 16, 32, 64, 128, 256] - -basic_types = ["uint%d" % v for v in UINT_SIZES] + ['bool', 'byte'] +# in bytes +UINT_SIZES = [1, 2, 4, 8, 16, 32] random_mode_names = ["random", "zero", "max", "nil", "one", "lengthy"] @@ -49,60 +50,61 @@ def get_random_ssz_object(rng: Random, """ if chaos: mode = rng.choice(list(RandomizationMode)) - if isinstance(typ, str): - # Bytes array - if typ == 'bytes': - if mode == RandomizationMode.mode_nil_count: - return b'' - if mode == RandomizationMode.mode_max_count: - return get_random_bytes_list(rng, max_bytes_length) - if mode == RandomizationMode.mode_one_count: - return get_random_bytes_list(rng, 1) - if mode == RandomizationMode.mode_zero: - return b'\x00' - if mode == RandomizationMode.mode_max: - return b'\xff' - return get_random_bytes_list(rng, rng.randint(0, max_bytes_length)) - elif typ[:5] == 'bytes' and len(typ) > 5: - length = int(typ[5:]) - # 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 - if mode == RandomizationMode.mode_max: - return b'\xff' * length - return get_random_bytes_list(rng, length) - # Basic types - else: - if mode == RandomizationMode.mode_zero: - return get_min_basic_value(typ) - if mode == RandomizationMode.mode_max: - return get_max_basic_value(typ) - return get_random_basic_value(rng, typ) + # Bytes array + if is_bytes_type(typ): + if mode == RandomizationMode.mode_nil_count: + return b'' + if mode == RandomizationMode.mode_max_count: + return get_random_bytes_list(rng, max_bytes_length) + if mode == RandomizationMode.mode_one_count: + return get_random_bytes_list(rng, 1) + if mode == RandomizationMode.mode_zero: + return b'\x00' + if mode == RandomizationMode.mode_max: + return b'\xff' + return get_random_bytes_list(rng, rng.randint(0, max_bytes_length)) + elif is_bytesn_type(typ): + 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 + if mode == RandomizationMode.mode_max: + return b'\xff' * length + return get_random_bytes_list(rng, length) + # Basic types + elif is_basic_type(typ): + if mode == RandomizationMode.mode_zero: + return get_min_basic_value(typ) + if mode == RandomizationMode.mode_max: + return get_max_basic_value(typ) + return get_random_basic_value(rng, typ) # Vector: - elif isinstance(typ, list) and len(typ) == 2: + elif is_vector_type(typ): + elem_typ = read_vector_elem_type(typ) return [ - get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos) - for _ in range(typ[1]) + get_random_ssz_object(rng, elem_typ, max_bytes_length, max_list_length, mode, chaos) + for _ in range(typ.length) ] # List: - elif isinstance(typ, list) and len(typ) == 1: + elif is_list_type(typ): + elem_typ = read_list_elem_type(typ) length = rng.randint(0, max_list_length) if mode == RandomizationMode.mode_one_count: length = 1 if mode == RandomizationMode.mode_max_count: length = max_list_length return [ - get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos) + get_random_ssz_object(rng, elem_typ, max_bytes_length, max_list_length, mode, chaos) for _ in range(length) ] # Container: - elif hasattr(typ, 'fields'): + elif is_container_type(typ): return typ(**{ field: get_random_ssz_object(rng, subtype, max_bytes_length, max_list_length, mode, chaos) - for field, subtype in typ.fields.items() + for field, subtype in typ.get_fields() }) else: print(typ) @@ -114,39 +116,33 @@ def get_random_bytes_list(rng: Random, length: int) -> bytes: def get_random_basic_value(rng: Random, typ: str) -> Any: - if typ == 'bool': + if is_bool_type(typ): return rng.choice((True, False)) - if typ[:4] == 'uint': - size = int(typ[4:]) + if is_uint_type(typ): + size = uint_byte_size(typ) assert size in UINT_SIZES - return rng.randint(0, 2**size - 1) - if typ == 'byte': - return rng.randint(0, 8) + return rng.randint(0, 256**size - 1) else: raise ValueError("Not a basic type") def get_min_basic_value(typ: str) -> Any: - if typ == 'bool': + if is_bool_type(typ): return False - if typ[:4] == 'uint': - size = int(typ[4:]) + if is_uint_type(typ): + size = uint_byte_size(typ) assert size in UINT_SIZES return 0 - if typ == 'byte': - return 0x00 else: raise ValueError("Not a basic type") def get_max_basic_value(typ: str) -> Any: - if typ == 'bool': + if is_bool_type(typ): return True - if typ[:4] == 'uint': - size = int(typ[4:]) + if is_uint_type(typ): + size = uint_byte_size(typ) assert size in UINT_SIZES - return 2**size - 1 - if typ == 'byte': - return 0xff + return 256**size - 1 else: raise ValueError("Not a basic type")