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