lbry-sdk/lbry/wallet/util.py

130 lines
3.3 KiB
Python
Raw Normal View History

2018-11-19 04:54:00 +01:00
import re
2018-08-16 06:56:46 +02:00
from typing import TypeVar, Sequence, Optional
2020-01-03 04:18:49 +01:00
from .constants import COIN
2018-11-19 04:54:00 +01:00
def coins_to_satoshis(coins):
if not isinstance(coins, str):
raise ValueError("{coins} must be a string")
result = re.search(r'^(\d{1,10})\.(\d{1,8})$', coins)
if result is not None:
whole, fractional = result.groups()
return int(whole+fractional.ljust(8, "0"))
raise ValueError("'{lbc}' is not a valid coin decimal")
def satoshis_to_coins(satoshis):
coins = '{:.8f}'.format(satoshis / COIN).rstrip('0')
if coins.endswith('.'):
return coins+'0'
else:
return coins
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
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