1 from __future__ import division
4 import cStringIO as StringIO
9 from p2pool.util import bases, expiring_dict, math
11 class EarlyEnd(Exception):
14 class LateEnd(Exception):
18 # the same data can have only one unpacked representation, but multiple packed binary representations
21 # return hash(tuple(self.__dict__.items()))
23 #def __eq__(self, other):
24 # if not isinstance(other, Type):
25 # raise NotImplementedError()
26 # return self.__dict__ == other.__dict__
28 def _unpack(self, data):
29 f = StringIO.StringIO(data)
33 if f.tell() != len(data):
34 raise LateEnd('underread ' + repr((self, data)))
38 def unpack(self, data):
39 obj = self._unpack(data)
42 data2 = self._pack(obj)
44 assert self._unpack(data2) == obj
49 f = StringIO.StringIO()
58 data = self._pack(obj)
59 assert self._unpack(data) == obj
64 def pack_base58(self, obj):
65 return base58.base58_encode(self.pack(obj))
67 def unpack_base58(self, base58_data):
68 return self.unpack(base58.base58_decode(base58_data))
71 def hash160(self, obj):
72 return ShortHashType().unpack(hashlib.new('ripemd160', hashlib.sha256(self.pack(obj)).digest()).digest())
74 def hash256(self, obj):
75 return HashType().unpack(hashlib.sha256(hashlib.sha256(self.pack(obj)).digest()).digest())
77 class VarIntType(Type):
78 # redundancy doesn't matter here because bitcoin and p2pool both reencode before hashing
93 raise AssertionError()
94 length = struct.calcsize(desc)
95 data = file.read(length)
96 if len(data) != length:
98 return struct.unpack(desc, data)[0]
100 def write(self, file, item):
102 file.write(struct.pack('<B', item))
104 file.write(struct.pack('<BH', 0xfd, item))
105 elif item <= 0xffffffff:
106 file.write(struct.pack('<BI', 0xfe, item))
107 elif item <= 0xffffffffffffffff:
108 file.write(struct.pack('<BQ', 0xff, item))
110 raise ValueError('int too large for varint')
112 class VarStrType(Type):
113 _inner_size = VarIntType()
115 def read(self, file):
116 length = self._inner_size.read(file)
117 res = file.read(length)
118 if len(res) != length:
119 raise EarlyEnd('var str not long enough %r' % ((length, len(res), res),))
122 def write(self, file, item):
123 self._inner_size.write(file, len(item))
126 class FixedStrType(Type):
127 def __init__(self, length):
130 def read(self, file):
131 res = file.read(self.length)
132 if len(res) != self.length:
133 raise EarlyEnd('early EOF!')
136 def write(self, file, item):
137 if len(item) != self.length:
138 raise ValueError('incorrect length!')
141 class EnumType(Type):
142 def __init__(self, inner, values):
147 for k, v in values.iteritems():
149 raise ValueError('duplicate value in values')
152 def read(self, file):
153 return self.keys[self.inner.read(file)]
155 def write(self, file, item):
156 self.inner.write(file, self.values[item])
158 class HashType(Type):
159 def read(self, file):
160 data = file.read(256//8)
161 if len(data) != 256//8:
162 raise EarlyEnd('incorrect length!')
163 return int(data[::-1].encode('hex'), 16)
165 def write(self, file, item):
166 if not 0 <= item < 2**256:
167 raise ValueError("invalid hash value")
168 if item != 0 and item < 2**160:
169 warnings.warn("very low hash value - maybe you meant to use ShortHashType? %x" % (item,))
170 file.write(('%064x' % (item,)).decode('hex')[::-1])
172 class ShortHashType(Type):
173 def read(self, file):
174 data = file.read(160//8)
175 if len(data) != 160//8:
176 raise EarlyEnd('incorrect length!')
177 return int(data[::-1].encode('hex'), 16)
179 def write(self, file, item):
181 raise ValueError("invalid hash value")
182 file.write(('%040x' % (item,)).decode('hex')[::-1])
184 class ListType(Type):
185 _inner_size = VarIntType()
187 def __init__(self, type):
190 def read(self, file):
191 length = self._inner_size.read(file)
192 return [self.type.read(file) for i in xrange(length)]
194 def write(self, file, item):
195 self._inner_size.write(file, len(item))
197 self.type.write(file, subitem)
199 class FastLittleEndianUnsignedInteger(Type):
200 def read(self, file):
201 data = map(ord, file.read(4))
202 return data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
204 def write(self, file, item):
205 StructType("<I").write(file, item)
207 class StructType(Type):
208 def __init__(self, desc):
210 self.length = struct.calcsize(self.desc)
212 def read(self, file):
213 data = file.read(self.length)
214 if len(data) != self.length:
216 res, = struct.unpack(self.desc, data)
219 def write(self, file, item):
220 data = struct.pack(self.desc, item)
221 if struct.unpack(self.desc, data)[0] != item:
222 # special test because struct doesn't error on some overflows
223 raise ValueError("item didn't survive pack cycle (%r)" % (item,))
226 class IPV6AddressType(Type):
227 def read(self, file):
231 if data[:12] != '00000000000000000000ffff'.decode('hex'):
232 raise ValueError("ipv6 addresses not supported yet")
233 return '.'.join(str(ord(x)) for x in data[12:])
235 def write(self, file, item):
236 bits = map(int, item.split('.'))
238 raise ValueError("invalid address: %r" % (bits,))
239 data = '00000000000000000000ffff'.decode('hex') + ''.join(chr(x) for x in bits)
240 assert len(data) == 16, len(data)
243 class ComposedType(Type):
244 def __init__(self, fields):
247 def read(self, file):
249 for key, type_ in self.fields:
250 item[key] = type_.read(file)
253 def write(self, file, item):
254 for key, type_ in self.fields:
255 type_.write(file, item[key])
257 class ChecksummedType(Type):
258 def __init__(self, inner):
261 def read(self, file):
262 obj = self.inner.read(file)
263 data = self.inner.pack(obj)
265 if file.read(4) != hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4]:
266 raise ValueError("invalid checksum")
270 def write(self, file, item):
271 data = self.inner.pack(item)
273 file.write(hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4])
275 class FloatingIntegerType(Type):
276 # redundancy doesn't matter here because bitcoin checks binary bits against its own computed bits
277 # so it will always be encoded 'normally' in blocks (they way bitcoin does it)
278 _inner = StructType("<I")
279 _inner = FastLittleEndianUnsignedInteger()
281 def read(self, file):
282 bits = self._inner.read(file)
283 target = self._bits_to_target(bits)
285 if self._target_to_bits(target) != bits:
286 raise ValueError("bits in non-canonical form")
289 def write(self, file, item):
290 self._inner.write(file, self._target_to_bits(item))
292 def truncate_to(self, x):
293 return self._bits_to_target(self._target_to_bits(x, _check=False))
295 def _bits_to_target(self, bits2):
296 target = math.shift_left(bits2 & 0x00ffffff, 8 * ((bits2 >> 24) - 3))
297 assert target == self._bits_to_target1(struct.pack("<I", bits2))
298 assert self._target_to_bits(target, _check=False) == bits2
301 def _bits_to_target1(self, bits):
303 length = ord(bits[0])
304 return bases.string_to_natural((bits[1:] + "\0"*length)[:length])
306 def _target_to_bits(self, target, _check=True):
307 n = bases.natural_to_string(target)
308 if n and ord(n[0]) >= 128:
310 bits2 = (chr(len(n)) + (n + 3*chr(0))[:3])[::-1]
311 bits = struct.unpack("<I", bits2)[0]
313 if self._bits_to_target(bits) != target:
314 raise ValueError(repr((target, self._bits_to_target(bits, _check=False))))
317 class PossiblyNone(Type):
318 def __init__(self, none_value, inner):
319 self.none_value = none_value
322 def read(self, file):
323 value = self.inner.read(file)
324 return None if value == self.none_value else value
326 def write(self, file, item):
327 if item == self.none_value:
328 raise ValueError("none_value used")
329 self.inner.write(file, self.none_value if item is None else item)
331 address_type = ComposedType([
332 ('services', StructType('<Q')),
333 ('address', IPV6AddressType()),
334 ('port', StructType('>H')),
337 tx_type = ComposedType([
338 ('version', StructType('<I')),
339 ('tx_ins', ListType(ComposedType([
340 ('previous_output', PossiblyNone(dict(hash=0, index=2**32 - 1), ComposedType([
341 ('hash', HashType()),
342 ('index', StructType('<I')),
344 ('script', VarStrType()),
345 ('sequence', PossiblyNone(2**32 - 1, StructType('<I'))),
347 ('tx_outs', ListType(ComposedType([
348 ('value', StructType('<Q')),
349 ('script', VarStrType()),
351 ('lock_time', StructType('<I')),
354 block_header_type = ComposedType([
355 ('version', StructType('<I')),
356 ('previous_block', PossiblyNone(0, HashType())),
357 ('merkle_root', HashType()),
358 ('timestamp', StructType('<I')),
359 ('target', FloatingIntegerType()),
360 ('nonce', StructType('<I')),
363 block_type = ComposedType([
364 ('header', block_header_type),
365 ('txs', ListType(tx_type)),
369 merkle_record_type = ComposedType([
370 ('left', HashType()),
371 ('right', HashType()),
374 def merkle_hash(tx_list):
377 hash_list = map(tx_type.hash256, tx_list)
378 while len(hash_list) > 1:
379 hash_list = [merkle_record_type.hash256(dict(left=left, right=left if right is None else right))
380 for left, right in zip(hash_list[::2], hash_list[1::2] + [None])]
383 def target_to_average_attempts(target):
384 return 2**256//(target + 1)
388 human_address_type = ChecksummedType(ComposedType([
389 ('version', StructType("<B")),
390 ('pubkey_hash', ShortHashType()),
393 pubkey_type = FixedStrType(65)
395 def pubkey_hash_to_address(pubkey_hash, net):
396 return human_address_type.pack_base58(dict(version=net.BITCOIN_ADDRESS_VERSION, pubkey_hash=pubkey_hash))
398 def pubkey_to_address(pubkey, net):
399 return pubkey_hash_to_address(pubkey_type.hash160(pubkey), net)
401 def address_to_pubkey_hash(address, net):
402 x = human_address_type.unpack_base58(address)
403 if x['version'] != net.BITCOIN_ADDRESS_VERSION:
404 raise ValueError('address not for this net!')
405 return x['pubkey_hash']
407 # network definitions
409 class Mainnet(object):
410 BITCOIN_P2P_PREFIX = 'f9beb4d9'.decode('hex')
411 BITCOIN_P2P_PORT = 8333
412 BITCOIN_ADDRESS_VERSION = 0
414 class Testnet(object):
415 BITCOIN_P2P_PREFIX = 'fabfb5da'.decode('hex')
416 BITCOIN_P2P_PORT = 18333
417 BITCOIN_ADDRESS_VERSION = 111