mirror of
https://github.com/ethereum/consensus-specs.git
synced 2026-02-08 20:45:02 -05:00
Add Bitvector and Bitlist
Bool, Bit -> boolean, bit Fix simple-serialize.md
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
from typing import Any
|
||||
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
|
||||
from eth2spec.utils.ssz.ssz_typing import (
|
||||
SSZType, SSZValue, uint, Container, Bytes, List, Bool,
|
||||
SSZType, SSZValue, uint, Container, Bytes, List, boolean,
|
||||
Vector, BytesN
|
||||
)
|
||||
|
||||
|
||||
def decode(data: Any, typ: SSZType) -> SSZValue:
|
||||
if issubclass(typ, (uint, Bool)):
|
||||
if issubclass(typ, (uint, boolean)):
|
||||
return typ(data)
|
||||
elif issubclass(typ, (List, Vector)):
|
||||
return typ(decode(element, typ.elem_type) for element in data)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
|
||||
from eth2spec.utils.ssz.ssz_typing import (
|
||||
SSZValue, uint, Container, Bool
|
||||
SSZValue, uint, Container, boolean
|
||||
)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ def encode(value: SSZValue, include_hash_tree_roots=False):
|
||||
if value.type().byte_len > 8:
|
||||
return str(int(value))
|
||||
return int(value)
|
||||
elif isinstance(value, Bool):
|
||||
elif isinstance(value, boolean):
|
||||
return value == 1
|
||||
elif isinstance(value, list): # normal python lists, ssz-List, Vector
|
||||
return [encode(element, include_hash_tree_roots) for element in value]
|
||||
|
||||
@@ -2,7 +2,7 @@ from random import Random
|
||||
from enum import Enum
|
||||
|
||||
from eth2spec.utils.ssz.ssz_typing import (
|
||||
SSZType, SSZValue, BasicValue, BasicType, uint, Container, Bytes, List, Bool,
|
||||
SSZType, SSZValue, BasicValue, BasicType, uint, Container, Bytes, List, boolean,
|
||||
Vector, BytesN
|
||||
)
|
||||
|
||||
@@ -118,7 +118,7 @@ def get_random_bytes_list(rng: Random, length: int) -> bytes:
|
||||
|
||||
|
||||
def get_random_basic_value(rng: Random, typ: BasicType) -> BasicValue:
|
||||
if issubclass(typ, Bool):
|
||||
if issubclass(typ, boolean):
|
||||
return typ(rng.choice((True, False)))
|
||||
elif issubclass(typ, uint):
|
||||
assert typ.byte_len in UINT_BYTE_SIZES
|
||||
@@ -128,7 +128,7 @@ def get_random_basic_value(rng: Random, typ: BasicType) -> BasicValue:
|
||||
|
||||
|
||||
def get_min_basic_value(typ: BasicType) -> BasicValue:
|
||||
if issubclass(typ, Bool):
|
||||
if issubclass(typ, boolean):
|
||||
return typ(False)
|
||||
elif issubclass(typ, uint):
|
||||
assert typ.byte_len in UINT_BYTE_SIZES
|
||||
@@ -138,7 +138,7 @@ def get_min_basic_value(typ: BasicType) -> BasicValue:
|
||||
|
||||
|
||||
def get_max_basic_value(typ: BasicType) -> BasicValue:
|
||||
if issubclass(typ, Bool):
|
||||
if issubclass(typ, boolean):
|
||||
return typ(True)
|
||||
elif issubclass(typ, uint):
|
||||
assert typ.byte_len in UINT_BYTE_SIZES
|
||||
|
||||
@@ -19,7 +19,7 @@ def translate_typ(typ) -> ssz.BaseSedes:
|
||||
return ssz.Vector(translate_typ(typ.elem_type), typ.length)
|
||||
elif issubclass(typ, spec_ssz.List):
|
||||
return ssz.List(translate_typ(typ.elem_type))
|
||||
elif issubclass(typ, spec_ssz.Bool):
|
||||
elif issubclass(typ, spec_ssz.boolean):
|
||||
return ssz.boolean
|
||||
elif issubclass(typ, spec_ssz.uint):
|
||||
if typ.byte_len == 1:
|
||||
@@ -64,7 +64,7 @@ def translate_value(value, typ):
|
||||
raise TypeError("invalid uint size")
|
||||
elif issubclass(typ, spec_ssz.List):
|
||||
return [translate_value(elem, typ.elem_type) for elem in value]
|
||||
elif issubclass(typ, spec_ssz.Bool):
|
||||
elif issubclass(typ, spec_ssz.boolean):
|
||||
return value
|
||||
elif issubclass(typ, spec_ssz.Vector):
|
||||
return typ(*(translate_value(elem, typ.elem_type) for elem in value))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from ..merkle_minimal import merkleize_chunks
|
||||
from ..hash_function import hash
|
||||
from .ssz_typing import (
|
||||
SSZValue, SSZType, BasicValue, BasicType, Series, Elements, Bool, Container, List, Bytes, uint,
|
||||
SSZValue, SSZType, BasicValue, BasicType, Series, Elements, boolean, Container, List, Bytes,
|
||||
Bitlist, Bitvector, uint,
|
||||
)
|
||||
|
||||
# SSZ Serialization
|
||||
@@ -13,7 +14,7 @@ BYTES_PER_LENGTH_OFFSET = 4
|
||||
def serialize_basic(value: SSZValue):
|
||||
if isinstance(value, uint):
|
||||
return value.to_bytes(value.type().byte_len, 'little')
|
||||
elif isinstance(value, Bool):
|
||||
elif isinstance(value, boolean):
|
||||
if value:
|
||||
return b'\x01'
|
||||
else:
|
||||
@@ -39,6 +40,12 @@ def is_empty(obj: SSZValue):
|
||||
def serialize(obj: SSZValue):
|
||||
if isinstance(obj, BasicValue):
|
||||
return serialize_basic(obj)
|
||||
elif isinstance(obj, Bitvector):
|
||||
as_integer = sum([obj[i] << i for i in range(len(obj))])
|
||||
return as_integer.to_bytes((len(obj) + 7) // 8, "little")
|
||||
elif isinstance(obj, Bitlist):
|
||||
as_integer = (1 << len(obj)) + sum([obj[i] << i for i in range(len(obj))])
|
||||
return as_integer.to_bytes((as_integer.bit_length() + 7) // 8, "little")
|
||||
elif isinstance(obj, Series):
|
||||
return encode_series(obj)
|
||||
else:
|
||||
@@ -85,6 +92,12 @@ def encode_series(values: Series):
|
||||
def pack(values: Series):
|
||||
if isinstance(values, bytes): # Bytes and BytesN are already packed
|
||||
return values
|
||||
elif isinstance(values, Bitvector):
|
||||
as_integer = sum([values[i] << i for i in range(len(values))])
|
||||
return as_integer.to_bytes((values.length + 7) // 8, "little")
|
||||
elif isinstance(values, Bitlist):
|
||||
as_integer = (1 << len(values)) + sum([values[i] << i for i in range(len(values))])
|
||||
return as_integer.to_bytes((values.length + 7) // 8, "little")
|
||||
return b''.join([serialize_basic(value) for value in values])
|
||||
|
||||
|
||||
@@ -134,7 +147,7 @@ def hash_tree_root(obj: SSZValue):
|
||||
else:
|
||||
raise Exception(f"Type not supported: {type(obj)}")
|
||||
|
||||
if isinstance(obj, (List, Bytes)):
|
||||
if isinstance(obj, (List, Bytes, Bitlist)):
|
||||
return mix_in_length(merkleize_chunks(leaves, pad_to=chunk_count(obj.type())), len(obj))
|
||||
else:
|
||||
return merkleize_chunks(leaves)
|
||||
|
||||
@@ -31,7 +31,7 @@ class BasicValue(int, SSZValue, metaclass=BasicType):
|
||||
pass
|
||||
|
||||
|
||||
class Bool(BasicValue): # can't subclass bool.
|
||||
class boolean(BasicValue): # can't subclass bool.
|
||||
byte_len = 1
|
||||
|
||||
def __new__(cls, value: int): # int value, but can be any subclass of int (bool, Bit, Bool, etc...)
|
||||
@@ -48,7 +48,7 @@ class Bool(BasicValue): # can't subclass bool.
|
||||
|
||||
|
||||
# Alias for Bool
|
||||
class Bit(Bool):
|
||||
class bit(boolean):
|
||||
pass
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ class ParamsMeta(SSZType):
|
||||
return f"{self.__name__}~{self.__class__.__name__}"
|
||||
|
||||
def __repr__(self):
|
||||
return self, self.__class__
|
||||
return f"{self.__name__}~{self.__class__.__name__}"
|
||||
|
||||
def attr_from_params(self, p):
|
||||
# single key params are valid too. Wrap them in a tuple.
|
||||
@@ -280,11 +280,12 @@ class ElementsType(ParamsMeta):
|
||||
elem_type: SSZType
|
||||
length: int
|
||||
|
||||
class BitElementsType(ElementsType):
|
||||
elem_type = boolean
|
||||
|
||||
class Elements(ParamsBase, metaclass=ElementsType):
|
||||
pass
|
||||
|
||||
|
||||
class BaseList(list, Elements):
|
||||
|
||||
def __init__(self, *args):
|
||||
@@ -310,6 +311,10 @@ class BaseList(list, Elements):
|
||||
cls = self.__class__
|
||||
return f"{cls.__name__}[{cls.elem_type.__name__}, {cls.length}]({', '.join(str(v) for v in self)})"
|
||||
|
||||
def __repr__(self):
|
||||
cls = self.__class__
|
||||
return f"{cls.__name__}[{cls.elem_type.__name__}, {cls.length}]({', '.join(str(v) for v in self)})"
|
||||
|
||||
def __getitem__(self, k) -> SSZValue:
|
||||
if isinstance(k, int): # check if we are just doing a lookup, and not slicing
|
||||
if k < 0:
|
||||
@@ -337,6 +342,15 @@ class BaseList(list, Elements):
|
||||
# be explict about getting the last item, for the non-python readers, and negative-index safety
|
||||
return self[len(self) - 1]
|
||||
|
||||
class BaseBitfield(BaseList, metaclass=BitElementsType):
|
||||
elem_type = bool
|
||||
|
||||
class Bitlist(BaseBitfield):
|
||||
pass
|
||||
|
||||
class Bitvector(BaseBitfield):
|
||||
pass
|
||||
|
||||
|
||||
class List(BaseList):
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import Iterable
|
||||
from .ssz_impl import serialize, hash_tree_root
|
||||
from .ssz_typing import (
|
||||
Bit, Bool, Container, List, Vector, Bytes, BytesN,
|
||||
bit, boolean, Container, List, Vector, Bytes, BytesN,
|
||||
uint8, uint16, uint32, uint64, uint256, byte
|
||||
)
|
||||
from ..hash_function import hash as bytes_hash
|
||||
@@ -74,10 +74,10 @@ def merge(a: str, branch: Iterable[str]) -> str:
|
||||
|
||||
|
||||
test_data = [
|
||||
("bit F", Bit(False), "00", chunk("00")),
|
||||
("bit T", Bit(True), "01", chunk("01")),
|
||||
("bool F", Bool(False), "00", chunk("00")),
|
||||
("bool T", Bool(True), "01", chunk("01")),
|
||||
("bit F", bit(False), "00", chunk("00")),
|
||||
("bit T", bit(True), "01", chunk("01")),
|
||||
("boolean F", boolean(False), "00", chunk("00")),
|
||||
("boolean T", boolean(True), "01", chunk("01")),
|
||||
("uint8 00", uint8(0x00), "00", chunk("00")),
|
||||
("uint8 01", uint8(0x01), "01", chunk("01")),
|
||||
("uint8 ab", uint8(0xab), "ab", chunk("ab")),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from .ssz_typing import (
|
||||
SSZValue, SSZType, BasicValue, BasicType, Series, ElementsType,
|
||||
Elements, Bit, Bool, Container, List, Vector, Bytes, BytesN,
|
||||
Elements, bit, boolean, Container, List, Vector, Bytes, BytesN,
|
||||
byte, uint, uint8, uint16, uint32, uint64, uint128, uint256,
|
||||
Bytes32, Bytes48
|
||||
)
|
||||
@@ -22,8 +22,8 @@ def test_subclasses():
|
||||
assert issubclass(u, SSZValue)
|
||||
assert isinstance(u, SSZType)
|
||||
assert isinstance(u, BasicType)
|
||||
assert issubclass(Bool, BasicValue)
|
||||
assert isinstance(Bool, BasicType)
|
||||
assert issubclass(boolean, BasicValue)
|
||||
assert isinstance(boolean, BasicType)
|
||||
|
||||
for c in [Container, List, Vector, Bytes, BytesN]:
|
||||
assert issubclass(c, Series)
|
||||
@@ -45,16 +45,16 @@ def test_basic_instances():
|
||||
assert isinstance(v, BasicValue)
|
||||
assert isinstance(v, SSZValue)
|
||||
|
||||
assert isinstance(Bool(True), BasicValue)
|
||||
assert isinstance(Bool(False), BasicValue)
|
||||
assert isinstance(Bit(True), Bool)
|
||||
assert isinstance(Bit(False), Bool)
|
||||
assert isinstance(boolean(True), BasicValue)
|
||||
assert isinstance(boolean(False), BasicValue)
|
||||
assert isinstance(bit(True), boolean)
|
||||
assert isinstance(bit(False), boolean)
|
||||
|
||||
|
||||
def test_basic_value_bounds():
|
||||
max = {
|
||||
Bool: 2 ** 1,
|
||||
Bit: 2 ** 1,
|
||||
boolean: 2 ** 1,
|
||||
bit: 2 ** 1,
|
||||
uint8: 2 ** (8 * 1),
|
||||
byte: 2 ** (8 * 1),
|
||||
uint16: 2 ** (8 * 2),
|
||||
|
||||
Reference in New Issue
Block a user