from binascii import unhexlify, hexlify from typing import TypeVar, Sequence, Optional T = TypeVar('T') class ReadOnlyList(Sequence[T]): def __init__(self, lst): self.lst = lst def __getitem__(self, key): return self.lst[key] def __len__(self) -> int: return len(self.lst) def subclass_tuple(name, base): return type(name, (base,), {'__slots__': ()}) class cachedproperty: def __init__(self, f): self.f = f def __get__(self, obj, objtype): obj = obj or objtype value = self.f(obj) setattr(obj, self.f.__name__, value) return value def bytes_to_int(be_bytes): """ Interprets a big-endian sequence of bytes as an integer. """ return int(hexlify(be_bytes), 16) def int_to_bytes(value): """ Converts an integer to a big-endian sequence of bytes. """ length = (value.bit_length() + 7) // 8 s = '%x' % value return unhexlify(('0' * (len(s) % 2) + s).zfill(length * 2)) class ArithUint256: # https://github.com/bitcoin/bitcoin/blob/master/src/arith_uint256.cpp __slots__ = '_value', '_compact' def __init__(self, value: int) -> None: self._value = value self._compact: Optional[int] = None @classmethod def from_compact(cls, compact) -> 'ArithUint256': size = compact >> 24 word = compact & 0x007fffff if size <= 3: return cls(word >> 8 * (3 - size)) else: return cls(word << 8 * (size - 3)) @property def value(self) -> int: return self._value @property def compact(self) -> int: if self._compact is None: self._compact = self._calculate_compact() return self._compact @property def negative(self) -> int: return self._calculate_compact(negative=True) @property def bits(self) -> int: """ Returns the position of the highest bit set plus one. """ bits = bin(self._value)[2:] for i, d in enumerate(bits): if d: return (len(bits) - i) + 1 return 0 @property def low64(self) -> int: return self._value & 0xffffffffffffffff def _calculate_compact(self, negative=False) -> int: size = (self.bits + 7) // 8 if size <= 3: compact = self.low64 << 8 * (3 - size) else: compact = ArithUint256(self._value >> 8 * (size - 3)).low64 # The 0x00800000 bit denotes the sign. # Thus, if it is already set, divide the mantissa by 256 and increase the exponent. if compact & 0x00800000: compact >>= 8 size += 1 assert (compact & ~0x007fffff) == 0 assert size < 256 compact |= size << 24 if negative and compact & 0x007fffff: compact |= 0x00800000 return compact def __mul__(self, x): # Take the mod because we are limited to an unsigned 256 bit number return ArithUint256((self._value * x) % 2 ** 256) def __truediv__(self, x): return ArithUint256(int(self._value / x)) def __gt__(self, other): return self._value > other def __lt__(self, other): return self._value < other