from __future__ import division import hashlib import struct from . import base58 from p2pool.util import bases, math, expiring_dict, memoize, slush import p2pool class EarlyEnd(Exception): pass class LateEnd(Exception): pass def read((data, pos), length): data2 = data[pos:pos + length] if len(data2) != length: raise EarlyEnd() return data2, (data, pos + length) def size((data, pos)): return len(data) - pos class Type(object): # the same data can have only one unpacked representation, but multiple packed binary representations def __hash__(self): rval = getattr(self, '_hash', None) if rval is None: try: rval = self._hash = hash((type(self), frozenset(self.__dict__.items()))) except: print self.__dict__ raise return rval def __eq__(self, other): return type(other) is type(self) and other.__dict__ == self.__dict__ def __ne__(self, other): return not (self == other) def _unpack(self, data): obj, (data2, pos) = self.read((data, 0)) assert data2 is data if pos != len(data): raise LateEnd() return obj def _pack(self, obj): f = self.write(None, obj) res = [] while f is not None: res.append(f[1]) f = f[0] res.reverse() return ''.join(res) def unpack(self, data): obj = self._unpack(data) if p2pool.DEBUG: data2 = self._pack(obj) if data2 != data: if self._unpack(data2) != obj: raise AssertionError() return obj def pack2(self, obj): data = self._pack(obj) if p2pool.DEBUG: if self._unpack(data) != obj: raise AssertionError((self._unpack(data), obj)) return data _backing = expiring_dict.ExpiringDict(100) pack2 = memoize.memoize_with_backing(_backing, [unpack])(pack2) unpack = memoize.memoize_with_backing(_backing)(unpack) # doesn't have an inverse def pack(self, obj): return self.pack2(slush.immutify(obj)) def pack_base58(self, obj): return base58.base58_encode(self.pack(obj)) def unpack_base58(self, base58_data): return self.unpack(base58.base58_decode(base58_data)) def hash160(self, obj): return ShortHashType().unpack(hashlib.new('ripemd160', hashlib.sha256(self.pack(obj)).digest()).digest()) def hash256(self, obj): return HashType().unpack(hashlib.sha256(hashlib.sha256(self.pack(obj)).digest()).digest()) def scrypt(self, obj): import ltc_scrypt return HashType().unpack(ltc_scrypt.getPoWHash(self.pack(obj))) class VarIntType(Type): # redundancy doesn't matter here because bitcoin and p2pool both reencode before hashing def read(self, file): data, file = read(file, 1) first = ord(data) if first < 0xfd: return first, file elif first == 0xfd: desc, length = '= 128: n = '\x00' + n bits2 = (chr(len(n)) + (n + 3*chr(0))[:3])[::-1] bits = struct.unpack('> 24) - 3)) def __hash__(self): return hash(self._value) def __cmp__(self, other): if isinstance(other, FloatingInteger): return cmp(self._value, other._value) elif isinstance(other, (int, long)): return cmp(self._value, other) else: raise NotImplementedError(other) def __int__(self): return self._value def __repr__(self): return 'FloatingInteger(bits=%s, value=%s)' % (hex(self._bits), hex(self._value)) def __add__(self, other): if isinstance(other, (int, long)): return self._value + other raise NotImplementedError() __radd__ = __add__ def __mul__(self, other): if isinstance(other, (int, long)): return self._value * other raise NotImplementedError() __rmul__ = __mul__ def __truediv__(self, other): if isinstance(other, (int, long)): return self._value / other raise NotImplementedError() def __floordiv__(self, other): if isinstance(other, (int, long)): return self._value // other raise NotImplementedError() __div__ = __truediv__ def __rtruediv__(self, other): if isinstance(other, (int, long)): return other / self._value raise NotImplementedError() def __rfloordiv__(self, other): if isinstance(other, (int, long)): return other // self._value raise NotImplementedError() __rdiv__ = __rtruediv__ class FloatingIntegerType(Type): _inner = StructType('H')), ]) tx_type = ComposedType([ ('version', StructType(' 1: hash_list = [merkle_record_type.hash256(dict(left=left, right=left if right is None else right)) for left, right in zip(hash_list[::2], hash_list[1::2] + [None])] return hash_list[0] def calculate_merkle_branch(hashes, index): # XXX optimize this hash_list = [(h, i == index, []) for i, h in enumerate(hashes)] while len(hash_list) > 1: hash_list = [ ( merkle_record_type.hash256(dict(left=left, right=right)), left_f or right_f, (left_l if left_f else right_l) + [dict(side=1, hash=right) if left_f else dict(side=0, hash=left)], ) for (left, left_f, left_l), (right, right_f, right_l) in zip(hash_list[::2], hash_list[1::2] + [hash_list[::2][-1]]) ] res = [x['hash'] for x in hash_list[0][2]] assert hash_list[0][1] assert check_merkle_branch(hashes[index], index, res) == hash_list[0][0] assert index == sum(k*2**i for i, k in enumerate([1-x['side'] for x in hash_list[0][2]])) return res def check_merkle_branch(tip_hash, index, merkle_branch): return reduce(lambda c, (i, h): merkle_record_type.hash256( dict(left=h, right=c) if 2**i & index else dict(left=c, right=h) ), enumerate(merkle_branch), tip_hash) def target_to_average_attempts(target): return 2**256//(target + 1) def target_to_difficulty(target): return (0xffff0000 * 2**(256-64) + 1)/(target + 1) # tx def tx_get_sigop_count(tx): return sum(script.get_sigop_count(txin['script']) for txin in tx['tx_ins']) + sum(script.get_sigop_count(txout['script']) for txout in tx['tx_outs']) # human addresses human_address_type = ChecksummedType(ComposedType([ ('version', StructType('