lbry-sdk/torba/client/util.py

123 lines
3.2 KiB
Python
Raw Normal View History

2018-05-25 08:03:25 +02:00
from binascii import unhexlify, hexlify
2018-08-16 06:56:46 +02:00
from typing import TypeVar, Sequence, Optional
2018-05-25 08:03:25 +02:00
T = TypeVar('T')
class ReadOnlyList(Sequence[T]):
2018-05-25 08:03:25 +02:00
def __init__(self, lst):
self.lst = lst
def __getitem__(self, key):
2018-05-25 08:03:25 +02:00
return self.lst[key]
def __len__(self) -> int:
2018-05-25 08:03:25 +02:00
return len(self.lst)
def subclass_tuple(name, base):
return type(name, (base,), {'__slots__': ()})
class cachedproperty:
2018-05-25 08:03:25 +02:00
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype):
obj = obj or objtype
2018-05-25 08:03:25 +02:00
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))
2018-05-25 08:03:25 +02:00
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
2018-08-16 06:56:46 +02:00
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. """
2018-08-16 06:56:46 +02:00
bits = bin(self._value)[2:]
for i, d in enumerate(bits):
if d:
2018-08-16 06:56:46 +02:00
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