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