working ... sorry for bad log messages\!
[p2pool.git] / p2pool / bitcoin / data.py
1 from __future__ import division
2
3 import struct
4 import StringIO
5 import hashlib
6 import warnings
7
8 from . import base58
9 from p2pool.util import bases, expiring_dict, math
10
11 class EarlyEnd(Exception):
12     pass
13
14 class LateEnd(Exception):
15     pass
16
17 class Type(object):
18     # the same data can have only one unpacked representation, but multiple packed binary representations
19     
20     #def __hash__(self):
21     #    return hash(tuple(self.__dict__.items()))
22     
23     #def __eq__(self, other):
24     #    if not isinstance(other, Type):
25     #        raise NotImplementedError()
26     #    return self.__dict__ == other.__dict__
27     
28     def _unpack(self, data):
29         f = StringIO.StringIO(data)
30         
31         obj = self.read(f)
32         
33         if f.tell() != len(data):
34             raise LateEnd('underread ' + repr((self, data)))
35         
36         return obj
37     
38     def unpack(self, data):
39         obj = self._unpack(data)
40         
41         data2 = self._pack(obj)
42         if data2 != data:
43             assert self._unpack(data2) == obj
44         
45         return obj
46     
47     def _pack(self, obj):
48         f = StringIO.StringIO()
49         
50         self.write(f, obj)
51         
52         data = f.getvalue()
53         
54         return data
55     
56     def pack(self, obj):
57         data = self._pack(obj)
58         assert self._unpack(data) == obj
59                 
60         return data
61     
62     
63     def pack_base58(self, obj):
64         return base58.base58_encode(self.pack(obj))
65     
66     def unpack_base58(self, base58_data):
67         return self.unpack(base58.base58_decode(base58_data))
68         
69     
70     def hash160(self, obj):
71         return ShortHashType().unpack(hashlib.new('ripemd160', hashlib.sha256(self.pack(obj)).digest()).digest())
72     
73     def hash256(self, obj):
74         return HashType().unpack(hashlib.sha256(hashlib.sha256(self.pack(obj)).digest()).digest())
75
76 class VarIntType(Type):
77     def read(self, file):
78         data = file.read(1)
79         if len(data) != 1:
80             raise EarlyEnd()
81         first, = struct.unpack('<B', data)
82         if first == 0xff: desc = '<Q'
83         elif first == 0xfe: desc = '<I'
84         elif first == 0xfd: desc = '<H'
85         else: return first
86         length = struct.calcsize(desc)
87         data = file.read(length)
88         if len(data) != length:
89             raise EarlyEnd()
90         return struct.unpack(desc, data)[0]
91     
92     def write(self, file, item):
93         if item < 0xfd:
94             file.write(struct.pack('<B', item))
95         elif item <= 0xffff:
96             file.write(struct.pack('<BH', 0xfd, item))
97         elif item <= 0xffffffff:
98             file.write(struct.pack('<BI', 0xfe, item))
99         elif item <= 0xffffffffffffffff:
100             file.write(struct.pack('<BQ', 0xff, item))
101         else:
102             raise ValueError('int too large for varint')
103
104 class VarStrType(Type):
105     def read(self, file):
106         length = VarIntType().read(file)
107         res = file.read(length)
108         if len(res) != length:
109             raise EarlyEnd('var str not long enough %r' % ((length, len(res), res),))
110         return res
111     
112     def write(self, file, item):
113         VarIntType().write(file, len(item))
114         file.write(item)
115
116 class FixedStrType(Type):
117     def __init__(self, length):
118         self.length = length
119     
120     def read(self, file):
121         res = file.read(self.length)
122         if len(res) != self.length:
123             raise EarlyEnd('early EOF!')
124         return res
125     
126     def write(self, file, item):
127         if len(item) != self.length:
128             raise ValueError('incorrect length!')
129         file.write(item)
130
131 class EnumType(Type):
132     def __init__(self, inner, values):
133         self.inner = inner
134         self.values = values
135         
136         self.keys = {}
137         for k, v in values.iteritems():
138             if v in self.keys:
139                 raise ValueError('duplicate value in values')
140             self.keys[v] = k
141     
142     def read(self, file):
143         return self.keys[self.inner.read(file)]
144     
145     def write(self, file, item):
146         self.inner.write(file, self.values[item])
147
148 class HashType(Type):
149     def read(self, file):
150         data = file.read(256//8)
151         if len(data) != 256//8:
152             raise EarlyEnd('incorrect length!')
153         return int(data[::-1].encode('hex'), 16)
154     
155     def write(self, file, item):
156         if item >= 2**256:
157             raise ValueError("invalid hash value")
158         if item != 0 and item < 2**160:
159             warnings.warn("very low hash value - maybe you meant to use ShortHashType?")
160         file.write(('%064x' % (item,)).decode('hex')[::-1])
161
162 class ShortHashType(Type):
163     def read(self, file):
164         data = file.read(160//8)
165         if len(data) != 160//8:
166             raise EarlyEnd('incorrect length!')
167         return int(data[::-1].encode('hex'), 16)
168     
169     def write(self, file, item):
170         if item >= 2**160:
171             raise ValueError("invalid hash value")
172         file.write(('%040x' % (item,)).decode('hex')[::-1])
173
174 class ListType(Type):
175     def __init__(self, type):
176         self.type = type
177     
178     def read(self, file):
179         length = VarIntType().read(file)
180         return [self.type.read(file) for i in xrange(length)]
181     
182     def write(self, file, item):
183         VarIntType().write(file, len(item))
184         for subitem in item:
185             self.type.write(file, subitem)
186
187 class StructType(Type):
188     def __init__(self, desc):
189         self.desc = desc
190         self.length = struct.calcsize(self.desc)
191     
192     def read(self, file):
193         data = file.read(self.length)
194         if len(data) != self.length:
195             raise EarlyEnd()
196         res, = struct.unpack(self.desc, data)
197         return res
198     
199     def write(self, file, item):
200         data = struct.pack(self.desc, item)
201         if struct.unpack(self.desc, data)[0] != item:
202             # special test because struct doesn't error on some overflows
203             raise ValueError("item didn't survive pack cycle (%r)" % (item,))
204         file.write(data)
205
206 class IPV6AddressType(Type):
207     def read(self, file):
208         data = file.read(16)
209         if len(data) != 16:
210             raise EarlyEnd()
211         if data[:12] != '00000000000000000000ffff'.decode('hex'):
212             raise ValueError("ipv6 addresses not supported yet")
213         return '.'.join(str(ord(x)) for x in data[12:])
214     
215     def write(self, file, item):
216         bits = map(int, item.split('.'))
217         if len(bits) != 4:
218             raise ValueError("invalid address: %r" % (bits,))
219         data = '00000000000000000000ffff'.decode('hex') + ''.join(chr(x) for x in bits)
220         assert len(data) == 16, len(data)
221         file.write(data)
222
223 class ComposedType(Type):
224     def __init__(self, fields):
225         self.fields = fields
226     
227     def read(self, file):
228         item = {}
229         for key, type_ in self.fields:
230             item[key] = type_.read(file)
231         return item
232     
233     def write(self, file, item):
234         for key, type_ in self.fields:
235             type_.write(file, item[key])
236
237 class ChecksummedType(Type):
238     def __init__(self, inner):
239         self.inner = inner
240     
241     def read(self, file):
242         obj = self.inner.read(file)
243         data = self.inner.pack(obj)
244         
245         if file.read(4) != hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4]:
246             raise ValueError("invalid checksum")
247         
248         return obj
249     
250     def write(self, file, item):
251         data = self.inner.pack(item)
252         file.write(data)
253         file.write(hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4])
254
255 class FloatingIntegerType(Type):
256     def read(self, file):
257         data = FixedStrType(4).read(file)
258         target = self._bits_to_target(data)
259         if self._target_to_bits(target) != data:
260             raise ValueError("bits in non-canonical form")
261         return target
262     
263     def write(self, file, item):
264         FixedStrType(4).write(file, self._target_to_bits(item))
265     
266     def truncate_to(self, x):
267         return self._bits_to_target(self._target_to_bits(x, _check=False))
268         
269     def _bits_to_target(self, bits, _check=True):
270         assert len(bits) == 4, repr(bits)
271         target1 = self._bits_to_target1(bits)
272         target2 = self._bits_to_target2(bits)
273         if target1 != target2:
274             raise ValueError()
275         if _check:
276             if self._target_to_bits(target1, _check=False) != bits:
277                 raise ValueError()
278         return target1
279     
280     def _bits_to_target1(self, bits):
281         bits = bits[::-1]
282         length = ord(bits[0])
283         return bases.string_to_natural((bits[1:] + "\0"*length)[:length])
284
285     def _bits_to_target2(self, bits):
286         bits = struct.unpack("<I", bits)[0]
287         return math.shift_left(bits & 0x00ffffff, 8 * ((bits >> 24) - 3))
288
289     def _target_to_bits(self, target, _check=True):
290         n = bases.natural_to_string(target)
291         if n and ord(n[0]) >= 128:
292             n = "\x00" + n
293         bits = (chr(len(n)) + (n + 3*chr(0))[:3])[::-1]
294         if _check:
295             if self._bits_to_target(bits, _check=False) != target:
296                 raise ValueError(repr((target, self._bits_to_target(bits, _check=False))))
297         return bits
298
299 class PossiblyNone(Type):
300     def __init__(self, none_value, inner):
301         self.none_value = none_value
302         self.inner = inner
303     
304     def read(self, file):
305         value = self.inner.read(file)
306         return None if value == self.none_value else value
307     
308     def write(self, file, item):
309         if item == self.none_value:
310             raise ValueError("none_value used")
311         self.inner.write(file, self.none_value if item is None else item)
312
313 address_type = ComposedType([
314     ('services', StructType('<Q')),
315     ('address', IPV6AddressType()),
316     ('port', StructType('>H')),
317 ])
318
319 tx_type = ComposedType([
320     ('version', StructType('<I')),
321     ('tx_ins', ListType(ComposedType([
322         ('previous_output', PossiblyNone(dict(hash=0, index=2**32 - 1), ComposedType([
323             ('hash', HashType()),
324             ('index', StructType('<I')),
325         ]))),
326         ('script', VarStrType()),
327         ('sequence', PossiblyNone(2**32 - 1, StructType('<I'))),
328     ]))),
329     ('tx_outs', ListType(ComposedType([
330         ('value', StructType('<Q')),
331         ('script', VarStrType()),
332     ]))),
333     ('lock_time', StructType('<I')),
334 ])
335
336 block_header_type = ComposedType([
337     ('version', StructType('<I')),
338     ('previous_block', PossiblyNone(0, HashType())),
339     ('merkle_root', HashType()),
340     ('timestamp', StructType('<I')),
341     ('target', FloatingIntegerType()),
342     ('nonce', StructType('<I')),
343 ])
344
345 block_type = ComposedType([
346     ('header', block_header_type),
347     ('txs', ListType(tx_type)),
348 ])
349
350
351 merkle_record_type = ComposedType([
352     ('left', HashType()),
353     ('right', HashType()),
354 ])
355
356 def merkle_hash(tx_list):
357     if not tx_list:
358         return 0
359     hash_list = map(tx_type.hash256, tx_list)
360     while len(hash_list) > 1:
361         hash_list = [merkle_record_type.hash256(dict(left=left, right=left if right is None else right))
362             for left, right in zip(hash_list[::2], hash_list[1::2] + [None])]
363     return hash_list[0]
364
365 def target_to_average_attempts(target):
366     return 2**256//(target + 1)
367
368 human_address_type = ChecksummedType(ComposedType([
369     ('version', StructType("<B")),
370     ('pubkey_hash', ShortHashType()),
371 ]))
372
373 pubkey_type = FixedStrType(65)
374
375 def pubkey_hash_to_address(pubkey_hash, net):
376     return human_address_type.pack_base58(dict(version=net.BITCOIN_ADDRESS_VERSION, pubkey_hash=pubkey_hash))
377
378 def pubkey_to_address(pubkey, net):
379     return pubkey_hash_to_address(pubkey_type.hash160(pubkey), net)
380
381 def address_to_pubkey_hash(address, net):
382     x = human_address_type.unpack_base58(address)
383     if x['version'] != net.BITCOIN_ADDRESS_VERSION:
384         raise ValueError('address not for this net!')
385     return x['pubkey_hash']
386
387 class Mainnet(object):
388     BITCOIN_P2P_PREFIX = 'f9beb4d9'.decode('hex')
389     BITCOIN_P2P_PORT = 8333
390     BITCOIN_ADDRESS_VERSION = 0
391
392 class Testnet(object):
393     BITCOIN_P2P_PREFIX = 'fabfb5da'.decode('hex')
394     BITCOIN_P2P_PORT = 18333
395     BITCOIN_ADDRESS_VERSION = 111