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 = None @classmethod def enable_caching(cls): assert cls._backing is None cls._backing = expiring_dict.ExpiringDict(100) cls._pre_pack2 = cls.pack2 cls.pack2 = memoize.memoize_with_backing(cls._backing, [cls.unpack])(cls.pack2) cls._pre_unpack = cls.unpack cls.unpack = memoize.memoize_with_backing(cls._backing)(cls.unpack) # doesn't have an inverse @classmethod def disable_caching(cls): assert cls._backing is not None cls._backing.stop() cls._backing = None cls.pack2 = cls._pre_pack2 del cls._pre_pack2 cls.unpack = cls._pre_unpack del cls._pre_unpack def pack(self, obj): return self.pack2(slush.immutify(obj)) def pack_base58(self, obj): return base58.encode(self.pack(obj)) def unpack_base58(self, base58_data): return self.unpack(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)) return res def __hash__(self): return hash(self.bits) def __eq__(self, other): return self.bits == other.bits def __ne__(self, other): return not (self == other) def __cmp__(self, other): assert False def __repr__(self): return 'FloatingInteger(bits=%s, target=%s)' % (hex(self.bits), hex(self.target)) 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('