예제 #1
0
def test_mixed_uint_rshifts():
    assert uint64(0xff00_0000_0000_0000) >> uint8(8 * 7) == uint64(0xff)
    assert uint16(0xff) >> uint8(8) == uint16(0)
    assert uint16(0xff) >> uint8(6) == uint16(3)
    assert uint256(1 << 255) >> uint8(255) == uint256(1)
    assert uint256(1 << 255) >> uint16(255) == uint256(1)
    assert uint8(42) << uint64(3) == uint8((42 << 3) & 0xff)
예제 #2
0
 def deserialize(cls: Type[V], stream: BinaryIO, scope: int) -> V:
     if scope < 1:
         raise Exception("cannot have empty scope for bitlist, need at least a delimiting bit")
     if scope > cls.max_byte_length():
         raise Exception(f"scope is too large: {scope}, max bitlist byte length is: {cls.max_byte_length()}")
     chunks: PyList[Node] = []
     bytelen = scope - 1  # excluding the last byte (which contains the delimiting bit)
     while scope > 32:
         chunks.append(RootNode(Root(stream.read(32))))
         scope -= 32
     # scope is [1, 32] here
     last_chunk_part = stream.read(scope)
     last_byte = int(last_chunk_part[scope-1])
     if last_byte == 0:
         raise Exception("last byte must not be 0: bitlist requires delimiting bit")
     last_byte_bitlen = last_byte.bit_length() - 1  # excluding the delimiting bit
     bitlen = bytelen * 8 + last_byte_bitlen
     if bitlen % 256 != 0:
         last_chunk = last_chunk_part[:scope-1] +\
                      (last_byte ^ (1 << last_byte_bitlen)).to_bytes(length=1, byteorder='little')
         last_chunk += b"\x00" * (32 - len(last_chunk))
         chunks.append(RootNode(Root(last_chunk)))
     if bitlen > cls.limit():
         raise Exception(f"bitlist too long: {bitlen}, delimiting bit is over limit ({cls.limit()})")
     contents = subtree_fill_to_contents(chunks, cls.contents_depth())
     backing = PairNode(contents, uint256(bitlen).get_backing())
     return cast(Bitlist, cls.view_from_backing(backing))
예제 #3
0
    def pop(self):
        ll = self.length()
        if ll == 0:
            raise Exception("list is empty, cannot pop")
        i = ll - 1
        chunk_i = i // 256
        target: Gindex = to_gindex(chunk_i, self.__class__.tree_depth())
        if i & 0xff == 0:
            set_last = self.get_backing().setter(target)
            next_backing = set_last(zero_node(0))
        else:
            set_last = self.get_backing().setter(target)
            chunk = self.get_backing().getter(target)
            next_backing = set_last(_new_chunk_with_bit(chunk, ll & 0xff, boolean(False)))

        # if possible, summarize
        can_summarize = (target & 1) == 0
        if can_summarize:
            # summarize to the highest node possible.
            # I.e. the resulting target must be a right-hand, unless it's the only content node.
            while (target & 1) == 0 and target != 0b10:
                target >>= 1
            summary_fn = next_backing.summarize_into(target)
            next_backing = summary_fn()

        set_length = next_backing.rebind_right
        new_length = uint256(ll - 1).get_backing()
        next_backing = set_length(new_length)
        self.set_backing(next_backing)
예제 #4
0
def test_mixed_uint_lshifts():
    assert uint64(0xff) << uint8(8 * 7) == uint64(0xff00_0000_0000_0000)
    assert uint16(0xff) << uint8(8 * 7) == uint16(0)
    assert uint256(1) << uint8(255) == uint256(1 << 255)
    assert uint256(1) << uint16(255) == uint256(1 << 255)
    assert uint256(1) << uint16(256) == uint256(0)
    assert uint8(42) >> uint64(3) == uint8(42 >> 3)
예제 #5
0
 def __new__(cls, *args, **kwargs):
     vals = list(args)
     if len(vals) > 0:
         if len(vals) == 1 and isinstance(vals[0], (GeneratorType, list, tuple)):
             vals = list(vals[0])
         limit = cls.limit()
         if len(vals) > limit:
             raise Exception(f"too many bitlist inputs: {len(vals)}, limit is: {limit}")
         input_bits = list(map(bool, vals))
         input_nodes = pack_bits_to_chunks(input_bits)
         contents = subtree_fill_to_contents(input_nodes, cls.contents_depth())
         kwargs['backing'] = PairNode(contents, uint256(len(input_bits)).get_backing())
     return super().__new__(cls, **kwargs)
예제 #6
0
    def pop(self):
        ll = self.length()
        if ll == 0:
            raise Exception("list is empty, cannot pop")
        i = ll - 1
        target: Gindex
        can_summarize: bool
        if self.__class__.is_packed():
            next_backing = self.get_backing()
            elem_type: Type[View] = self.__class__.element_cls()
            if isinstance(elem_type, BasicTypeDef):
                elems_per_chunk = 32 // elem_type.type_byte_length()
                chunk_i = i // elems_per_chunk
                target = to_gindex(chunk_i, self.__class__.tree_depth())
                if i % elems_per_chunk == 0:
                    chunk = zero_node(0)
                else:
                    chunk = next_backing.getter(target)
                set_last = next_backing.setter(target)
                chunk = cast(BasicView,
                             elem_type.default(None)).backing_from_base(
                                 chunk, i % elems_per_chunk)
                next_backing = set_last(chunk)

                can_summarize = (target & 1) == 0 and i % elems_per_chunk == 0
            else:
                raise Exception(
                    "cannot pop a packed element that is not a basic type")
        else:
            target = to_gindex(i, self.__class__.tree_depth())
            set_last = self.get_backing().setter(target)
            next_backing = set_last(zero_node(0))
            can_summarize = (target & 1) == 0

        # if possible, summarize
        if can_summarize:
            # summarize to the highest node possible.
            # I.e. the resulting target must be a right-hand, unless it's the only content node.
            while (target & 1) == 0 and target != 0b10:
                target >>= 1
            summary_fn = next_backing.summarize_into(target)
            next_backing = summary_fn()

        set_length = next_backing.rebind_right
        new_length = uint256(ll - 1).get_backing()
        next_backing = set_length(new_length)
        self.set_backing(next_backing)
예제 #7
0
 def append(self, v: boolean):
     ll = self.length()
     if ll >= self.__class__.limit():
         raise Exception("list is maximum capacity, cannot append")
     i = ll
     chunk_i = i // 256
     target: Gindex = to_gindex(chunk_i, self.__class__.tree_depth())
     if i & 0xff == 0:
         set_last = self.get_backing().setter(target, expand=True)
         next_backing = set_last(_new_chunk_with_bit(zero_node(0), 0, v))
     else:
         set_last = self.get_backing().setter(target)
         chunk = self.get_backing().getter(target)
         next_backing = set_last(_new_chunk_with_bit(chunk, i & 0xff, v))
     set_length = next_backing.rebind_right
     new_length = uint256(ll + 1).get_backing()
     next_backing = set_length(new_length)
     self.set_backing(next_backing)
예제 #8
0
    def __new__(cls,
                *args,
                backing: Optional[Node] = None,
                hook: Optional[ViewHook] = None,
                **kwargs):
        if backing is not None:
            if len(args) != 0:
                raise Exception(
                    "cannot have both a backing and elements to init List")
            return super().__new__(cls, backing=backing, hook=hook, **kwargs)

        elem_cls = cls.element_cls()
        vals = list(args)
        if len(vals) == 1:
            val = vals[0]
            if isinstance(val, (GeneratorType, list, tuple)):
                vals = list(val)
            if issubclass(elem_cls, uint8):
                if isinstance(val, bytes):
                    vals = list(val)
                if isinstance(val, str):
                    if val[:2] == '0x':
                        val = val[2:]
                    vals = list(bytes.fromhex(val))
        if len(vals) > 0:
            limit = cls.limit()
            if len(vals) > limit:
                raise Exception(
                    f"too many list inputs: {len(vals)}, limit is: {limit}")
            input_views = []
            for el in vals:
                if isinstance(el, View):
                    input_views.append(el)
                else:
                    input_views.append(elem_cls.coerce_view(el))
            input_nodes = cls.views_into_chunks(input_views)
            contents = subtree_fill_to_contents(input_nodes,
                                                cls.contents_depth())
            backing = PairNode(contents,
                               uint256(len(input_views)).get_backing())
        return super().__new__(cls, backing=backing, hook=hook, **kwargs)
예제 #9
0
    def append(self, v: View):
        ll = self.length()
        if ll >= self.__class__.limit():
            raise Exception("list is maximum capacity, cannot append")
        i = ll
        elem_type: Type[View] = self.__class__.element_cls()
        if not isinstance(v, elem_type):
            v = elem_type.coerce_view(v)
        if self.__class__.is_packed():
            next_backing = self.get_backing()
            if isinstance(elem_type, BasicTypeDef):
                if not isinstance(v, BasicView):
                    raise Exception("input element is not a basic view")
                basic_v: BasicView = v
                elems_per_chunk = 32 // elem_type.type_byte_length()
                chunk_i = i // elems_per_chunk
                target: Gindex = to_gindex(chunk_i,
                                           self.__class__.tree_depth())
                if i % elems_per_chunk == 0:
                    set_last = next_backing.setter(target, expand=True)
                    chunk = zero_node(0)
                else:
                    set_last = next_backing.setter(target)
                    chunk = next_backing.getter(target)
                chunk = basic_v.backing_from_base(chunk, i % elems_per_chunk)
                next_backing = set_last(chunk)
            else:
                raise Exception(
                    "cannot append a packed element that is not a basic type")
        else:
            target: Gindex = to_gindex(i, self.__class__.tree_depth())
            set_last = self.get_backing().setter(target, expand=True)
            next_backing = set_last(v.get_backing())

        set_length = next_backing.rebind_right
        new_length = uint256(ll + 1).get_backing()
        next_backing = set_length(new_length)
        self.set_backing(next_backing)
예제 #10
0
 def get_backing(self) -> Node:
     return PairNode(
         subtree_fill_to_contents(pack_bytes_to_chunks(self),
                                  self.__class__.contents_depth()),
         uint256(len(self)).get_backing())
예제 #11
0
     List[uint16, 32](uint16(0xaabb), uint16(0xc0ad), uint16(0xeeff)),
     "bbaaadc0ffee",
     h(h(chunk("bbaaadc0ffee"), chunk("")),
       chunk("03000000")),  # max length: 32 * 2 = 64 bytes = 2 chunks
     [0xaabb, 0xc0ad, 0xeeff]),
 (
     "uint32 list",
     List[uint32, 128],
     List[uint32, 128](uint32(0xaabb), uint32(0xc0ad), uint32(0xeeff)),
     "bbaa0000adc00000ffee0000",
     # max length: 128 * 4 = 512 bytes = 16 chunks
     h(merge(chunk("bbaa0000adc00000ffee0000"), zero_hashes[0:4]),
       chunk("03")),
     [0xaabb, 0xc0ad, 0xeeff]  # still the same, no padding, just literals
 ),
 ("uint256 list", List[uint256, 32], List[uint256, 32](uint256(0xaabb),
                                                       uint256(0xc0ad),
                                                       uint256(0xeeff)),
  "bbaa000000000000000000000000000000000000000000000000000000000000"
  "adc0000000000000000000000000000000000000000000000000000000000000"
  "ffee000000000000000000000000000000000000000000000000000000000000",
  h(
      merge(h(h(chunk("bbaa"), chunk("adc0")), h(chunk("ffee"), chunk(""))),
            zero_hashes[2:5]), chunk("03")),
  [
      "0xbbaa000000000000000000000000000000000000000000000000000000000000",
      "0xadc0000000000000000000000000000000000000000000000000000000000000",
      "0xffee000000000000000000000000000000000000000000000000000000000000",
  ]),
 (
     "uint256 list long",