This commit is contained in:
Hsiao-Wei Wang
2019-06-04 17:42:21 +08:00
parent fb584bc067
commit a7ee6f108e
4 changed files with 80 additions and 59 deletions

View File

@@ -36,5 +36,4 @@ def decode(data, typ):
hash_tree_root(ret, typ).hex())
return ret
else:
print(data, typ)
raise Exception("Type not recognized")
raise Exception(f"Type not recognized: data={data}, typ={typ}")

View File

@@ -33,5 +33,4 @@ def encode(value, typ, include_hash_tree_roots=False):
ret["hash_tree_root"] = '0x' + hash_tree_root(value, typ).hex()
return ret
else:
print(value, typ)
raise Exception("Type not recognized")
raise Exception(f"Type not recognized: value={value}, typ={typ}")

View File

@@ -56,65 +56,69 @@ def get_random_ssz_object(rng: Random,
"""
if chaos:
mode = rng.choice(list(RandomizationMode))
# Bytes array
if is_bytes_type(typ):
# Bytes array
if mode == RandomizationMode.mode_nil_count:
return b''
if mode == RandomizationMode.mode_max_count:
elif mode == RandomizationMode.mode_max_count:
return get_random_bytes_list(rng, max_bytes_length)
if mode == RandomizationMode.mode_one_count:
elif mode == RandomizationMode.mode_one_count:
return get_random_bytes_list(rng, 1)
if mode == RandomizationMode.mode_zero:
elif mode == RandomizationMode.mode_zero:
return b'\x00'
if mode == RandomizationMode.mode_max:
elif mode == RandomizationMode.mode_max:
return b'\xff'
return get_random_bytes_list(rng, rng.randint(0, max_bytes_length))
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
if mode == RandomizationMode.mode_max:
elif mode == RandomizationMode.mode_max:
return b'\xff' * length
return get_random_bytes_list(rng, length)
# Basic types
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)
if mode == RandomizationMode.mode_max:
elif mode == RandomizationMode.mode_max:
return get_max_basic_value(typ)
return get_random_basic_value(rng, typ)
# Vector:
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)
]
# List:
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
if mode == RandomizationMode.mode_max_count:
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)
]
# Container:
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:
print(typ)
raise Exception("Type not recognized")
raise Exception(f"Type not recognized: typ={typ}")
def get_random_bytes_list(rng: Random, length: int) -> bytes:
@@ -129,7 +133,7 @@ def get_random_basic_value(rng: Random, typ) -> Any:
assert size in UINT_SIZES
return rng.randint(0, 256**size - 1)
else:
raise ValueError("Not a basic type")
raise ValueError(f"Not a basic type: typ={typ}")
def get_min_basic_value(typ) -> Any:
@@ -140,7 +144,7 @@ def get_min_basic_value(typ) -> Any:
assert size in UINT_SIZES
return 0
else:
raise ValueError("Not a basic type")
raise ValueError(f"Not a basic type: typ={typ}")
def get_max_basic_value(typ) -> Any:
@@ -151,4 +155,4 @@ def get_max_basic_value(typ) -> Any:
assert size in UINT_SIZES
return 256**size - 1
else:
raise ValueError("Not a basic type")
raise ValueError(f"Not a basic type: typ={typ}")

View File

@@ -83,13 +83,15 @@ def is_uint_type(typ):
def uint_byte_size(typ):
if hasattr(typ, '__supertype__'):
typ = typ.__supertype__
if isinstance(typ, type):
if issubclass(typ, uint):
return typ.byte_len
elif issubclass(typ, int):
# Default to uint64
return 8
raise TypeError("Type %s is not an uint (or int-default uint64) type" % typ)
else:
raise TypeError("Type %s is not an uint (or int-default uint64) type" % typ)
# SSZ Container base class
@@ -167,32 +169,34 @@ def _is_vector_instance_of(a, b):
# Other must not be a BytesN
if issubclass(b, bytes):
return False
if not hasattr(b, 'elem_type') or not hasattr(b, 'length'):
elif not hasattr(b, 'elem_type') or not hasattr(b, 'length'):
# Vector (b) is not an instance of Vector[X, Y] (a)
return False
if not hasattr(a, 'elem_type') or not hasattr(a, 'length'):
elif not hasattr(a, 'elem_type') or not hasattr(a, 'length'):
# Vector[X, Y] (b) is an instance of Vector (a)
return True
# Vector[X, Y] (a) is an instance of Vector[X, Y] (b)
return a.elem_type == b.elem_type and a.length == b.length
else:
# Vector[X, Y] (a) is an instance of Vector[X, Y] (b)
return a.elem_type == b.elem_type and a.length == b.length
def _is_equal_vector_type(a, b):
# Other must not be a BytesN
if issubclass(b, bytes):
return False
if not hasattr(a, 'elem_type') or not hasattr(a, 'length'):
elif not hasattr(a, 'elem_type') or not hasattr(a, 'length'):
if not hasattr(b, 'elem_type') or not hasattr(b, 'length'):
# Vector == Vector
return True
# Vector != Vector[X, Y]
return False
if not hasattr(b, 'elem_type') or not hasattr(b, 'length'):
else:
# Vector != Vector[X, Y]
return False
elif not hasattr(b, 'elem_type') or not hasattr(b, 'length'):
# Vector[X, Y] != Vector
return False
# Vector[X, Y] == Vector[X, Y]
return a.elem_type == b.elem_type and a.length == b.length
else:
# Vector[X, Y] == Vector[X, Y]
return a.elem_type == b.elem_type and a.length == b.length
class VectorMeta(type):
@@ -233,7 +237,7 @@ class Vector(metaclass=VectorMeta):
cls = self.__class__
if not hasattr(cls, 'elem_type'):
raise TypeError("Type Vector without elem_type data cannot be instantiated")
if not hasattr(cls, 'length'):
elif not hasattr(cls, 'length'):
raise TypeError("Type Vector without length data cannot be instantiated")
if len(args) != cls.length:
@@ -282,32 +286,34 @@ def _is_bytes_n_instance_of(a, b):
# Other has to be a Bytes derivative class to be a BytesN
if not issubclass(b, bytes):
return False
if not hasattr(b, 'length'):
elif not hasattr(b, 'length'):
# BytesN (b) is not an instance of BytesN[X] (a)
return False
if not hasattr(a, 'length'):
elif not hasattr(a, 'length'):
# BytesN[X] (b) is an instance of BytesN (a)
return True
# BytesN[X] (a) is an instance of BytesN[X] (b)
return a.length == b.length
else:
# BytesN[X] (a) is an instance of BytesN[X] (b)
return a.length == b.length
def _is_equal_bytes_n_type(a, b):
# Other has to be a Bytes derivative class to be a BytesN
if not issubclass(b, bytes):
return False
if not hasattr(a, 'length'):
elif not hasattr(a, 'length'):
if not hasattr(b, 'length'):
# BytesN == BytesN
return True
# BytesN != BytesN[X]
return False
if not hasattr(b, 'length'):
else:
# BytesN != BytesN[X]
return False
elif not hasattr(b, 'length'):
# BytesN[X] != BytesN
return False
# BytesN[X] == BytesN[X]
return a.length == b.length
else:
# BytesN[X] == BytesN[X]
return a.length == b.length
class BytesNMeta(type):
@@ -341,14 +347,15 @@ class BytesNMeta(type):
def parse_bytes(val):
if val is None:
return None
if isinstance(val, str):
elif isinstance(val, str):
# TODO: import from eth-utils instead, and do: hexstr_if_str(to_bytes, val)
return None
if isinstance(val, bytes):
elif isinstance(val, bytes):
return val
if isinstance(val, int):
elif isinstance(val, int):
return bytes([val])
return None
else:
return None
class BytesN(bytes, metaclass=BytesNMeta):
@@ -433,6 +440,9 @@ def infer_input_type(fn):
def is_bool_type(typ):
"""
Checks if the given type is a bool.
"""
if hasattr(typ, '__supertype__'):
typ = typ.__supertype__
return isinstance(typ, type) and issubclass(typ, bool)
@@ -446,36 +456,45 @@ def is_list_type(typ):
def is_bytes_type(typ):
"""
Check if the given type is a ``bytes``.
"""
# Do not accept subclasses of bytes here, to avoid confusion with BytesN
return typ == bytes
def is_bytesn_type(typ):
"""
Check if the given type is a BytesN.
"""
return isinstance(typ, type) and issubclass(typ, BytesN)
def is_list_kind(typ):
"""
Checks if the given type is a kind of list. Can be bytes.
Check if the given type is a kind of list. Can be bytes.
"""
return is_list_type(typ) or is_bytes_type(typ)
def is_vector_type(typ):
"""
Checks if the given type is a vector.
Check if the given type is a vector.
"""
return isinstance(typ, type) and issubclass(typ, Vector)
def is_bytesn_type(typ):
return isinstance(typ, type) and issubclass(typ, BytesN)
def is_vector_kind(typ):
"""
Checks if the given type is a kind of vector. Can be BytesN.
Check if the given type is a kind of vector. Can be BytesN.
"""
return is_vector_type(typ) or is_bytesn_type(typ)
def is_container_type(typ):
"""
Check if the given type is a container.
"""
return isinstance(typ, type) and issubclass(typ, Container)